Merge remote-tracking branch 'origin/master' into extraction-script

This commit is contained in:
elliotcraft79 2021-03-06 01:20:07 +10:30
commit a6a408b97f
123 changed files with 6705 additions and 5843 deletions

207
package-lock.json generated
View file

@ -4384,11 +4384,6 @@
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="
},
"chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
},
"check-types": {
"version": "11.1.2",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz",
@ -4476,19 +4471,6 @@
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
},
"cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"requires": {
"restore-cursor": "^3.1.0"
}
},
"cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@ -6886,16 +6868,6 @@
}
}
},
"external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"requires": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
"extglob": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
@ -7022,14 +6994,6 @@
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
"integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="
},
"figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"file-entry-cache": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
@ -8087,9 +8051,9 @@
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
},
"immer": {
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/immer/-/immer-7.0.9.tgz",
"integrity": "sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A=="
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz",
"integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA=="
},
"import-cwd": {
"version": "2.1.0",
@ -8177,94 +8141,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inquirer": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
"integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
"requires": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.19",
"mute-stream": "0.0.8",
"run-async": "^2.4.0",
"rxjs": "^6.6.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"internal-ip": {
"version": "4.3.0",
@ -11909,11 +11788,6 @@
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
},
"mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
},
"nanoid": {
"version": "3.1.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz",
@ -12395,9 +12269,9 @@
}
},
"open": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
"integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"requires": {
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
@ -12453,11 +12327,6 @@
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"p-each-series": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz",
@ -14064,9 +13933,9 @@
}
},
"react-dev-utils": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.0.tgz",
"integrity": "sha512-uIZTUZXB5tbiM/0auUkLVjWhZGM7DSI304iGunyhA9m985iIDVXd9I4z6MkNa9jeLzeUJbU9A7TUNrcbXAahxw==",
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.3.tgz",
"integrity": "sha512-4lEA5gF4OHrcJLMUV1t+4XbNDiJbsAWCH5Z2uqlTqW6dD7Cf5nEASkeXrCI/Mz83sI2o527oBIFKVMXtRf1Vtg==",
"requires": {
"@babel/code-frame": "7.10.4",
"address": "1.1.2",
@ -14081,13 +13950,13 @@
"global-modules": "2.0.0",
"globby": "11.0.1",
"gzip-size": "5.1.1",
"immer": "7.0.9",
"inquirer": "7.3.3",
"immer": "8.0.1",
"is-root": "2.1.0",
"loader-utils": "2.0.0",
"open": "^7.0.2",
"pkg-up": "3.1.0",
"react-error-overlay": "^6.0.8",
"prompts": "2.4.0",
"react-error-overlay": "^6.0.9",
"recursive-readdir": "2.2.2",
"shell-quote": "1.7.2",
"strip-ansi": "6.0.0",
@ -14160,9 +14029,9 @@
}
},
"react-error-overlay": {
"version": "6.0.8",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz",
"integrity": "sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw=="
"version": "6.0.9",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
"integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew=="
},
"react-is": {
"version": "16.13.1",
@ -14292,6 +14161,11 @@
"utility-types": "^3.10.0"
}
},
"react-use-gesture": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/react-use-gesture/-/react-use-gesture-9.0.4.tgz",
"integrity": "sha512-G0sbQY+HSm2gSVIlD+LE1unpVpG7YZRTr8TI72vo0Nu1lecJtvjbcY3ZLonEZLTtODJgLL6nBllMRXyy0bRSQA=="
},
"react-use-measure": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.0.2.tgz",
@ -14785,15 +14659,6 @@
}
}
},
"restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"requires": {
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
}
},
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
@ -14935,11 +14800,6 @@
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
},
"run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="
},
"run-parallel": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz",
@ -14953,14 +14813,6 @@
"aproba": "^1.1.1"
}
},
"rxjs": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
"integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
"requires": {
"tslib": "^1.9.0"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@ -16412,11 +16264,6 @@
"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
"integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
@ -16473,14 +16320,6 @@
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"tmpl": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",

View file

@ -16,6 +16,7 @@
"react-dom": "^16.13.1",
"react-scripts": "^4.0.0",
"react-three-fiber": "^4.2.20",
"react-use-gesture": "^9.0.4",
"three": "^0.119.1",
"three-plain-animator": "^1.0.2",
"typescript": "^3.7.5",
@ -24,7 +25,7 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!three/.*)/\"",
"eject": "react-scripts eject",
"extract": "node scripts/extract/extract.mjs"
},

View file

@ -5,18 +5,12 @@
<link rel="icon" type="image/png" href="icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<style>
body {
background-color: #000;
}
</style>
</head>
<body>
<noscript
>do you actually believe i could rewrite this in plain html css or
smoetihng</noscript
>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r119/three.min.js"></script>
<div id="root"></div>
</body>
</html>

View file

@ -1,9 +0,0 @@
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View file

@ -1,4 +1,10 @@
import React, { Suspense, useEffect, useMemo } from "react";
import React, {
Suspense,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import MainScene from "./scenes/MainScene";
import "./static/css/page.css";
import { Canvas } from "react-three-fiber";
@ -13,8 +19,8 @@ import TaKScene from "./scenes/TaKScene";
import ChangeDiscScene from "./scenes/ChangeDiscScene";
import EndScene from "./scenes/EndScene";
import IdleMediaScene from "./scenes/IdleMediaScene";
import KeyPressHandler from "./components/KeyPressHandler";
import Preloader from "./components/Preloader";
import InputHandler from "./components/InputHandler";
import mobileAndTabletCheck from "./utils/mobileAndTabletCheck";
const App = () => {
const currentScene = useStore((state) => state.currentScene);
@ -35,23 +41,72 @@ const App = () => {
tak: <TaKScene />,
change_disc: <ChangeDiscScene />,
end: <EndScene />,
null: <></>,
}),
[]
);
const [width, setWidth] = useState((window.screen.height / 1.8) * 1.3);
const [height, setHeight] = useState(window.screen.height / 1.8);
const [isMobile, setIsMobile] = useState(false);
const handleGameResize = useCallback((event) => {
switch (event.key) {
case "k":
setWidth((prevWidth) => prevWidth * 1.1);
setHeight((prevHeight) => prevHeight * 1.1);
break;
case "j":
setWidth((prevWidth) => prevWidth / 1.1);
setHeight((prevHeight) => prevHeight / 1.1);
}
}, []);
const handleScreenResize = useCallback(() => {
const isMobile = mobileAndTabletCheck();
if (!isMobile) {
const h = window.screen.height / 1.8;
setWidth(h * 1.3);
setHeight(h);
setIsMobile(false);
} else {
const h = window.screen.height / 1.05;
setHeight(h);
setWidth(h * 1.3);
setIsMobile(true);
}
}, []);
useEffect(() => {
if (!isMobile) window.addEventListener("keydown", handleGameResize);
window.addEventListener("resize", handleScreenResize);
return () => {
window.removeEventListener("keydown", handleGameResize);
window.removeEventListener("resize", handleScreenResize);
};
}, [handleGameResize, handleScreenResize, isMobile]);
return (
<div id="game-root" className="game">
<span className="canvas">
<Canvas concurrent>
<KeyPressHandler />
<Suspense fallback={null}>
{/*<Preloader />*/}
{dispatchScene[currentScene as keyof typeof dispatchScene]}
</Suspense>
</Canvas>
</span>
<div className="game" style={{ width: width, height: height }}>
<Canvas
concurrent
gl={{ antialias: false }}
pixelRatio={window.devicePixelRatio}
className="main-canvas"
>
<Suspense fallback={null}>
{/*<Preloader />*/}
{dispatchScene[currentScene as keyof typeof dispatchScene]}
<InputHandler isMobile={isMobile} />
</Suspense>
</Canvas>
{["media", "idle_media", "tak", "end"].includes(currentScene) && (
<MediaPlayer />
<div style={{ marginTop: -height }}>
<MediaPlayer />
</div>
)}
</div>
);

View file

@ -0,0 +1,37 @@
import { findNodeFromWord } from "../../helpers/media-helpers";
it("Finds the next node with the same word", () => {
expect(findNodeFromWord("father", "Cou041", "b").node.node_name).toEqual(
"Lda151"
);
expect(findNodeFromWord("father", "Lda151", "b").node.node_name).toEqual(
"Lda155"
);
expect(findNodeFromWord("father", "Lda155", "b").node.node_name).toEqual(
"Lda164"
);
expect(findNodeFromWord("father", "Lda182", "b").node.node_name).toEqual(
"Lda200"
);
expect(findNodeFromWord("father", "Lda229", "b").node.node_name).toEqual(
"Cou041"
);
expect(findNodeFromWord("father", "Cou041", "b").node.node_name).toEqual(
"Lda151"
);
expect(findNodeFromWord("chaos", "Lda154", "b").node.node_name).toEqual(
"Tda056"
);
expect(findNodeFromWord("chaos", "Tda056", "b").node.node_name).toEqual(
"Tda059"
);
expect(findNodeFromWord("prompt", "Lda154", "b").node.node_name).toEqual(
"Tda072"
);
expect(findNodeFromWord("abuse", "Dc1012", "a").node.node_name).toEqual(
"Lda005"
);
expect(findNodeFromWord("abuse", "Lda005", "a").node.node_name).toEqual(
"Dc1012"
);
});

View file

@ -0,0 +1,29 @@
import handleNameSelection from "../../helpers/name-selection-helpers";
it("Handles the logic for japanese characters", () => {
// cant be first character check
expect(handleNameSelection("", "ン")).toEqual(undefined);
// if its not first, then fine
expect(handleNameSelection("キ", "ン")).toEqual("キン");
//「ー」 cannot be added to 「ッ」 and 「ン」or itself
expect(handleNameSelection("キッ", "ー")).toEqual(undefined);
expect(handleNameSelection("キン", "ー")).toEqual(undefined);
expect(handleNameSelection("キー", "ー")).toEqual(undefined);
// characters that can be followed by the lowercase characters
expect(handleNameSelection("キ", "ャ")).toEqual("キャ");
// cant be followed by lowercase character
expect(handleNameSelection("ー", "ャ")).toEqual(undefined);
// for 「ッ」, it can added to any character except itself
expect(handleNameSelection("ャ", "ッ")).toEqual("ャッ");
// cant be added
expect(handleNameSelection("ッ", "ッ")).toEqual(undefined);
// dakuten
expect(handleNameSelection("カ", "゛")).toEqual("ガ");
// cant be appended
expect(handleNameSelection("ガ", "゛")).toEqual(undefined);
// handakuten
expect(handleNameSelection("ハ", "゜")).toEqual("パ");
// cant be appended
expect(handleNameSelection("キ", "゜")).toEqual(undefined);
expect(handleNameSelection("パ", "゜")).toEqual(undefined);
});

View file

@ -0,0 +1,158 @@
import { findNode, unknownNodeTemplate } from "../../helpers/node-helpers";
import site_a from "../../resources/site_a.json";
import gameProgress from "../../resources/initial_progress.json";
/*
visual representation of the data we're working with
[null, "0517", null, null],
[null, null, "0510", "0513"],
["0506", null, null, null],
|
[null, null, null, "0422"], ["0422", "0417", null, null], [null, "0416", "0417", "0420"],
[null, null, null, "0414"], - ["0414", null, null, "0413"], - ["0413", null, null, null],
[null, null, null, null], [null, null, null, "0405"], ["0405", null, null, null],
|
[null, null, null, null] [null, null, null, null], [null, null, null, null],
[null, null, null, null], [null, null, null, null], [null, null, null, null],
[null, null, null, null], [null, null, null, null], [null, null, null, null],
*/
const middleMatrixIdx = 7;
const leftMatrixIdx = 8;
it("Finds which node to go to", () => {
// from unknown to left unknown
expect(
findNode(
{
...unknownNodeTemplate,
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 2, colIdx: 3 },
},
"left",
3,
"a",
gameProgress,
true
)
).toEqual({
node: "unknown",
matrixIndices: { rowIdx: 2, colIdx: 3, matrixIdx: leftMatrixIdx },
didMove: true,
});
// from 0405 down
expect(
findNode(
{
...site_a["04"]["0405"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 2, colIdx: 3 },
},
"down",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "unknown",
matrixIndices: { rowIdx: 2, colIdx: 3, matrixIdx: middleMatrixIdx },
didMove: true,
});
// from 0422 (from left matrix) right
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: 8, rowIdx: 0, colIdx: 3 },
},
"right",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0413",
matrixIndices: { rowIdx: 1, colIdx: 3, matrixIdx: 7 },
didMove: true,
});
// from 0422 left
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"left",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0422",
matrixIndices: { rowIdx: 0, colIdx: 3, matrixIdx: 8 },
didMove: true,
});
// from 0422 up
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"up",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0506",
matrixIndices: { rowIdx: 2, colIdx: 0, matrixIdx: 7 },
didMove: true,
});
// from 0422 right
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"right",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0417",
matrixIndices: { rowIdx: 0, colIdx: 1, matrixIdx: 7 },
didMove: false,
});
// from 0414 up
expect(
findNode(
{
...site_a["04"]["0414"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 1, colIdx: 0 },
},
"up",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0422",
matrixIndices: { rowIdx: 0, colIdx: 0, matrixIdx: 7 },
didMove: false,
});
});

View file

@ -0,0 +1,29 @@
import { getNodeById, isNodeVisible } from "../../helpers/node-helpers";
import site_a from "../../resources/site_a.json";
import gameProgress from "../../resources/initial_progress.json";
it("Finds the node by it's id", () => {
expect(getNodeById("0422", "a").node_name).toEqual("Tda028");
expect(getNodeById("0000", "a").node_name).toEqual("Env001");
expect(getNodeById("0616", "a").node_name).toEqual("Cou015");
expect(getNodeById("0100", "b").node_name).toEqual("Sskn04#");
expect(getNodeById("0101", "b").node_name).toEqual("Dc1025");
});
const oneViewCount = { ...gameProgress, final_video_viewcount: 1 };
const twoViewCount = { ...gameProgress, final_video_viewcount: 2 };
const threeViewCount = { ...gameProgress, final_video_viewcount: 3 };
const fourViewCount = { ...gameProgress, final_video_viewcount: 4 };
it("Checks if the node is visible", () => {
expect(isNodeVisible(site_a["04"]["0422"], gameProgress)).toEqual(true);
expect(isNodeVisible(site_a["04"]["0413"], gameProgress)).toEqual(true);
expect(isNodeVisible(site_a["04"]["0406"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["04"]["0410"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["04"]["0406"], oneViewCount)).toEqual(true);
expect(isNodeVisible(site_a["06"]["0612"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["06"]["0612"], oneViewCount)).toEqual(true);
expect(isNodeVisible(site_a["06"]["0612"], twoViewCount)).toEqual(true);
expect(isNodeVisible(site_a["08"]["0801"], fourViewCount)).toEqual(true);
expect(isNodeVisible(site_a["08"]["0801"], threeViewCount)).toEqual(false);
});

View file

@ -0,0 +1,84 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getBootSceneContext } from "../../store";
import handleBootSceneInput from "../../core/input-handlers/handleBootSceneInput";
import {
enterLoadData,
enterUserAuthorization,
exitUserAuthorization,
startNewGame,
} from "../../core/eventTemplates";
import { BootSubscene, MainMenuComponent } from "../../types/types";
it("Checks whether or not the boot scene input handler reacts appropriately for each input", () => {
{
// change main menu active component
const spy = jest.spyOn(eventTemplates, "changeMainMenuComponent");
const testContext = getBootSceneContext();
handleBootSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
// select main menu component
{
const testContext = {
...getBootSceneContext(),
activeMainMenuComponent: "authorize_user" as MainMenuComponent,
};
expect(handleBootSceneInput(testContext, "CIRCLE")).toEqual(
enterUserAuthorization
);
}
{
const testContext = {
...getBootSceneContext(),
activeMainMenuComponent: "load_data" as MainMenuComponent,
};
expect(handleBootSceneInput(testContext, "CIRCLE")).toEqual(enterLoadData);
}
{
// change letter in authorize user scene
const spy = jest.spyOn(eventTemplates, "updateAuthorizeUserLetterIdx");
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
};
handleBootSceneInput(testContext, "RIGHT");
expect(spy).toHaveBeenCalled();
}
{
// start new game
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "チ",
};
expect(handleBootSceneInput(testContext, "START")).toEqual(startNewGame);
}
{
// delete last char if player name is not empty
const spy = jest.spyOn(eventTemplates, "removePlayerNameLastChar");
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "チ",
};
handleBootSceneInput(testContext, "X");
expect(spy).toHaveBeenCalled();
}
{
// go back to main menu if player name is empty
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "",
};
expect(handleBootSceneInput(testContext, "X")).toEqual(
exitUserAuthorization
);
}
});

View file

@ -0,0 +1,38 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getEndSceneContext } from "../../store";
import handleEndSceneInput from "../../core/input-handlers/handleEndSceneInput";
import { EndComponent } from "../../types/types";
it("Checks whether or not the end scene input handler reacts appropriately for each input", () => {
{
// changing end active component
const spy = jest.spyOn(eventTemplates, "changeEndComponent");
const testContext = { ...getEndSceneContext(), selectionVisible: true };
handleEndSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
// selecting end component
{
const spy = jest.spyOn(eventTemplates, "endGame");
const testContext = { ...getEndSceneContext(), selectionVisible: true };
handleEndSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
const spy = jest.spyOn(eventTemplates, "changeSite");
const testContext = {
...getEndSceneContext(),
selectionVisible: true,
activeEndComponent: "continue" as EndComponent,
};
handleEndSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
});

View file

@ -0,0 +1,131 @@
import { getMainSceneContext } from "../../store";
import handleMainSceneInput from "../../core/input-handlers/handleMainSceneInput";
import * as eventTemplates from "../../core/eventTemplates";
import site_a from "../../resources/site_a.json";
import {
enterLevelSelection,
pauseGame,
ripNode,
showAbout,
throwNode,
} from "../../core/eventTemplates";
import { nodeToScene } from "../../helpers/node-helpers";
import { PauseComponent } from "../../types/types";
const expectOr = (...tests: (() => void)[]) => {
try {
tests.shift()!();
} catch (e) {
if (tests.length) expectOr(...tests);
else throw e;
}
};
it("Checks whether or not the main scene input handler reacts appropriately for each input", () => {
{
const spy = jest.spyOn(eventTemplates, "changeNode");
const testContext = getMainSceneContext();
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// move vertically when utmost up node is currently selected
const spy = jest.spyOn(eventTemplates, "siteMoveVertical");
const testContext = {
...getMainSceneContext(),
activeNode: {
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
},
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// move horizontally when utmost left node is currently selected
const spy = jest.spyOn(eventTemplates, "siteMoveHorizontal");
const testContext = getMainSceneContext();
handleMainSceneInput(testContext, "LEFT");
expect(spy).toHaveBeenCalled();
}
{
// play throw node/rip node animation and set the scene when the player selects a node
const testContext = getMainSceneContext();
const output = handleMainSceneInput(testContext, "CIRCLE");
expectOr(
() =>
expect(output).toEqual(
ripNode({ currentScene: nodeToScene(testContext.activeNode)! })
),
() =>
expect(output).toEqual(
throwNode({ currentScene: nodeToScene(testContext.activeNode)! })
)
);
}
{
// entering level selection
const testContext = getMainSceneContext();
expect(handleMainSceneInput(testContext, "L2")).toEqual(
enterLevelSelection({ selectedLevel: testContext.level })
);
}
{
// entering pause
const testContext = getMainSceneContext();
expect(handleMainSceneInput(testContext, "TRIANGLE")).toEqual(
pauseGame({ siteRot: [Math.PI / 2, testContext.siteRotY, 0] })
);
}
{
// changing level inside level selection
const spy = jest.spyOn(eventTemplates, "changeSelectedLevel");
const testContext = {
...getMainSceneContext(),
subscene: "level_selection",
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// selecting new level when currently below it
const spy = jest.spyOn(eventTemplates, "selectLevel");
const testContext = {
...getMainSceneContext(),
selectedLevel: 10,
subscene: "level_selection",
};
handleMainSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
// changing pause active component
const spy = jest.spyOn(eventTemplates, "changePauseComponent");
const testContext = {
...getMainSceneContext(),
subscene: "pause",
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// selecting pause component
const testContext = {
...getMainSceneContext(),
subscene: "pause",
activePauseComponent: "about" as PauseComponent,
};
expect(handleMainSceneInput(testContext, "CIRCLE")).toEqual(showAbout);
}
});

View file

@ -0,0 +1,68 @@
import * as eventTemplates from "../../core/eventTemplates";
import { exitMedia } from "../../core/eventTemplates";
import { getMediaSceneContext } from "../../store";
import handleMediaSceneInput from "../../core/input-handlers/handleMediaSceneInput";
import { LeftMediaComponent, MediaSide } from "../../types/types";
it("Checks whether or not the media scene input handler reacts appropriately for each input", () => {
{
// changing left side media active component
const spy = jest.spyOn(eventTemplates, "changeLeftMediaComponent");
const testContext = getMediaSceneContext();
handleMediaSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// changing media side from left to right
const spy = jest.spyOn(eventTemplates, "changeMediaSide");
const testContext = getMediaSceneContext();
handleMediaSceneInput(testContext, "RIGHT");
expect(spy).toHaveBeenCalled();
}
{
// exit media
const testContext = {
...getMediaSceneContext(),
activeMediaComponent: "exit" as LeftMediaComponent,
};
expect(handleMediaSceneInput(testContext, "CIRCLE")).toEqual(exitMedia);
}
{
// play media
const spy = jest.spyOn(eventTemplates, "playMedia");
const testContext = getMediaSceneContext();
handleMediaSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
// change right side media component
const spy = jest.spyOn(eventTemplates, "changeRightMediaComponent");
const testContext = {
...getMediaSceneContext(),
currentMediaSide: "right" as MediaSide,
};
handleMediaSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// change from right side to left
const spy = jest.spyOn(eventTemplates, "changeMediaSide");
const testContext = {
...getMediaSceneContext(),
currentMediaSide: "right" as MediaSide,
};
handleMediaSceneInput(testContext, "LEFT");
expect(spy).toHaveBeenCalled();
}
});

View file

@ -0,0 +1,34 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getSsknSceneContext } from "../../store";
import handleSsknSceneInput from "../../core/input-handlers/handleSsknSceneInput";
import { exitSskn } from "../../core/eventTemplates";
import { SsknComponent } from "../../types/types";
it("Checks whether or not the sskn scene input handler reacts appropriately for each input", () => {
{
// changing sskn active component
const spy = jest.spyOn(eventTemplates, "changeSsknComponent");
const testContext = getSsknSceneContext();
handleSsknSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// select ok
const spy = jest.spyOn(eventTemplates, "upgradeSskn");
const testContext = getSsknSceneContext();
handleSsknSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
// select cancel
const testContext = {
...getSsknSceneContext(),
activeSsknComponent: "cancel" as SsknComponent,
};
expect(handleSsknSceneInput(testContext, "CIRCLE")).toEqual(exitSskn);
}
});

View file

@ -0,0 +1,9 @@
import { getCurrentUserState } from "../store";
it("Checks if setting state on localStorage works", () => {
const spy = jest.spyOn(Storage.prototype, "setItem");
const saveState = JSON.stringify(getCurrentUserState());
localStorage.setItem("lainSaveState", saveState);
expect(spy).toHaveBeenCalledTimes(1);
expect(localStorage.getItem("lainSaveState")).toEqual(saveState);
});

View file

@ -1,6 +1,6 @@
import React, { useState } from "react";
import accelaBootSpriteSheet from "../../static/sprite/login_intro_accela_spritesheet.png";
import makeMeSad from "../../static/sprite/make_me_sad.png";
import accelaBootSpriteSheet from "../../static/sprites/boot/login_intro_accela_spritesheet.png";
import makeMeSad from "../../static/sprites/boot/make_me_sad.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";

View file

@ -1,23 +1,24 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import bootLof from "../../static/sprite/boot_lof.png";
import bootBottomBarLeft from "../../static/sprite/boot_bottom_bar_left.png";
import bootBottomBarRight from "../../static/sprite/boot_bottom_bar_right.png";
import bootPurpleSquare from "../../static/sprite/boot_purple_square.png";
import bootGraySquare from "../../static/sprite/boot_gray_square.png";
import bootDangoText from "../../static/sprite/dango_text.png";
import bootMisoShio from "../../static/sprite/miso_shio.png";
import bootArrows from "../../static/sprite/boot_arrows.png";
import bootStatusTexts from "../../static/sprite/boot_status_texts.png";
import bootBackgroundText from "../../static/sprite/boot_background_text.png";
import bootBackgroundDistortedTex from "../../static/sprite/distorted_text.png";
import React, {useEffect, useMemo, useRef, useState} from "react";
import bootLof from "../../static/sprites/boot/boot_lof.png";
import bootBottomBarLeft from "../../static/sprites/boot/boot_bottom_bar_left.png";
import bootBottomBarRight from "../../static/sprites/boot/boot_bottom_bar_right.png";
import bootPurpleSquare from "../../static/sprites/boot/boot_purple_square.png";
import bootGraySquare from "../../static/sprites/boot/boot_gray_square.png";
import bootDangoText from "../../static/sprites/boot/dango_text.png";
import bootMisoShio from "../../static/sprites/boot/miso_shio.png";
import bootArrows from "../../static/sprites/boot/boot_arrows.png";
import bootStatusTexts from "../../static/sprites/boot/boot_status_texts.png";
import bootBackgroundText from "../../static/sprites/boot/boot_background_text.png";
import bootBackgroundDistortedTex from "../../static/sprites/boot/distorted_text.png";
import { useFrame, useLoader } from "react-three-fiber";
import { a, useSpring } from "@react-spring/three";
import {useFrame, useLoader} from "react-three-fiber";
import {a, useSpring} from "@react-spring/three";
import * as THREE from "three";
import sleep from "../../utils/sleep";
type BootAnimationProps = {
visible: boolean;
mainMenuVisible: boolean;
activeSubScene: string;
};
@ -134,20 +135,22 @@ const BootAnimation = (props: BootAnimationProps) => {
await sleep(100);
currentBootStatusTextTex.offset.y = 0.79;
await sleep(1700);
currentBootStatusTextTex.offset.x = 0.5;
currentBootStatusTextTex.offset.y = 0.005;
setBootOpacity(0);
setGraySquarePosY(0);
setLofPosX(1.3);
setLofPosY(1);
setBackgroundFloatingTextShown(true);
})();
}
}, [bootBackgroundTextTex, currentBootStatusTextTex.offset, props.visible]);
useEffect(() => {
if (props.mainMenuVisible) {
currentBootStatusTextTex.offset.x = 0.5;
currentBootStatusTextTex.offset.y = 0.005;
setBootOpacity(0);
setGraySquarePosY(0);
setLofPosX(1.3);
setLofPosY(1);
setBackgroundFloatingTextShown(true);
}
}, [currentBootStatusTextTex.offset, props.mainMenuVisible]);
const [bootOpacity, setBootOpacity] = useState(1);
const [graySquarePosY, setGraySquarePosY] = useState(-0.8);
const [lofPosX, setLofPosX] = useState(0);
@ -196,7 +199,7 @@ const BootAnimation = (props: BootAnimationProps) => {
opacity={animationState.graySquareOpacity}
/>
</a.sprite>
{props.activeSubScene !== "authorize_user" ? (
{props.activeSubScene !== "authorize_user" && (
<>
{/*we have two of each to create looping effect*/}
<a.sprite
@ -315,8 +318,6 @@ const BootAnimation = (props: BootAnimationProps) => {
/>
</sprite>
</>
) : (
<></>
)}
</group>
);

View file

@ -1,16 +1,14 @@
import React, { useEffect, useMemo, useRef } from "react";
import authorizeHeaderUnderline from "../../static/sprite/authorize_header_underline.png";
import authorizeGlass from "../../static/sprite/authorize_glass.png";
import authorizeGlassUnderline from "../../static/sprite/authorize_glass_underline.png";
import authorizeOrangeSquare from "../../static/sprite/authorize_orange_square.png";
import authorizeStartToFinish from "../../static/sprite/authorize_start_to_finish.png";
import authorizeInactiveLetters from "../../static/sprite/authorize_inactive_letters.png";
import authorizeActiveLetters from "../../static/sprite/authorize_active_letters.png";
import authorizeHeaderUnderline from "../../static/sprites/boot/authorize_header_underline.png";
import authorizeGlass from "../../static/sprites/boot/authorize_glass.png";
import authorizeGlassUnderline from "../../static/sprites/boot/authorize_glass_underline.png";
import authorizeOrangeSquare from "../../static/sprites/boot/authorize_orange_square.png";
import authorizeStartToFinish from "../../static/sprites/boot/authorize_start_to_finish.png";
import authorizeInactiveLetters from "../../static/sprites/boot/authorize_inactive_letters.png";
import authorizeActiveLetters from "../../static/sprites/boot/authorize_active_letters.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { OrbitControls } from "@react-three/drei";
import { useStore } from "../../store";
import usePrevious from "../../hooks/usePrevious";
import StaticJpCharacter from "../TextRenderer/StaticJpCharacter";
type BootAuthorizeUserProps = {
@ -44,78 +42,32 @@ const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
authorizeActiveLetters
);
const letterIdx = useStore((state) => state.authorizeUserLetterIdx);
const subscene = useStore((state) => state.bootSubscene);
const prevData = usePrevious({ letterIdx, subscene });
const authorizeUserMatrixIndices = useStore(
(state) => state.authorizeUserMatrixIndices
);
const bgLettersRef = useRef<THREE.Object3D>();
const activeLetterRef = useRef<THREE.Mesh>();
const activeLetterMap = useMemo(() => {
activeLettersTex.wrapT = activeLettersTex.wrapS = THREE.RepeatWrapping;
activeLettersTex.repeat.set(0.06, 0.2);
activeLettersTex.offset.x = 0;
activeLettersTex.offset.y = -0.2;
activeLettersTex.offset.x = 0.0775 * authorizeUserMatrixIndices.colIdx;
activeLettersTex.offset.y = -0.2 - 0.2 * authorizeUserMatrixIndices.rowIdx;
return activeLettersTex;
}, [activeLettersTex]);
useEffect(() => {
if (
prevData?.subscene === "main_menu" &&
subscene === "authorize_user" &&
activeLetterRef
) {
activeLetterMap.offset.x = 0;
activeLetterMap.offset.y = -0.2;
}
}, [subscene, prevData?.subscene, activeLetterMap.offset]);
}, [
activeLettersTex,
authorizeUserMatrixIndices.colIdx,
authorizeUserMatrixIndices.rowIdx,
]);
useEffect(() => {
if (bgLettersRef.current) {
//down
if (prevData!.letterIdx + 13 === letterIdx) {
bgLettersRef.current.position.y += 0.25;
activeLetterMap.offset.y -= 0.2;
// down skip
} else if (letterIdx === prevData!.letterIdx + 26) {
bgLettersRef.current.position.y += 0.5;
activeLetterMap.offset.y -= 0.4;
} else if (letterIdx === prevData!.letterIdx + 52) {
bgLettersRef.current.position.y += 1;
activeLetterMap.offset.y -= 0.8;
}
// up
else if (letterIdx === prevData!.letterIdx - 13) {
bgLettersRef.current.position.y -= 0.25;
activeLetterMap.offset.y += 0.2;
// up skip
} else if (letterIdx === prevData!.letterIdx - 26) {
bgLettersRef.current.position.y -= 0.5;
activeLetterMap.offset.y += 0.4;
} else if (letterIdx === prevData!.letterIdx - 52) {
bgLettersRef.current.position.y -= 1;
activeLetterMap.offset.y += 0.8;
}
// left
else if (letterIdx === prevData!.letterIdx - 1) {
bgLettersRef.current.position.x += 0.3;
activeLetterMap.offset.x -= 0.0775;
}
// left skip
else if (letterIdx === prevData!.letterIdx - 2) {
bgLettersRef.current.position.x += 0.6;
activeLetterMap.offset.x -= 0.155;
}
// right
else if (letterIdx === prevData!.letterIdx + 1) {
bgLettersRef.current.position.x -= 0.3;
activeLetterMap.offset.x += 0.0775;
} else if (letterIdx === prevData!.letterIdx + 2) {
bgLettersRef.current.position.x -= 0.6;
activeLetterMap.offset.x += 0.155;
}
bgLettersRef.current.position.y =
-0.7 + 0.25 * authorizeUserMatrixIndices.rowIdx;
bgLettersRef.current.position.x =
3.35 - 0.3 * authorizeUserMatrixIndices.colIdx;
}
}, [activeLetterMap.offset, letterIdx, prevData]);
}, [authorizeUserMatrixIndices.colIdx, authorizeUserMatrixIndices.rowIdx]);
const playerName = useStore((state) => state.playerName.split(""));
@ -160,8 +112,9 @@ const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
</sprite>
<sprite
scale={[0.2, 0.2, 0]}
position={[-0.2, -0.3, 0]}
position={[-0.19, -0.3, 0]}
renderOrder={3}
visible={!(playerName.length === 8)}
>
<spriteMaterial
map={authorizeOrangeSquareTex}
@ -170,8 +123,15 @@ const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
depthTest={false}
/>
</sprite>
<group position={[playerName.length * -0.25 - 0.2, -0.27, 0]}>
<group
position={[
(playerName.length === 8 ? 0.2 : 0) +
playerName.length * -0.2 -
0.2,
-0.29,
0,
]}
>
{playerName.map((char, idx) => (
<StaticJpCharacter char={char} charIdx={idx} key={idx} />
))}
@ -189,11 +149,10 @@ const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
/>
</sprite>
<OrbitControls />
<group position={[-1.15, 0.4, 0.3]} rotation={[-0.8, 0, -0.3]}>
<mesh
scale={[4, 1.28, 0]}
position={[3.35, -0.7, 0]}
position={[1.25, -0.45, 0]}
ref={bgLettersRef}
>
<planeBufferGeometry attach="geometry" />
@ -201,7 +160,6 @@ const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
map={authorizeInactiveLettersTex}
attach="material"
transparent={true}
side={THREE.DoubleSide}
/>
</mesh>
<mesh

View file

@ -1,5 +1,5 @@
import React from "react";
import loadDataUnderline from "../../static/sprite/load_data_header_underline.png";
import loadDataUnderline from "../../static/sprites/boot/load_data_header_underline.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import Prompt from "../Prompt";

View file

@ -1,13 +1,13 @@
import React, { useMemo } from "react";
import { a, useSpring } from "@react-spring/three";
import authorizeActive from "../../static/sprite/authorize_user_active.png";
import authorizeInactive from "../../static/sprite/authorize_user_inactive.png";
import loadDataActive from "../../static/sprite/load_data_active.png";
import loadDataInactive from "../../static/sprite/load_data_inactive.png";
import authorizeActive from "../../static/sprites/boot/authorize_user_active.png";
import authorizeInactive from "../../static/sprites/boot/authorize_user_inactive.png";
import loadDataActive from "../../static/sprites/boot/load_data_active.png";
import loadDataInactive from "../../static/sprites/boot/load_data_inactive.png";
import authorizeUserHeader from "../../static/sprites/boot/authorize_user_scene_header.png";
import loadDataHeader from "../../static/sprites/boot/load_data_header.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import authorizeUserHeader from "../../static/sprite/authorize_user_scene_header.png";
import loadDataHeader from "../../static/sprite/load_data_header.png";
import { useStore } from "../../store";
type BootMainMenuProps = {

View file

@ -1,7 +1,7 @@
import React from "react";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import mainCylinder from "../../static/sprite/end_cylinder_1.png";
import mainCylinder from "../../static/sprites/end/end_cylinder_1.png";
const EndCylinder = () => {
const mainCylinderTex = useLoader(THREE.TextureLoader, mainCylinder);

View file

@ -1,16 +1,20 @@
import React, { useRef, useState } from "react";
import middleSpritesheet from "../../static/sprite/end_middle_spritesheet.png";
import middleLain from "../../static/sprite/end_middle_lain.png";
import circleSpritesheet from "../../static/sprite/end_circle_spritesheet.png";
import endText from "../../static/sprite/end_end_text.png";
import continueText from "../../static/sprite/end_continue_text.png";
import React, { memo, useRef, useState } from "react";
import middleSpritesheet from "../../static/sprites/end/end_middle_spritesheet.png";
import middleLain from "../../static/sprites/end/end_middle_lain.png";
import circleSpritesheet from "../../static/sprites/end/end_circle_spritesheet.png";
import endText from "../../static/sprites/end/end_end_text.png";
import continueText from "../../static/sprites/end/end_continue_text.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../store";
const EndSelectionScreen = () => {
type EndSelectionScreenProps = {
visible: boolean;
};
const EndSelectionScreen = memo((props: EndSelectionScreenProps) => {
const middleSpritesheetTex: any = useLoader(
THREE.TextureLoader,
middleSpritesheet
@ -63,7 +67,7 @@ const EndSelectionScreen = () => {
const lainOpacity = lainOpacityToggle.to([0, 1], [0, 0.5]);
return (
<>
<group visible={props.visible}>
<sprite position={[-3.5, 0, -3]} scale={[10, 0.8, 0]}>
<spriteMaterial attach="material" map={middleSpritesheetTex} />
</sprite>
@ -93,8 +97,8 @@ const EndSelectionScreen = () => {
opacity={lainOpacity}
/>
</sprite>
</>
</group>
);
};
});
export default EndSelectionScreen;

View file

@ -1,7 +1,7 @@
import React, { useRef } from "react";
import * as THREE from "three";
import { useFrame, useLoader } from "react-three-fiber";
import secondCylinder from "../../static/sprite/end_cylinder_2.png";
import secondCylinder from "../../static/sprites/end/end_cylinder_2.png";
type EndSphereProps = {
position: number[];

View file

@ -1,10 +1,10 @@
import React, { useEffect, useMemo, useRef } from "react";
import gateText from "../../static/sprite/gate_pass.png";
import gateTextUnderline from "../../static/sprite/gate_pass_underline.png";
import gateTextAccessPass from "../../static/sprite/you_got_an_access_pass.png";
import changeSiteEnable from "../../static/sprite/change_site_enable.png";
import gateLeftThing from "../../static/sprite/left_gate_thing.png";
import gateRightThing from "../../static/sprite/right_gate_thing.png";
import gateText from "../../static/sprites/gate/gate_pass.png";
import gateTextUnderline from "../../static/sprites/gate/gate_pass_underline.png";
import gateTextAccessPass from "../../static/sprites/gate/you_got_an_access_pass.png";
import changeSiteEnable from "../../static/sprites/gate/change_site_enable.png";
import gateLeftThing from "../../static/sprites/gate/left_gate_thing.png";
import gateRightThing from "../../static/sprites/gate/right_gate_thing.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
@ -14,7 +14,7 @@ type GateMiddleProps = {
};
const GateHUD = (props: GateMiddleProps) => {
const wordFont = useLoader(THREE.FontLoader, "/3d_fonts/MediaWord.blob");
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,

View file

@ -1,9 +1,8 @@
import React, { useEffect, useState } from "react";
import BlueZero from "./GateMiddleObject/BlueZero";
import BlueOne from "./GateMiddleObject/BlueOne";
import { a, useSpring, useSprings } from "@react-spring/three";
import blue_digit_positions from "../../resources/blue_digit_positions.json";
import Mirror from "./GateMiddleObject/Mirror";
import BlueDigit from "./GateMiddleObject/BlueDigit";
type GateMiddleObjectProps = {
intro: boolean;
@ -16,14 +15,12 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
const [springs, set] = useSprings(44, (intIdx) => {
const idx = intIdx.toString();
return {
type: blue_digit_positions[idx as keyof typeof blue_digit_positions].type,
posX:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_x,
posY:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_y,
visibility: false,
config: { duration: 150 },
};
});
@ -40,7 +37,6 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
.final_y,
delay:
blue_digit_positions[idx as keyof typeof blue_digit_positions].delay,
visibility: true,
};
});
@ -62,23 +58,18 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
position-z={middleObjectGroupState.posZ}
visible={props.intro}
>
{springs.map((item, idx) =>
item.type.get() === 1 ? (
<BlueOne
posX={item.posX}
posY={item.posY}
key={idx}
visibility={item.visibility}
/>
) : (
<BlueZero
posX={item.posX}
posY={item.posY}
key={idx}
visibility={item.visibility}
/>
)
)}
{springs.map((item, idx) => (
<BlueDigit
type={
blue_digit_positions[
idx.toString() as keyof typeof blue_digit_positions
].type
}
posX={item.posX}
posY={item.posY}
key={idx}
/>
))}
</a.group>
<Mirror
visible={props.gateLvl === 1 ? !props.intro : props.gateLvl > 0}

View file

@ -1,29 +1,41 @@
import React, { useEffect, useMemo, useRef } from "react";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import gateBlueBinarySingularZero from "../../../static/sprite/blue_binary_singular_zero.png";
import gateBlueBinarySingularOne from "../../../static/sprites/gate/blue_binary_singular_one.png";
import { a, SpringValue } from "@react-spring/three";
import gateBlueBinarySingularZero from "../../../static/sprites/gate/blue_binary_singular_zero.png";
type BlueZeroProps = {
type BlueDigitProps = {
type: number;
posX: SpringValue<number>;
posY: SpringValue<number>;
visibility: SpringValue<boolean>;
};
const BlueZero = (props: BlueZeroProps) => {
const BlueDigit = (props: BlueDigitProps) => {
const gateBlueBinarySingularOneTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularOne
);
const gateBlueBinarySingularZeroTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularZero
);
const objRef = useRef<THREE.Mesh>();
const matRef = useRef<THREE.ShaderMaterial>();
const uniforms = useMemo(
() => ({
zeroTex: { type: "t", value: gateBlueBinarySingularZeroTex },
tex: {
type: "t",
value:
props.type === 1
? gateBlueBinarySingularOneTex
: gateBlueBinarySingularZeroTex,
},
brightnessMultiplier: { value: 1.5 },
}),
[gateBlueBinarySingularZeroTex]
[gateBlueBinarySingularOneTex, gateBlueBinarySingularZeroTex, props.type]
);
const vertexShader = `
@ -35,14 +47,13 @@ const BlueZero = (props: BlueZeroProps) => {
}
`;
const fragmentShaderZero = `
uniform sampler2D zeroTex;
const fragmentShader = `
uniform sampler2D tex;
uniform float brightnessMultiplier;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(zeroTex, vUv) * brightnessMultiplier;
gl_FragColor = texture2D(tex, vUv) * brightnessMultiplier;
}
`;
@ -50,21 +61,26 @@ const BlueZero = (props: BlueZeroProps) => {
setTimeout(() => {
if (matRef.current) {
matRef.current.uniforms.brightnessMultiplier.value = 3.5;
matRef.current.uniformsNeedUpdate = true;
}
}, 1400);
setTimeout(() => {
if (objRef.current) objRef.current.visible = true;
}, 150);
}, []);
return (
<a.mesh
scale={[0.08, 0.1, 0]}
scale={[props.type === 1 ? 0.04 : 0.08, 0.1, 0]}
position-x={props.posX}
position-y={props.posY}
renderOrder={5}
visible={props.visibility}
visible={false}
ref={objRef}
>
<planeBufferGeometry attach="geometry"></planeBufferGeometry>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
fragmentShader={fragmentShaderZero}
fragmentShader={fragmentShader}
vertexShader={vertexShader}
uniforms={uniforms}
attach="material"
@ -76,4 +92,4 @@ const BlueZero = (props: BlueZeroProps) => {
);
};
export default BlueZero;
export default BlueDigit;

View file

@ -1,77 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import gateBlueBinarySingularOne from "../../../static/sprite/blue_binary_singular_one.png";
import { a, SpringValue } from "@react-spring/three";
type BlueOneProps = {
posX: SpringValue<number>;
posY: SpringValue<number>;
visibility: SpringValue<boolean>;
};
const BlueOne = (props: BlueOneProps) => {
const gateBlueBinarySingularOneTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularOne
);
const matRef = useRef<THREE.ShaderMaterial>();
const uniforms = useMemo(
() => ({
oneTex: { type: "t", value: gateBlueBinarySingularOneTex },
brightnessMultiplier: { value: 1.5 },
}),
[gateBlueBinarySingularOneTex]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShaderOne = `
uniform sampler2D oneTex;
uniform float brightnessMultiplier;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(oneTex, vUv) * brightnessMultiplier;
}
`;
useEffect(() => {
setTimeout(() => {
if (matRef.current)
matRef.current.uniforms.brightnessMultiplier.value = 3.5;
}, 1400);
}, []);
return (
<a.mesh
scale={[0.04, 0.1, 0]}
position-x={props.posX}
position-y={props.posY}
renderOrder={5}
visible={props.visibility}
>
<planeBufferGeometry attach="geometry"></planeBufferGeometry>
<shaderMaterial
fragmentShader={fragmentShaderOne}
vertexShader={vertexShader}
uniforms={uniforms}
attach="material"
transparent={true}
depthTest={false}
ref={matRef}
/>
</a.mesh>
);
};
export default BlueOne;

View file

@ -1,7 +1,7 @@
import React, { useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import mirrorTexture from "../../../static/sprite/gate_object_texture.png";
import mirrorTexture from "../../../static/sprites/gate/gate_object_texture.png";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
type GLTFResult = GLTF & {

View file

@ -1,5 +1,5 @@
import React, { useMemo, useRef } from "react";
import blueBinary from "../../static/sprite/blue_binary.png";
import blueBinary from "../../static/sprites/gate/blue_binary.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
@ -85,7 +85,7 @@ const GateSide = () => {
scale={[3, 1.5, 0]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry"></planeBufferGeometry>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
attach="material"
uniforms={uniforms}
@ -101,7 +101,7 @@ const GateSide = () => {
scale={[-3, 1.5, 0]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry"></planeBufferGeometry>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
attach="material"
uniforms={uniforms}

View file

@ -0,0 +1,84 @@
import { useFrame } from "react-three-fiber";
import { playAudio, useStore } from "../store";
import * as audio from "../static/audio/sfx";
import {
playIdleAudio,
playIdleVideo,
playLainIdleAnim,
} from "../core/eventTemplates";
import {
getRandomIdleLainAnim,
getRandomIdleMedia,
} from "../helpers/idle-helpers";
import handleEvent from "../core/handleEvent";
import { useEffect } from "react";
type IdleManagerProps = {
lainIdleTimerRef: any;
idleSceneTimerRef: any;
};
const IdleManager = (props: IdleManagerProps) => {
const mainSubscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
useEffect(() => {
if (scene !== "main") {
props.idleSceneTimerRef.current = -1;
}
}, [props.idleSceneTimerRef, scene]);
useFrame(() => {
const now = Date.now();
if (
props.lainIdleTimerRef.current !== -1 &&
props.idleSceneTimerRef.current !== -1 &&
mainSubscene !== "pause" &&
mainSubscene !== "level_selection" &&
scene === "main"
) {
if (now > props.lainIdleTimerRef.current + 10000) {
// after one idle animation plays, the second comes sooner than it would after a regular keypress
props.lainIdleTimerRef.current = now - 2500;
const [idleLainAnim, duration] = getRandomIdleLainAnim();
const event = playLainIdleAnim({
lainMoveState: idleLainAnim,
duration: duration,
});
if (event) handleEvent(event);
}
if (now > props.idleSceneTimerRef.current + 30000) {
// put it on lock until the next action, since while the idle media plays, the
// Date.now() value keeps increasing, which can result in another idle media playing right after one finishes
// one way to work around this would be to modify the value depending on the last played idle media's duration
// but i'm way too lazy for that
props.idleSceneTimerRef.current = -1;
playAudio(audio.sound32);
const data = getRandomIdleMedia();
const { type, nodeName, images, media } = data;
let event;
if (type === "audio" && images && nodeName) {
event = playIdleAudio({
idleNodeName: nodeName,
idleImages: images,
idleMedia: media,
});
} else if (type === "video") {
event = playIdleVideo({ idleMedia: media });
}
if (event) handleEvent(event);
}
}
});
return null;
};
export default IdleManager;

View file

@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useState } from "react";
import { useStore } from "../store";
import { a, useSpring } from "@react-spring/three";
import dummy from "../static/sprite/dummy.png";
import dummy from "../static/sprites/dummy.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
@ -31,13 +31,7 @@ const Images = () => {
const textureLoader = useMemo(() => new THREE.TextureLoader(), []);
useEffect(() => {
let images;
if (currentScene === "media" || currentScene === "tak") {
images = nodeImages;
} else if (currentScene === "idle_media") {
images = idleNodeImages;
}
const images = currentScene === "idle_media" ? idleNodeImages : nodeImages;
if (images) {
// checking the length of the img arr doesn't work in some cases
// since the amount of images varies from 1 to 3.
@ -63,24 +57,27 @@ const Images = () => {
}, [currentScene, activeSite, idleNodeImages, nodeImages]);
useEffect(() => {
const loadNewImage = (imgIdx: number) => {
setImageScaleY(0);
let timer: ReturnType<typeof setTimeout>;
setTimeout(() => {
textureLoader.load(sceneImages[imgIdx].default, setActiveImage);
if (mediaPercentageElapsed === 0 && sceneImages[0]) {
textureLoader.load(sceneImages[0].default, setActiveImage);
} else if (mediaPercentageElapsed === 35 && sceneImages[1]) {
setImageScaleY(0);
timer = setTimeout(() => {
textureLoader.load(sceneImages[1].default, setActiveImage);
setImageScaleY(3.75);
}, 300);
};
} else if (mediaPercentageElapsed === 70 && sceneImages[2]) {
setImageScaleY(0);
timer = setTimeout(() => {
textureLoader.load(sceneImages[1].default, setActiveImage);
setImageScaleY(3.75);
}, 300);
}
(async () => {
if (mediaPercentageElapsed === 0 && sceneImages[0]) {
textureLoader.load(sceneImages[0].default, setActiveImage);
} else if (mediaPercentageElapsed === 35 && sceneImages[1]) {
loadNewImage(1);
} else if (mediaPercentageElapsed === 70 && sceneImages[2]) {
loadNewImage(2);
}
})();
return () => {
clearTimeout(timer);
};
}, [mediaPercentageElapsed, sceneImages, textureLoader]);
return (

View file

@ -0,0 +1,277 @@
import React, { useCallback, useEffect, useRef } from "react";
import {
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSsknSceneContext,
useStore,
} from "../store";
import getKeyPress from "../utils/getKeyPress";
import handleMediaSceneInput from "../core/input-handlers/handleMediaSceneInput";
import handleSsknSceneInput from "../core/input-handlers/handleSsknSceneInput";
import handleMainSceneInput from "../core/input-handlers/handleMainSceneInput";
import handleBootSceneInput from "../core/input-handlers/handleBootSceneInput";
import handleEndSceneInput from "../core/input-handlers/handleEndSceneInput";
import handleEvent from "../core/handleEvent";
import { GameEvent } from "../types/types";
import { MouseEvent, useLoader } from "react-three-fiber";
import circleButton from "../static/sprites/controller/circle.png";
import squareButton from "../static/sprites/controller/square.png";
import triangleButton from "../static/sprites/controller/triangle.png";
import crossButton from "../static/sprites/controller/cross.png";
import startButton from "../static/sprites/controller/start.png";
import l2Button from "../static/sprites/controller/l2.png";
import * as THREE from "three";
import { useGesture } from "react-use-gesture";
import IdleManager from "./IdleManager";
type InputHandlerProps = {
isMobile: boolean;
};
const InputHandler = (props: InputHandlerProps) => {
const scene = useStore((state) => state.currentScene);
const inputCooldown = useStore((state) => state.inputCooldown);
const circleButtonTex = useLoader(THREE.TextureLoader, circleButton);
const crossButtonTex = useLoader(THREE.TextureLoader, crossButton);
const squareButtonTex = useLoader(THREE.TextureLoader, squareButton);
const triangleButtonTex = useLoader(THREE.TextureLoader, triangleButton);
const startButtonTex = useLoader(THREE.TextureLoader, startButton);
const l2ButtonTex = useLoader(THREE.TextureLoader, l2Button);
const timeSinceLastKeyPress = useRef(-1);
const lainIdleTimerRef = useRef(-1);
const idleSceneTimerRef = useRef(-1);
const handleKeyPress = useCallback(
(keyPress: string) => {
const now = Date.now();
if (
now > timeSinceLastKeyPress.current + inputCooldown &&
inputCooldown !== -1
) {
if (scene === "main") {
timeSinceLastKeyPress.current = now;
lainIdleTimerRef.current = now;
idleSceneTimerRef.current = now;
}
const sceneFns = (() => {
switch (scene) {
case "main":
return {
contextProvider: getMainSceneContext,
keyPressHandler: handleMainSceneInput,
};
case "media":
return {
contextProvider: getMediaSceneContext,
keyPressHandler: handleMediaSceneInput,
};
case "sskn":
return {
contextProvider: getSsknSceneContext,
keyPressHandler: handleSsknSceneInput,
};
case "boot":
return {
contextProvider: getBootSceneContext,
keyPressHandler: handleBootSceneInput,
};
case "end":
return {
contextProvider: getEndSceneContext,
keyPressHandler: handleEndSceneInput,
};
case "gate":
case "polytan":
useStore.setState({ currentScene: "main" });
break;
case "idle_media":
useStore.setState({
currentScene: "main",
idleStarting: false,
intro: false,
inputCooldown: -1,
});
break;
}
})();
if (sceneFns) {
const { contextProvider, keyPressHandler } = sceneFns;
const ctx = contextProvider();
const event: GameEvent | undefined = keyPressHandler(
ctx as any,
keyPress
);
if (event) handleEvent(event);
}
}
},
[inputCooldown, scene]
);
const bind = useGesture(
{
onDragEnd: ({ axis, direction: xy }) => {
if (axis === "x") {
if (xy[0] > 0) handleKeyPress("RIGHT");
else handleKeyPress("LEFT");
} else {
if (xy[1] > 0) handleKeyPress("DOWN");
else handleKeyPress("UP");
}
},
},
{ drag: { delay: true } }
);
const firedRef = useRef(false);
const handleKeyBoardEvent = useCallback(
(event) => {
if (!firedRef.current) {
firedRef.current = true;
const key = getKeyPress(event.key);
if (key) handleKeyPress(key);
}
},
[handleKeyPress]
);
const handleVirtualButtonPress = useCallback(
(event: MouseEvent) => {
handleKeyPress(event.object.name);
},
[handleKeyPress]
);
useEffect(() => {
window.addEventListener("keydown", handleKeyBoardEvent);
window.addEventListener("keyup", () => {
firedRef.current = false;
});
return () => {
window.removeEventListener("keydown", handleKeyBoardEvent);
window.removeEventListener("keyup", () => {
firedRef.current = false;
});
};
}, [handleKeyBoardEvent]);
return (
<>
{props.isMobile && (
<>
<sprite scale={[10, 10, 0]} renderOrder={99999} {...bind()}>
<spriteMaterial attach="material" opacity={0} depthTest={false} />
</sprite>
<sprite
scale={[1.5, 1.5, 0]}
position={[-4, 3, 0]}
renderOrder={99999}
onClick={handleVirtualButtonPress}
name={"L2"}
>
<spriteMaterial
attach="material"
map={l2ButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
<sprite
scale={[1.5, 1.5, 0]}
position={[4, 3, 0]}
renderOrder={99999}
onClick={handleVirtualButtonPress}
name={"START"}
>
<spriteMaterial
attach="material"
map={startButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
<group
scale={[0.8, 0.8, 0]}
position={[3.5, -2.3, 0]}
renderOrder={9999}
>
<sprite
scale={[1.5, 1.5, 0]}
position={[1, 0, 0]}
onClick={handleVirtualButtonPress}
name={"CIRCLE"}
>
<spriteMaterial
attach="material"
map={circleButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
<sprite
scale={[1.5, 1.5, 0]}
position={[0, -1, 0]}
onClick={handleVirtualButtonPress}
name={"CROSS"}
>
<spriteMaterial
attach="material"
map={crossButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
<sprite
scale={[1.5, 1.5, 0]}
position={[0, 1, 0]}
onClick={handleVirtualButtonPress}
name={"TRIANGLE"}
>
<spriteMaterial
attach="material"
map={triangleButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
<sprite
scale={[1.5, 1.5, 0]}
position={[-1, 0, 0]}
onClick={handleVirtualButtonPress}
name={"square"}
>
<spriteMaterial
attach="material"
map={squareButtonTex}
depthTest={false}
opacity={0.8}
/>
</sprite>
</group>
</>
)}
<IdleManager
lainIdleTimerRef={lainIdleTimerRef}
idleSceneTimerRef={idleSceneTimerRef}
/>
</>
);
};
export default InputHandler;

View file

@ -1,163 +0,0 @@
import { useCallback, useEffect, useRef } from "react";
import {
BootSceneContext,
EndSceneContext,
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSsknSceneContext,
MainSceneContext,
MediaSceneContext,
playAudio,
SsknSceneContext,
useStore,
} from "../store";
import { getKeyCodeAssociation } from "../utils/keyPressUtils";
import handleMediaSceneKeyPress from "../core/scene-keypress-handlers/handleMediaSceneKeyPress";
import handleSsknSceneKeyPress from "../core/scene-keypress-handlers/handleSsknSceneKeyPress";
import handleMainSceneKeyPress from "../core/scene-keypress-handlers/handleMainSceneKeyPress";
import handleBootSceneKeyPress from "../core/scene-keypress-handlers/handleBootSceneKeyPress";
import { useFrame } from "react-three-fiber";
import { getRandomIdleLainAnim } from "../utils/idle-utils";
import * as audio from "../static/sfx";
import handleEndSceneKeyPress from "../core/scene-keypress-handlers/handleEndSceneKeyPress";
import handleMediaSceneEvent from "../core/scene-event-handlers/handleMediaSceneEvent";
import handleSsknSceneEvent from "../core/scene-event-handlers/handleSsknSceneEvent";
import handleBootSceneEvent from "../core/scene-event-handlers/handleBootSceneEvent";
import handleEndSceneEvent from "../core/scene-event-handlers/handleEndSceneEvent";
import handleEvent from "../core/scene-event-handlers/handleEvent";
const KeyPressHandler = () => {
const scene = useStore((state) => state.currentScene);
const mainSubscene = useStore((state) => state.mainSubscene);
const inputCooldown = useStore((state) => state.inputCooldown);
const setLainMoveState = useStore((state) => state.setLainMoveState);
const timeSinceLastKeyPress = useRef(-1);
const lainIdleCounter = useRef(-1);
const idleSceneCounter = useRef(-1);
useFrame(() => {
const now = Date.now();
if (
lainIdleCounter.current > -1 &&
idleSceneCounter.current > -1 &&
mainSubscene !== "pause" &&
mainSubscene !== "level_selection" &&
scene === "main"
) {
if (now > lainIdleCounter.current + 10000) {
setLainMoveState(getRandomIdleLainAnim());
// after one idle animation plays, the second comes sooner than it would after a regular keypress
lainIdleCounter.current = now - 2500;
}
if (now > idleSceneCounter.current + 30000) {
// put it on lock until the next action, since while the idle media plays, the
// Date.now() value keeps increasing, which can result in another idle media playing right after one finishes
// one way to work around this would be to modify the value depending on the last played idle media's duration
// but i'm way too lazy for that
idleSceneCounter.current = -1;
// idleManager(getRandomIdleMedia());
playAudio(audio.sound32);
setTimeout(() => {
// useStore.setState({ event: "play_idle_media" });
}, 1200);
}
}
});
useEffect(() => {
if (scene !== "main") idleSceneCounter.current = -1;
}, [scene]);
const handleKeyPress = useCallback(
(event) => {
const { keyCode } = event;
const keyPress = getKeyCodeAssociation(keyCode);
const now = Date.now();
if (
keyPress
// !inputCooldown &&
// now > timeSinceLastKeyPress.current + 1500
) {
if (scene === "main") {
lainIdleCounter.current = now;
idleSceneCounter.current = now;
timeSinceLastKeyPress.current = now;
}
const sceneFns = (() => {
switch (scene) {
case "main":
return {
contextProvider: getMainSceneContext,
keyPressHandler: handleMainSceneKeyPress,
};
case "media":
return {
contextProvider: getMediaSceneContext,
keyPressHandler: handleMediaSceneKeyPress,
};
// case "sskn":
// return {
// contextProvider: getSsknSceneContext,
// keyPressHandler: handleSsknSceneKeyPress,
// eventHandler: handleSsknSceneEvent,
// };
// case "boot":
// return {
// contextProvider: getBootSceneContext,
// keyPressHandler: handleBootSceneKeyPress,
// eventHandler: handleBootSceneEvent,
// };
// case "end":
// return {
// contextProvider: getEndSceneContext,
// keyPressHandler: handleEndSceneKeyPress,
// eventHandler: handleEndSceneEvent,
// };
// case "gate":
// case "polytan":
// useStore.setState({ currentScene: "main" });
// break;
// case "idle_media":
// useStore.setState({
// currentScene: "main",
// idleStarting: false,
// });
// break;
}
})();
if (sceneFns) {
const { contextProvider, keyPressHandler } = sceneFns;
const ctx = contextProvider(keyPress);
const event = keyPressHandler(ctx as any) as any;
if (event) handleEvent(event);
// if (event) eventHandler(event.event, event.mutations);
}
}
},
[inputCooldown, scene]
);
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, [handleKeyPress]);
return null;
};
export default KeyPressHandler;

View file

@ -1,12 +1,12 @@
import React, { useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import takIntro from "../static/sprite/tak_intro.png";
import takOutro from "../static/sprite/tak_outro.png";
import mouth1 from "../static/sprite/mouth_1.png";
import mouth2 from "../static/sprite/mouth_2.png";
import mouth3 from "../static/sprite/mouth_3.png";
import mouth4 from "../static/sprite/mouth_4.png";
import takIntro from "../static/sprites/lain/lain_speak_intro.png";
import takOutro from "../static/sprites/lain/lain_speak_outro.png";
import mouth1 from "../static/sprites/lain/mouth_1.png";
import mouth2 from "../static/sprites/lain/mouth_2.png";
import mouth3 from "../static/sprites/lain/mouth_3.png";
import mouth4 from "../static/sprites/lain/mouth_4.png";
import { useStore } from "../store";
import { LainConstructor } from "./MainScene/Lain";

View file

@ -1,11 +1,11 @@
import React, { useState } from "react";
import loadingSpritesheet from "../static/sprite/loading_spritesheet.png";
import lifeInstinct from "../static/sprite/life_instinct_function_os.png";
import React, { memo, useState } from "react";
import loadingSpritesheet from "../static/sprites/loading/loading_spritesheet.png";
import lifeInstinct from "../static/sprites/loading/life_instinct_function_os.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
const Loading = () => {
const Loading = memo(() => {
const loadingTex: any = useLoader(THREE.TextureLoader, loadingSpritesheet);
const lifeInstinctTex = useLoader(THREE.TextureLoader, lifeInstinct);
@ -21,14 +21,29 @@ const Loading = () => {
return (
<>
<sprite scale={[0.35, 0.6, 0.35]} position={[0, 0.2, 0]}>
<spriteMaterial attach="material" map={loadingTex} />
<sprite scale={[5, 5, 5]} renderOrder={999}>
<spriteMaterial attach="material" color={0x000000} depthTest={false} />
</sprite>
<sprite scale={[0.4, 0.6, 0.4]} position={[0, -0.5, 0]}>
<spriteMaterial attach="material" map={lifeInstinctTex} />
<sprite
scale={[0.35, 0.6, 0.35]}
position={[0, 0.2, 0]}
renderOrder={1000}
>
<spriteMaterial attach="material" map={loadingTex} depthTest={false} />
</sprite>
<sprite
scale={[0.4, 0.6, 0.4]}
position={[0, -0.5, 0]}
renderOrder={1000}
>
<spriteMaterial
attach="material"
map={lifeInstinctTex}
depthTest={false}
/>
</sprite>
</>
);
};
});
export default Loading;

View file

@ -1,35 +1,15 @@
import React, { memo, useEffect, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import bigHud from "../../static/sprite/big_hud.png";
import longHud from "../../static/sprite/long_hud.png";
import boringHud from "../../static/sprite/long_hud_boring.png";
import bigHud from "../../static/sprites/main/big_hud.png";
import longHud from "../../static/sprites/main/long_hud.png";
import boringHud from "../../static/sprites/main/boring_hud.png";
import { useStore } from "../../store";
import lerp from "../../utils/lerp";
import GreenTextRenderer from "../TextRenderer/GreenTextRenderer";
import usePrevious from "../../hooks/usePrevious";
import { getNodeHud } from "../../utils/node-utils";
export type HUDType = {
mirrored: number;
long: {
position: number[];
initial_position: number[];
};
boring: {
position: number[];
initial_position: number[];
};
big: {
position: number[];
initial_position: number[];
};
big_text: number[];
medium_text: {
position: number[];
initial_position: number[];
};
};
import { getNodeHud } from "../../helpers/node-helpers";
import { HUDData } from "../../types/types";
const HUD = memo(() => {
const activeRef = useRef(true);
@ -45,18 +25,6 @@ const HUD = memo(() => {
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ siteRotY, activeLevel, subscene, scene });
const lerpObject = (
obj: THREE.Object3D,
posX: number,
initialPosX: number
) => {
obj.position.x = lerp(
obj.position.x,
activeRef.current ? posX : initialPosX,
0.12
);
};
// this part is imperative because it performs a lot better than having a toggleable spring.
useFrame(() => {
if (
@ -66,25 +34,30 @@ const HUD = memo(() => {
greenTextRef.current
) {
const hud = currentHudRef.current;
lerpObject(
longHudRef.current,
hud.long.position[0],
hud.long.initial_position[0]
longHudRef.current.position.x = lerp(
longHudRef.current.position.x,
activeRef.current ? hud.long.position[0] : hud.long.initial_position[0],
0.12
);
lerpObject(
boringHudRef.current,
hud.boring.position[0],
hud.boring.initial_position[0]
boringHudRef.current.position.x = lerp(
boringHudRef.current.position.x,
activeRef.current
? hud.boring.position[0]
: hud.boring.initial_position[0],
0.12
);
lerpObject(
bigHudRef.current,
hud.big.position[0],
hud.big.initial_position[0]
bigHudRef.current.position.x = lerp(
bigHudRef.current.position.x,
activeRef.current ? hud.big.position[0] : hud.big.initial_position[0],
0.12
);
lerpObject(
greenTextRef.current,
hud.medium_text.position[0],
hud.medium_text.initial_position[0]
greenTextRef.current.position.x = lerp(
greenTextRef.current.position.x,
activeRef.current
? hud.medium_text.position[0]
: hud.medium_text.initial_position[0],
0.12
);
}
});
@ -102,7 +75,7 @@ const HUD = memo(() => {
bigHudRef.current!.scale.x = Math.abs(bigHudRef.current!.scale.x);
};
const setPos = (hud: HUDType, pos: string) => {
const setPos = (hud: HUDData, pos: string) => {
longHudRef.current!.position.set(
...(hud.long[pos as keyof typeof hud.long] as [number, number, number])
);
@ -130,11 +103,12 @@ const HUD = memo(() => {
if (
!(scene === "main" && prevData?.scene === "main") ||
(subscene === "site" && prevData?.subscene === "pause") ||
(subscene === "site" && prevData?.subscene === "not_found") ||
subscene === "pause"
) {
// set to final pos instantly
setPos(hud, "position");
if (hud.mirrored) mirror();
else unMirror();
} else {
if (
prevData?.siteRotY !== siteRotY ||
@ -149,11 +123,10 @@ const HUD = memo(() => {
() => {
// set to initial pos instantly while its hidden
setPos(hud, "initial_position");
if (hud.mirrored) {
mirror();
} else {
unMirror();
}
if (hud.mirrored) mirror();
else unMirror();
currentHudRef.current = hud;
activeRef.current = true;
},

View file

@ -2,35 +2,35 @@ import React, { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-animator";
import moveDownSpriteSheet from "../../static/sprite/jump_down.png";
import moveUpSpriteSheet from "../../static/sprite/jump_up.png";
import moveLeftSpriteSheet from "../../static/sprite/move_left.png";
import moveRightSpriteSheet from "../../static/sprite/move_right.png";
import standingSpriteSheet from "../../static/sprite/standing.png";
import introSpriteSheet from "../../static/sprite/intro.png";
import throwNodeSpriteSheet from "../../static/sprite/throw_node.png";
import ripMiddleRingSpriteSheet from "../../static/sprite/rip_middle_ring.png";
import knockSpriteSheet from "../../static/sprite/knock.png";
import knockAndFallSpriteSheet from "../../static/sprite/knock_and_fall.png";
import touchAndScareSpriteSheet from "../../static/sprite/touch_node_and_get_scared.png";
import ripNodeSpriteSheet from "../../static/sprite/rip_node.png";
import touchSleeveSpriteSheet from "../../static/sprite/touch_sleeve.png";
import prayerSpriteSheet from "../../static/sprite/prayer.png";
import thinkingSpriteSheet from "../../static/sprite/thinking.png";
import stretchSpriteSheet from "../../static/sprite/stretch.png";
import stretch2SpriteSheet from "../../static/sprite/stretch_2.png";
import spinSpriteSheet from "../../static/sprite/spin.png";
import scratchHeadSpriteSheet from "../../static/sprite/scratch_head.png";
import blushSpriteSheet from "../../static/sprite/blush.png";
import handsBehindHeadSpriteSheet from "../../static/sprite/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../../static/sprite/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../../static/sprite/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../../static/sprite/hands_together.png";
import leanForwardSpriteSheet from "../../static/sprite/lean_forward.png";
import leanLeftSpriteSheet from "../../static/sprite/lean_left.png";
import leanRightSpriteSheet from "../../static/sprite/lean_right.png";
import lookAroundSpriteSheet from "../../static/sprite/look_around.png";
import playWithHairSpriteSheet from "../../static/sprite/play_with_hair.png";
import moveDownSpriteSheet from "../../static/sprites/lain/jump_down.png";
import moveUpSpriteSheet from "../../static/sprites/lain/jump_up.png";
import moveLeftSpriteSheet from "../../static/sprites/lain/move_left.png";
import moveRightSpriteSheet from "../../static/sprites/lain/move_right.png";
import standingSpriteSheet from "../../static/sprites/lain/standing.png";
import introSpriteSheet from "../../static/sprites/lain/intro.png";
import throwNodeSpriteSheet from "../../static/sprites/lain/throw_node.png";
import ripMiddleRingSpriteSheet from "../../static/sprites/lain/rip_middle_ring.png";
import knockSpriteSheet from "../../static/sprites/lain/knock.png";
import knockAndFallSpriteSheet from "../../static/sprites/lain/knock_and_fall.png";
import touchAndScareSpriteSheet from "../../static/sprites/lain/touch_node_and_get_scared.png";
import ripNodeSpriteSheet from "../../static/sprites/lain/rip_node.png";
import touchSleeveSpriteSheet from "../../static/sprites/lain/touch_sleeve.png";
import prayerSpriteSheet from "../../static/sprites/lain/prayer.png";
import thinkingSpriteSheet from "../../static/sprites/lain/thinking.png";
import stretchSpriteSheet from "../../static/sprites/lain/stretch.png";
import stretch2SpriteSheet from "../../static/sprites/lain/stretch_2.png";
import spinSpriteSheet from "../../static/sprites/lain/spin.png";
import scratchHeadSpriteSheet from "../../static/sprites/lain/scratch_head.png";
import blushSpriteSheet from "../../static/sprites/lain/blush.png";
import handsBehindHeadSpriteSheet from "../../static/sprites/lain/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../../static/sprites/lain/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../../static/sprites/lain/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../../static/sprites/lain/hands_together.png";
import leanForwardSpriteSheet from "../../static/sprites/lain/lean_forward.png";
import leanLeftSpriteSheet from "../../static/sprites/lain/lean_left.png";
import leanRightSpriteSheet from "../../static/sprites/lain/lean_right.png";
import lookAroundSpriteSheet from "../../static/sprites/lain/look_around.png";
import playWithHairSpriteSheet from "../../static/sprites/lain/play_with_hair.png";
import { useStore } from "../../store";

View file

@ -1,12 +1,12 @@
import React, { useEffect, useRef } from "react";
import level_selection_font from "../../static/sprite/select_level_font.png";
import verticalHud from "../../static/sprite/select_level_hud_vertical.png";
import horizontalHud from "../../static/sprite/select_level_hud_horizontal.png";
import levelSelectionText from "../../static/sprite/select_level_text.png";
import upArrow from "../../static/sprite/select_level_up_arrow.png";
import downArrow from "../../static/sprite/select_level_down_arrow.png";
import upArrowActive from "../../static/sprite/select_level_up_arrow_active.png";
import downArrowActive from "../../static/sprite/select_level_down_arrow_active.png";
import level_selection_font from "../../static/sprites/main/select_level_font.png";
import verticalHud from "../../static/sprites/main/select_level_hud_vertical.png";
import horizontalHud from "../../static/sprites/main/select_level_hud_horizontal.png";
import levelSelectionText from "../../static/sprites/main/select_level_text.png";
import upArrow from "../../static/sprites/main/select_level_up_arrow.png";
import downArrow from "../../static/sprites/main/select_level_down_arrow.png";
import upArrowActive from "../../static/sprites/main/select_level_up_arrow_active.png";
import downArrowActive from "../../static/sprites/main/select_level_down_arrow_active.png";
import { useStore } from "../../store";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
@ -124,7 +124,7 @@ const LevelSelection = () => {
]);
return (
<group>
<>
<a.group position-y={pos.vertPosY} renderOrder={5}>
<mesh
scale={[0.3, 0.4, 0]}
@ -212,7 +212,7 @@ const LevelSelection = () => {
depthTest={false}
/>
</a.sprite>
</group>
</>
);
};

View file

@ -1,6 +1,6 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import middleRingTexture from "../../../static/sprite/middle_ring_tex.png";
import middleRingTexture from "../../../static/sprites/main/middle_ring_tex.png";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";

View file

@ -1,5 +1,5 @@
import React, { useEffect, useMemo } from "react";
import middleRingTexture from "../../../static/sprite/middle_ring_tex.png";
import middleRingTexture from "../../../static/sprites/main/middle_ring_tex.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";

View file

@ -3,28 +3,9 @@ import * as THREE from "three";
import PauseSquare from "./PauseSquare";
import PauseBigLetter from "../../TextRenderer/PauseBigLetter";
import { useStore } from "../../../store";
import { useLoader } from "react-three-fiber";
import usePrevious from "../../../hooks/usePrevious";
const Pause = () => {
const exit = useStore((state) => state.pauseExitAnimation);
const [showActiveComponent, setShowActiveComponent] = useState(false);
const [animation, setAnimation] = useState(false);
const [intro, setIntro] = useState(true);
const wordFont = useLoader(THREE.FontLoader, "/3d_fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,
size: 2.5,
}),
[wordFont]
);
const activeComponent = useStore((state) =>
showActiveComponent ? state.activePauseComponent : ""
);
const generateSqaureGeom = useCallback((row: number, square: number) => {
const geometry = new THREE.PlaneBufferGeometry();
const uvAttribute = geometry.attributes.uv;
@ -48,306 +29,169 @@ const Pause = () => {
[generateSqaureGeom]
);
const subscene = useStore((state) => state.mainSubscene);
const letterLocs = useMemo(
() => ({
"05": { letter: "E" },
"11": { letter: "S" },
"33": { letter: "C" },
"45": { letter: "A" },
"51": { letter: "L" },
}),
[]
);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ subscene });
const setInputCooldown = useStore((state) => state.setInputCooldown);
const [visible, setVisible] = useState(false);
const [finished, setFinished] = useState(false);
const [exit, setExit] = useState(false);
const activeComponent = useStore(
useCallback((state) => (finished ? state.activePauseComponent : ""), [
finished,
])
);
useEffect(() => {
setAnimation(false);
setIntro(true);
setShowActiveComponent(false);
if (subscene === "pause") {
setTimeout(() => {
setTimeout(() => {
setAnimation(true);
}, 1000);
setTimeout(() => {
setShowActiveComponent(true);
setIntro(false);
setInputCooldown(false);
}, 3500);
}, 3400);
setTimeout(() => setVisible(true), 4400);
setTimeout(() => setFinished(true), 7300);
setTimeout(() => setInputCooldown(1000), 7600);
}
}, [setInputCooldown, subscene]);
if (prevData?.subscene === "pause" && subscene === "site") {
setExit(true);
setTimeout(() => {
setVisible(false);
setFinished(false);
setExit(false);
}, 1200);
}
}, [prevData?.subscene, setInputCooldown, subscene]);
const whenActive = useCallback((rowIdx: number, colIdx: number) => {
switch (rowIdx) {
case 5:
if (colIdx > 1 && colIdx < 5) return "load";
break;
case 4:
if (colIdx > 5 && colIdx < 7) return "about";
break;
case 3:
if (colIdx > 3 && colIdx < 7) return "change";
break;
case 1:
if (colIdx > 1 && colIdx < 5) return "save";
break;
case 0:
if (colIdx > 4 && colIdx < 7) return "exit";
break;
}
}, []);
return (
<>
{animation && (
<>
<group position={[-0.85, -0.7, 0]} scale={[0.85, 0.85, 0]}>
{[0, 1, 2, 3, 2, 1, 0].map((row: number, rowIdx: number) =>
[0, 1, 2, 3, 4, 5, 6].map((col: number) => {
if (rowIdx === 5 && col > 0 && col < 5) {
return col === 1 ? (
<React.Fragment key={`Lfragment`}>
<PauseBigLetter
color={"white"}
letter={"L"}
letterIdx={col}
position={[0.35, 1.8, 0]}
scale={[0.25, 0.25, 0.25]}
active={!(activeComponent === "load")}
key={"whiteL"}
rowIdx={rowIdx}
colIdx={col}
intro={intro}
/>
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={"whiteLsquare"}
shouldDisappear={true}
intro={intro}
/>
</React.Fragment>
) : (
<PauseSquare
geometry={squareGeoms[row][col]}
{visible && (
<group position={[-0.9, -0.7, 0]} scale={[0.85, 0.85, 0]}>
{[0, 1, 2, 3, 2, 1, 0].map((r: number, rowIdx: number) =>
[0, 1, 2, 3, 4, 5, 6].map((c: number, colIdx: number) => {
const key = `${rowIdx}${colIdx}`;
const letter = letterLocs[key as keyof typeof letterLocs];
if (letter)
return (
<React.Fragment key={`${key}fragment`}>
<PauseBigLetter
letter={letter.letter}
letterIdx={0}
position={[colIdx / 2.8, rowIdx / 2.8, 0]}
rowIdx={rowIdx}
colIdx={col}
active={!(activeComponent === "load")}
key={`${rowIdx}${col}L`}
intro={intro}
colIdx={colIdx}
mainLetter={true}
active={
letter.letter ===
activeComponent.charAt(0).toUpperCase()
}
introFinished={finished}
exit={exit}
/>
);
} else if (rowIdx === 4 && col > 4 && col < 7) {
return col === 5 ? (
<React.Fragment key={"AFragment"}>
<PauseBigLetter
color={"white"}
letter={"A"}
letterIdx={col}
position={[1.78, 1.43, 0]}
scale={[0.25, 0.25, 0]}
active={!(activeComponent === "about")}
key={"whiteA"}
rowIdx={rowIdx}
colIdx={col}
intro={intro}
/>
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={"whiteAsquare"}
shouldDisappear={true}
intro={intro}
/>
</React.Fragment>
) : (
<PauseSquare
geometry={squareGeoms[row][col]}
geometry={squareGeoms[r][c]}
colIdx={colIdx}
rowIdx={rowIdx}
colIdx={col}
active={!(activeComponent === "about")}
key={`${rowIdx}${col}A`}
intro={intro}
letter={letter.letter}
introFinished={finished}
exit={exit}
/>
);
} else if (rowIdx === 3 && col > 2 && col < 7) {
return col === 3 ? (
<React.Fragment key={"CFragment"}>
<PauseBigLetter
color={"white"}
letter={"C"}
letterIdx={col}
position={[1.05, 1.07, 0]}
scale={[0.25, 0.25, 0]}
active={!(activeComponent === "change")}
key={"whiteC"}
rowIdx={rowIdx}
colIdx={col}
intro={intro}
/>
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={"whiteCsquare"}
shouldDisappear={true}
intro={intro}
/>
</React.Fragment>
) : (
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
active={!(activeComponent === "change")}
key={`${rowIdx}${col}C`}
intro={intro}
/>
);
} else if (rowIdx === 1 && col > 0 && col < 5) {
return col === 1 ? (
<React.Fragment key={"Sfragment"}>
<PauseBigLetter
color={"white"}
letter={"S"}
letterIdx={col}
position={[0.35, 0.35, 0]}
scale={[0.25, 0.25, 0]}
active={!(activeComponent === "save")}
key={"whiteS"}
rowIdx={rowIdx}
colIdx={col}
intro={intro}
/>
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={"whiteSsquare"}
shouldDisappear={true}
intro={intro}
/>
</React.Fragment>
) : (
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
active={!(activeComponent === "save")}
key={`${rowIdx}${col}S`}
intro={intro}
/>
);
} else if (rowIdx === 0 && col > 4 && col < 7) {
return col === 5 ? (
<React.Fragment key={"Efragment"}>
<PauseBigLetter
color={"white"}
letter={"E"}
letterIdx={col}
position={[1.78, 0, 0]}
scale={[0.25, 0.25, 0]}
active={!(activeComponent === "exit")}
key={"whiteE"}
rowIdx={1}
colIdx={col}
intro={intro}
/>
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={"whiteEsquare"}
shouldDisappear={true}
intro={intro}
/>
</React.Fragment>
) : (
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
active={!(activeComponent === "exit")}
key={`${rowIdx}${col}E`}
intro={intro}
/>
);
} else {
return (
<PauseSquare
geometry={squareGeoms[row][col]}
rowIdx={rowIdx}
colIdx={col}
key={`${rowIdx}${col}r`}
active={true}
intro={intro}
/>
);
}
})
)}
{"Load".split("").map((letter, idx) => (
</React.Fragment>
);
else
return (
<PauseSquare
geometry={squareGeoms[r][c]}
colIdx={colIdx}
rowIdx={rowIdx}
key={key}
active={activeComponent === whenActive(rowIdx, colIdx)}
introFinished={finished}
exit={exit}
/>
);
})
)}
<>
{"oad".split("").map((letter, idx) => (
<PauseBigLetter
color={idx > 0 ? "yellow" : "orange"}
letter={letter}
letterIdx={idx}
key={idx}
position={[0.35 + idx / 2.8, 1.8, 0]}
scale={[0.25, 0.25, 0.25]}
position={[2 / 2.8 + idx / 2.8, 5 / 2.8, 0]}
active={activeComponent === "load"}
/>
))}
{"About".split("").map((letter, idx) => (
{"bout".split("").map((letter, idx) => (
<PauseBigLetter
color={idx > 0 ? "yellow" : "orange"}
letter={letter}
letterIdx={idx}
position={[1.78 + idx / 2.8, 1.43, 0]}
scale={[0.25, 0.25, 0]}
position={[6 / 2.8 + idx / 2.8, 4 / 2.8, 0]}
active={activeComponent === "about"}
key={idx}
/>
))}
{"Change".split("").map((letter, idx) => (
{"hange".split("").map((letter, idx) => (
<PauseBigLetter
color={idx > 0 ? "yellow" : "orange"}
letter={letter}
letterIdx={idx}
position={[1.05 + idx / 2.8, 1.07, 0]}
scale={[0.25, 0.25, 0]}
position={[4 / 2.8 + idx / 2.8, 3 / 2.8, 0]}
active={activeComponent === "change"}
key={idx}
/>
))}
{"Save".split("").map((letter, idx) => (
{"ave".split("").map((letter, idx) => (
<PauseBigLetter
color={idx > 0 ? "yellow" : "orange"}
letter={letter}
letterIdx={idx}
position={[0.35 + idx / 2.8, 0.35, 0]}
scale={[0.25, 0.25, 0]}
position={[2 / 2.8 + idx / 2.8, 1 / 2.8, 0]}
active={activeComponent === "save"}
key={idx}
/>
))}
{"Exit".split("").map((letter, idx) => (
{"xit".split("").map((letter, idx) => (
<PauseBigLetter
color={idx > 0 ? "yellow" : "orange"}
letter={letter}
letterIdx={idx}
position={[1.78 + idx / 2.8, 0, 0]}
scale={[0.25, 0.25, 0]}
position={[6 / 2.8 + idx / 2.8, 0, 0]}
key={idx}
active={activeComponent === "exit"}
/>
))}
<group visible={!exit}>
<sprite
position={[0.5, -0.8, 0]}
scale={[3, 1, 0]}
renderOrder={100}
>
<spriteMaterial
attach="material"
color={0x000000}
opacity={0.8}
depthTest={false}
/>
</sprite>
<mesh
scale={[0.08, 0.07, 0]}
position={[-0.2, -0.6, 0]}
renderOrder={101}
>
<textGeometry
attach="geometry"
args={["Application Version 1.0", config]}
/>
<meshBasicMaterial
attach="material"
color={0x00ba7c}
transparent={true}
depthTest={false}
/>
</mesh>
</group>
</group>
</>
</>
</group>
)}
</>
);

View file

@ -1,25 +1,47 @@
import React, { useMemo, memo } from "react";
import * as THREE from "three";
import React, { memo, useMemo } from "react";
import pauseGrayBoxes from "../../../static/sprites/main/pause_gray_boxes.png";
import { useLoader } from "react-three-fiber";
import pauseGrayBoxes from "../../../static/sprite/pause_gray_boxes.png";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
type PauseSquareProps = {
geometry: THREE.PlaneBufferGeometry;
colIdx: number;
rowIdx: number;
geometry: THREE.PlaneBufferGeometry;
letter?: string;
active?: boolean;
shouldDisappear?: boolean;
intro?: boolean;
introFinished?: boolean;
exit?: boolean;
};
const PauseSquare = memo((props: PauseSquareProps) => {
const exitAnimation = useStore((state) => state.pauseExitAnimation);
const squareTex = useLoader(THREE.TextureLoader, pauseGrayBoxes);
const grayBoxesTex = useLoader(THREE.TextureLoader, pauseGrayBoxes);
const introSpring = useSpring({
from: {
posX: 1.05,
posY: 1.07,
rotZ: -1,
rotX: Math.PI,
rotY: Math.PI,
},
to: async (next) => {
await next({
posX: props.colIdx / 2.8,
posY: props.rowIdx / 2.8,
rotZ: 0,
config: { duration: 500 },
});
await next({
rotX: 0,
rotY: props.letter ? Math.PI / 2 : 0,
delay: (props.rowIdx + props.colIdx) * 100,
config: { duration: 200 },
});
},
});
const getExitAnimValue = useMemo(() => {
const exitAnimValue = useMemo(() => {
let col, row;
if (props.colIdx < 3) col = -1;
else if (props.colIdx > 3) col = 1;
@ -29,85 +51,47 @@ const PauseSquare = memo((props: PauseSquareProps) => {
else if (props.rowIdx > 3) row = 1;
else row = 0;
return { row, col };
return { row: row * 2.2, col: col * 2.2 };
}, [props.colIdx, props.rowIdx]);
const initialState = useSpring({
posX: props.colIdx / 2.8 + getExitAnimValue.col * (exitAnimation ? 2.2 : 0),
posY: props.rowIdx / 2.8 + getExitAnimValue.row * (exitAnimation ? 2.2 : 0),
rotX: props.active ? (exitAnimation ? Math.PI / 2 : 0) : -Math.PI,
rotY: props.active ? (exitAnimation ? Math.PI / 2 : 0) : Math.PI / 2,
rotZ: 0,
from: { posX: 1.05, posY: 1.07, rotZ: -1 },
const spring = useSpring({
posX: props.colIdx / 2.8 + (props.exit ? exitAnimValue.col : 0),
posY: props.rowIdx / 2.8 + (props.exit ? exitAnimValue.row : 0),
rotY: props.active || props.exit ? Math.PI / 2 : 0,
rotX: props.active ? Math.PI : 0,
config: { duration: 500 },
});
const shadowState = useSpring({
posX: props.colIdx / 2.8 + getExitAnimValue.col * (exitAnimation ? 2.2 : 0),
posY: props.rowIdx / 2.8 + getExitAnimValue.row * (exitAnimation ? 2.2 : 0),
rotX: exitAnimation ? Math.PI / 2 : 0,
rotY: exitAnimation ? Math.PI / 2 : 0,
from: { posX: 1.05, posY: 1.07, rotZ: -1 },
config: { duration: 500 },
});
const introState = useSpring({
rotX: 0,
rotY: props.shouldDisappear ? Math.PI / 2 : 0,
from: { rotX: Math.PI, rotY: Math.PI },
delay: (props.rowIdx + props.colIdx) * 100 + 500,
config: { duration: 200 },
});
return (
<>
<a.mesh
geometry={props.geometry}
position-x={initialState.posX}
position-y={initialState.posY}
scale={[
props.colIdx > 3 ? -0.25 : 0.25,
props.rowIdx <= 3 ? -0.25 : 0.25,
0,
]}
rotation-x={props.intro ? introState.rotX : initialState.rotX}
rotation-y={props.intro ? introState.rotY : initialState.rotY}
rotation-z={initialState.rotZ}
renderOrder={100}
>
<meshBasicMaterial
attach="material"
map={grayBoxesTex}
side={
(props.colIdx > 3 && props.rowIdx <= 3) ||
(props.colIdx <= 3 && props.rowIdx > 3)
? THREE.FrontSide
: THREE.BackSide
}
transparent={true}
depthTest={false}
/>
</a.mesh>
<group scale={[0.9, 0.9, 0]} position={[0.1, 0.1, 0]}>
<a.mesh
geometry={props.geometry}
position-x={shadowState.posX}
position-y={shadowState.posY}
scale={[0.25, 0.25, 0]}
rotation-x={shadowState.rotX}
rotation-y={shadowState.rotY}
rotation-z={initialState.rotZ}
renderOrder={99}
>
<meshBasicMaterial
attach="material"
side={THREE.DoubleSide}
transparent={true}
color={0x1d1d2d}
/>
</a.mesh>
</group>
</>
<a.mesh
position-x={props.introFinished ? spring.posX : introSpring.posX}
position-y={props.introFinished ? spring.posY : introSpring.posY}
rotation-z={props.introFinished ? 0 : introSpring.rotZ}
rotation-x={props.introFinished ? spring.rotX : introSpring.rotX}
rotation-y={
!props.letter && props.introFinished ? spring.rotY : introSpring.rotY
}
geometry={props.geometry}
scale={[
props.colIdx > 3 ? -0.25 : 0.25,
props.rowIdx <= 3 ? -0.25 : 0.25,
0,
]}
renderOrder={100}
>
<meshBasicMaterial
attach="material"
map={squareTex}
side={
(props.colIdx > 3 && props.rowIdx <= 3) ||
(props.colIdx <= 3 && props.rowIdx > 3)
? THREE.FrontSide
: THREE.BackSide
}
transparent={true}
depthTest={false}
/>
</a.mesh>
);
});

View file

@ -1,5 +1,5 @@
import React, { useRef } from "react";
import aboutBg from "../../../static/sprite/about_background.png";
import aboutBg from "../../../static/sprites/main/about_background.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../../store";
@ -10,8 +10,6 @@ const About = () => {
const aboutBgTex = useLoader(THREE.TextureLoader, aboutBg);
const bgRef = useRef<THREE.Sprite>();
// todo im not sure where the other bg file is located,
// the one here is just the text, in the original game there's another one
useFrame(() => {
if (bgRef.current) {

View file

@ -1,15 +1,18 @@
import React, { memo } from "react";
import notFound from "../../../static/sprite/not_found.png";
import notFoundLof from "../../../static/sprite/not_found_lof.png";
import notFound from "../../../static/sprites/main/not_found.png";
import notFoundLof from "../../../static/sprites/main/not_found_lof.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../../store";
const NotFound = memo(() => {
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
const wordNotFound = useStore((state) => state.wordNotFound);
return (
<group visible={false}>
<group visible={wordNotFound}>
<sprite scale={[1, 0.25, 0]} renderOrder={106} position={[-1, -0.05, 0]}>
<spriteMaterial
attach="material"

View file

@ -1,5 +1,5 @@
import React, { memo } from "react";
import headerContainer from "../../../static/sprite/prompt_question_container.png";
import headerContainer from "../../../static/sprites/prompt/prompt_question_container.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import StaticOrangeLetter from "../../TextRenderer/StaticOrangeLetter";

View file

@ -2,8 +2,8 @@ import React, { memo, useEffect, useState } from "react";
import Node from "./Node";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import { NodeData, SiteData } from "./Site";
import usePrevious from "../../../hooks/usePrevious";
import {NodeData, SiteData} from "../../../types/types";
type ActiveLevelNodesProps = {
visibleNodes: SiteData;

View file

@ -1,8 +1,8 @@
import React, { memo, useMemo } from "react";
import * as THREE from "three";
import lofTexture from "../../../static/sprite/gray_ring_lof.png";
import holeTexture from "../../../static/sprite/hole.png";
import lifeTexture from "../../../static/sprite/life.png";
import lofTexture from "../../../static/sprites/main/gray_ring_lof.png";
import holeTexture from "../../../static/sprites/main/hole.png";
import lifeTexture from "../../../static/sprites/main/life.png";
import { useLoader } from "react-three-fiber";
type GrayRingProps = {

View file

@ -2,20 +2,20 @@ import React, { memo, useMemo } from "react";
import { useLoader } from "react-three-fiber";
import { a } from "@react-spring/three";
import * as THREE from "three";
import Cou from "../../../static/sprite/Cou.png";
import CouViewed from "../../../static/sprite/Cou_viewed.png";
import Dc from "../../../static/sprite/Dc.png";
import DcViewed from "../../../static/sprite/Dc_viewed.png";
import Sskn from "../../../static/sprite/SSkn.png";
import SsknViewed from "../../../static/sprite/SSkn_viewed.png";
import Tda from "../../../static/sprite/Tda.png";
import TdaViewed from "../../../static/sprite/Tda_viewed.png";
import Dia from "../../../static/sprite/Dia.png";
import DiaViewed from "../../../static/sprite/Dia_viewed.png";
import Lda from "../../../static/sprite/Lda.png";
import LdaViewed from "../../../static/sprite/Lda_viewed.png";
import MULTI from "../../../static/sprite/MULTI.png";
import MULTIViewed from "../../../static/sprite/MULTI_viewed.png";
import Cou from "../../../static/sprites/nodes/Cou.png";
import CouViewed from "../../../static/sprites/nodes/Cou_viewed.png";
import Dc from "../../../static/sprites/nodes/Dc.png";
import DcViewed from "../../../static/sprites/nodes/Dc_viewed.png";
import Sskn from "../../../static/sprites/nodes/SSkn.png";
import SsknViewed from "../../../static/sprites/nodes/SSkn_viewed.png";
import Tda from "../../../static/sprites/nodes/Tda.png";
import TdaViewed from "../../../static/sprites/nodes/Tda_viewed.png";
import Dia from "../../../static/sprites/nodes/Dia.png";
import DiaViewed from "../../../static/sprites/nodes/Dia_viewed.png";
import Lda from "../../../static/sprites/nodes/Lda.png";
import LdaViewed from "../../../static/sprites/nodes/Lda_viewed.png";
import MULTI from "../../../static/sprites/nodes/MULTI.png";
import MULTIViewed from "../../../static/sprites/nodes/MULTI_viewed.png";
import level_y_values from "../../../resources/level_y_values.json";
type NodeContructorProps = {

View file

@ -1,10 +1,10 @@
import React, { memo, useEffect, useState } from "react";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import { SiteData } from "./Site";
import InactiveLevelNode from "./InactiveLevelNode";
import usePrevious from "../../../hooks/usePrevious";
import { generateInactiveNodes } from "../../../utils/node-utils";
import { generateInactiveNodes } from "../../../helpers/node-helpers";
import {SiteData} from "../../../types/types";
type ActiveLevelNodesProps = {
visibleNodes: SiteData;

View file

@ -0,0 +1,21 @@
import React, { memo } from "react";
import mainSceneBg from "../../../static/sprites/main/main_scene_background.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
const MainSceneBackground = memo(() => {
const mainSceneBgTex = useLoader(THREE.TextureLoader, mainSceneBg);
return (
<mesh renderOrder={-5} scale={[5, 1, 0]}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={mainSceneBgTex}
depthTest={false}
/>
</mesh>
);
});
export default MainSceneBackground;

View file

@ -2,27 +2,27 @@ import React, { memo, useEffect, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import { a, useSpring } from "@react-spring/three";
import * as THREE from "three";
import Cou from "../../../static/sprite/Cou.png";
import CouActive from "../../../static/sprite/Cou_active.png";
import CouViewed from "../../../static/sprite/Cou_viewed.png";
import Dc from "../../../static/sprite/Dc.png";
import DcActive from "../../../static/sprite/Dc_active.png";
import DcViewed from "../../../static/sprite/Dc_viewed.png";
import Sskn from "../../../static/sprite/SSkn.png";
import SsknActive from "../../../static/sprite/SSkn_active.png";
import SsknViewed from "../../../static/sprite/SSkn_viewed.png";
import Tda from "../../../static/sprite/Tda.png";
import TdaActive from "../../../static/sprite/Tda_active.png";
import TdaViewed from "../../../static/sprite/Tda_viewed.png";
import Dia from "../../../static/sprite/Dia.png";
import DiaActive from "../../../static/sprite/Dia_active.png";
import DiaViewed from "../../../static/sprite/Dia_viewed.png";
import Lda from "../../../static/sprite/Lda.png";
import LdaActive from "../../../static/sprite/Lda_active.png";
import LdaViewed from "../../../static/sprite/Lda_viewed.png";
import MULTI from "../../../static/sprite/MULTI.png";
import MULTIActive from "../../../static/sprite/MULTI_active.png";
import MULTIViewed from "../../../static/sprite/MULTI_viewed.png";
import Cou from "../../../static/sprites/nodes/Cou.png";
import CouActive from "../../../static/sprites/nodes/Cou_active.png";
import CouViewed from "../../../static/sprites/nodes/Cou_viewed.png";
import Dc from "../../../static/sprites/nodes/Dc.png";
import DcActive from "../../../static/sprites/nodes/Dc_active.png";
import DcViewed from "../../../static/sprites/nodes/Dc_viewed.png";
import Sskn from "../../../static/sprites/nodes/SSkn.png";
import SsknActive from "../../../static/sprites/nodes/SSkn_active.png";
import SsknViewed from "../../../static/sprites/nodes/SSkn_viewed.png";
import Tda from "../../../static/sprites/nodes/Tda.png";
import TdaActive from "../../../static/sprites/nodes/Tda_active.png";
import TdaViewed from "../../../static/sprites/nodes/Tda_viewed.png";
import Dia from "../../../static/sprites/nodes/Dia.png";
import DiaActive from "../../../static/sprites/nodes/Dia_active.png";
import DiaViewed from "../../../static/sprites/nodes/Dia_viewed.png";
import Lda from "../../../static/sprites/nodes/Lda.png";
import LdaActive from "../../../static/sprites/nodes/Lda_active.png";
import LdaViewed from "../../../static/sprites/nodes/Lda_viewed.png";
import MULTI from "../../../static/sprites/nodes/MULTI.png";
import MULTIActive from "../../../static/sprites/nodes/MULTI_active.png";
import MULTIViewed from "../../../static/sprites/nodes/MULTI_viewed.png";
import level_y_values from "../../../resources/level_y_values.json";
import { useStore } from "../../../store";

View file

@ -2,20 +2,20 @@ import React, { useEffect, useMemo, useRef } from "react";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import * as THREE from "three";
import { useFrame, useLoader } from "react-three-fiber";
import Cou from "../../../../../static/sprite/Cou.png";
import CouGold from "../../../../../static/sprite/Cou_gold.png";
import Dc from "../../../../../static/sprite/Dc.png";
import DcGold from "../../../../../static/sprite/Dc_gold.png";
import Sskn from "../../../../../static/sprite/SSkn.png";
import SsknGold from "../../../../../static/sprite/SSkn_gold.png";
import Tda from "../../../../../static/sprite/Tda.png";
import TdaGold from "../../../../../static/sprite/Tda_gold.png";
import Dia from "../../../../../static/sprite/Dia.png";
import DiaGold from "../../../../../static/sprite/Dia_gold.png";
import Lda from "../../../../../static/sprite/Lda.png";
import LdaGold from "../../../../../static/sprite/Lda_gold.png";
import MULTI from "../../../../../static/sprite/MULTI.png";
import MULTIGold from "../../../../../static/sprite/MULTI_gold.png";
import Cou from "../../../../../static/sprites/nodes/Cou.png";
import CouGold from "../../../../../static/sprites/nodes/Cou_gold.png";
import Dc from "../../../../../static/sprites/nodes/Dc.png";
import DcGold from "../../../../../static/sprites/nodes/Dc_gold.png";
import Sskn from "../../../../../static/sprites/nodes/SSkn.png";
import SsknGold from "../../../../../static/sprites/nodes/SSkn_gold.png";
import Tda from "../../../../../static/sprites/nodes/Tda.png";
import TdaGold from "../../../../../static/sprites/nodes/Tda_gold.png";
import Dia from "../../../../../static/sprites/nodes/Dia.png";
import DiaGold from "../../../../../static/sprites/nodes/Dia_gold.png";
import Lda from "../../../../../static/sprites/nodes/Lda.png";
import LdaGold from "../../../../../static/sprites/nodes/Lda_gold.png";
import MULTI from "../../../../../static/sprites/nodes/MULTI.png";
import MULTIGold from "../../../../../static/sprites/nodes/MULTI_gold.png";
import { useStore } from "../../../../../store";
type GLTFResult = GLTF & {
@ -35,9 +35,7 @@ type GoldNodeProps = {
const GoldNode = (props: GoldNodeProps) => {
const { nodes } = useLoader<GLTFResult>(GLTFLoader, "models/gold_node.glb");
const activeNodeName = useStore(
(state) => state.activeNode.node_name
);
const activeNodeName = useStore((state) => state.activeNode.node_name);
const tex = useMemo(() => {
if (activeNodeName.includes("S")) {

View file

@ -1,5 +1,5 @@
import React, { useEffect, useRef } from "react";
import MULTI from "../../../../../static/sprite/MULTI.png";
import MULTI from "../../../../../static/sprites/nodes/MULTI.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";

View file

@ -1,9 +1,9 @@
import React, { memo, useEffect, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import siteATex from "../../../static/sprite/site_a.png";
import siteBTex from "../../../static/sprite/site_b.png";
import siteLevelTex from "../../../static/sprite/site_levels.png";
import siteATex from "../../../static/sprites/main/site_a.png";
import siteBTex from "../../../static/sprites/main/site_b.png";
import siteLevelTex from "../../../static/sprites/main/site_levels.png";
type PurpleRingProps = {
purpleRingPosY: number;

View file

@ -8,38 +8,9 @@ import InactiveLevelNodes from "./InactiveLevelNodes";
import site_a from "../../../resources/site_a.json";
import site_b from "../../../resources/site_b.json";
import level_y_values from "../../../resources/level_y_values.json";
import { filterInvisibleNodes } from "../../../utils/node-utils";
import { filterInvisibleNodes } from "../../../helpers/node-helpers";
import Loading from "../../Loading";
export type NodeData = {
id: string;
image_table_indices: { 1: string; 2: string; 3: string };
triggers_final_video: number;
required_final_video_viewcount: number;
media_file: string;
node_name: string;
site: string;
type: number;
title: string;
unlocked_by: string;
upgrade_requirement: number;
words: { 1: string; 2: string; 3: string };
matrixIndices?: {
matrixIdx: number;
rowIdx: number;
colIdx: number;
};
is_viewed?: number;
};
export type Level = {
[key: string]: NodeData;
};
export type SiteData = {
[key: string]: Level;
};
type SiteProps = {
introFinished: boolean;
};
@ -96,7 +67,7 @@ const Site = (props: SiteProps) => {
);
return (
<Suspense fallback={<Loading />}>
<Suspense fallback={props.introFinished ? <Loading /> : null}>
<a.group rotation-x={rotXState.x}>
<a.group rotation-y={rotYState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />

View file

@ -0,0 +1,79 @@
import React, { useMemo, useRef } from "react";
import { a } from "@react-spring/three";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
type IntroStarProps = {
position: number[];
color: string;
};
const IntroStar = (props: IntroStarProps) => {
const uniforms = useMemo(
() => ({
color1: {
value: new THREE.Color("white"),
},
color2: {
value: new THREE.Color(props.color),
},
}),
[props.color]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
uniform float alpha;
varying vec2 vUv;
void main() {
float alpha = smoothstep(0.0, 1.0, vUv.y);
float colorMix = smoothstep(1.0, 2.0, 1.8);
gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.8;
}
`;
const starRef = useRef<THREE.Object3D>();
const amp = useRef(Math.random() / 10);
useFrame(() => {
if (starRef.current && starRef.current.visible) {
starRef.current.position.y += 0.25 + amp.current;
if (starRef.current.position.y > 40) starRef.current.visible = false;
}
});
return (
<mesh
position={props.position as [number, number, number]}
scale={[0.01, 2, 0.01]}
renderOrder={-1}
ref={starRef}
>
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
<a.shaderMaterial
attach="material"
fragmentShader={fragmentShader}
vertexShader={vertexShader}
transparent={true}
depthWrite={false}
uniforms={uniforms}
/>
</mesh>
);
};
export default IntroStar;

View file

@ -1,26 +1,27 @@
import React, { useRef } from "react";
import React, { useMemo, useRef } from "react";
import { a } from "@react-spring/three";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import lerp from "../../../utils/lerp";
type StarProps = {
position: number[];
color: string;
introStar?: boolean;
shouldIntro?: boolean;
shouldIntro: boolean;
};
const Star = (props: StarProps) => {
const uniformConstructor = (col: string) => {
return {
const uniforms = useMemo(
() => ({
color1: {
value: new THREE.Color("white"),
},
color2: {
value: new THREE.Color(col),
value: new THREE.Color(props.color),
},
};
};
}),
[props.color]
);
const vertexShader = `
varying vec2 vUv;
@ -54,17 +55,11 @@ const Star = (props: StarProps) => {
useFrame(() => {
if (starRef.current) {
if (props.introStar) {
starRef.current.position.y += 0.25 + amp.current;
} else {
if (starRef.current.position.y > 4) {
starRef.current.position.y = props.position[1];
}
starRef.current.position.y += 0.01 + amp.current + introAmpRef.current;
if (introAmpRef.current > 0) {
introAmpRef.current -= 0.004;
}
if (starRef.current.position.y > 4) {
starRef.current.position.y = props.position[1];
}
starRef.current.position.y += 0.01 + amp.current + introAmpRef.current;
introAmpRef.current = lerp(introAmpRef.current, 0, 0.01);
}
});
@ -82,7 +77,7 @@ const Star = (props: StarProps) => {
vertexShader={vertexShader}
transparent={true}
depthWrite={false}
uniforms={uniformConstructor(props.color)}
uniforms={uniforms}
/>
</mesh>
);

View file

@ -1,5 +1,6 @@
import React, { memo, useEffect, useMemo, useState } from "react";
import React, { memo, useMemo } from "react";
import Star from "./Star";
import IntroStar from "./IntroStar";
type StarfieldProps = {
shouldIntro: boolean;
@ -34,17 +35,11 @@ const Starfield = memo((props: StarfieldProps) => {
].map((x) =>
Array.from({ length: x }, () => [
lcgInstance() / 1000000050,
lcgInstance() / 100000099 - 15,
lcgInstance() / 100000059 + 5,
lcgInstance() / 1000000050,
])
);
const [introVisible, setIntroVisible] = useState(true);
useEffect(() => {
setTimeout(() => setIntroVisible(false), 3200);
}, []);
return (
<>
<group position={[0, -1, 2]} visible={props.mainVisible}>
@ -101,20 +96,18 @@ const Starfield = memo((props: StarfieldProps) => {
))}
</group>
</group>
{introVisible && props.shouldIntro ? (
{props.shouldIntro && (
<group position={[-2, -15, -30]} rotation={[Math.PI / 3, 0, 0]}>
{posesBlueFromBottom.map((poses, idx) => (
<Star position={poses} color={"blue"} key={idx} introStar={true} />
<IntroStar position={poses} color={"blue"} key={idx} />
))}
{posesWhiteFromBottom.map((poses, idx) => (
<Star position={poses} color={"white"} key={idx} introStar={true} />
<IntroStar position={poses} color={"white"} key={idx} />
))}
{posesCyanFromBottom.map((poses, idx) => (
<Star position={poses} color={"cyan"} key={idx} introStar={true} />
<IntroStar position={poses} color={"cyan"} key={idx} />
))}
</group>
) : (
<></>
)}
</>
);

View file

@ -1,7 +1,7 @@
import React, { memo, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import orbSprite from "../../static/sprite/orb.png";
import orbSprite from "../../static/sprites/main/orb.png";
import { useStore } from "../../store";
type YellowOrbProps = {

View file

@ -59,7 +59,7 @@ const MediaPlayer = () => {
return (
<>
<video width="800" height="600" id="media" ref={videoRef} controls>
<video width="800" height="600" id="media" ref={videoRef}>
<track id={"track"} ref={trackRef} kind="captions" default />
</video>
<div id={"subtitle-container"}>

View file

@ -1,6 +1,6 @@
import React, { MutableRefObject } from "react";
import audioVisualizerOrangeOrb from "../../../static/sprite/audio_visual_orb_orange.png";
import audioVisualizerYellowOrb from "../../../static/sprite/audio_visual_orb_yellow.png";
import audioVisualizerOrangeOrb from "../../../static/sprites/media/audio_visual_orb_orange.png";
import audioVisualizerYellowOrb from "../../../static/sprites/media/audio_visual_orb_yellow.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";

View file

@ -1,7 +1,7 @@
import React, { memo, useState } from "react";
import * as THREE from "three";
import { useFrame, useLoader } from "react-three-fiber";
import lofSpriteSheet from "../../static/sprite/lof_spritesheet.png";
import lofSpriteSheet from "../../static/sprites/media/lof_spritesheet.png";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
const Lof = memo(() => {

View file

@ -1,177 +0,0 @@
import React, { useMemo, useRef } from "react";
import { useStore } from "../../store";
import loadingBarContainer from "../../static/sprite/media_loading_bar_container.png";
import loadingBar from "../../static/sprite/media_loading_bar.png";
import loadingBar10Perc from "../../static/sprite/media_loading_bar_10perc.png";
import loadingBar20Perc from "../../static/sprite/media_loading_bar_20perc.png";
import loadingBar30Perc from "../../static/sprite/media_loading_bar_30perc.png";
import loadingBar40Perc from "../../static/sprite/media_loading_bar_40perc.png";
import loadingBar50Perc from "../../static/sprite/media_loading_bar_50perc.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
const MediaLoadingBar = () => {
const mediaPercentageElapsed = useStore(
(state) => state.mediaPercentageElapsed
);
const loadingBarContainerTex = useLoader(
THREE.TextureLoader,
loadingBarContainer
);
const loadingBarTex = useLoader(THREE.TextureLoader, loadingBar);
const loadingBar10PercTex = useLoader(THREE.TextureLoader, loadingBar10Perc);
const loadingBar20PercTex = useLoader(THREE.TextureLoader, loadingBar20Perc);
const loadingBar30PercTex = useLoader(THREE.TextureLoader, loadingBar30Perc);
const loadingBar40PercTex = useLoader(THREE.TextureLoader, loadingBar40Perc);
const loadingBar50PercTex = useLoader(THREE.TextureLoader, loadingBar50Perc);
// the additions here are very linear, but just +ing the values wouldn't work
// since in case the video were to get rewinded the bar wouldn't react properly
// doing it declaratively like this fixes that concern
const loadingBarState = useMemo(() => {
const mediaPercentageDispatch = {
0: {
scaleX: 0,
texture: loadingBar10PercTex,
offsetX: 0,
},
5: {
scaleX: 0.25,
texture: loadingBar10PercTex,
offsetX: 0,
},
10: { scaleX: 0.5, texture: loadingBar20PercTex, offsetX: 0.145 },
15: { scaleX: 0.75, texture: loadingBar30PercTex, offsetX: 0.25 },
20: {
scaleX: 1,
texture: loadingBar40PercTex,
offsetX: 0.4,
},
25: {
scaleX: 1.25,
texture: loadingBar50PercTex,
offsetX: 0.55,
},
30: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 0.8,
},
35: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 1.05,
},
40: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 1.3,
},
45: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 1.55,
},
50: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 1.8,
},
55: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 2.05,
},
60: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 2.3,
},
65: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 2.55,
},
70: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 2.8,
},
75: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.05,
},
80: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.3,
},
85: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.55,
},
90: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.65,
},
95: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.85,
},
100: {
scaleX: 1.5,
texture: loadingBarTex,
offsetX: 3.95,
},
};
return mediaPercentageDispatch[
mediaPercentageElapsed as keyof typeof mediaPercentageDispatch
];
}, [
loadingBar10PercTex,
loadingBar20PercTex,
loadingBar30PercTex,
loadingBar40PercTex,
loadingBar50PercTex,
loadingBarTex,
mediaPercentageElapsed,
]);
const loadingBarMatRef = useRef<THREE.Material>();
useFrame(() => {
if (loadingBarMatRef) {
loadingBarMatRef.current!.needsUpdate = true;
}
});
return (
<>
<sprite scale={[5.2, 0.5, 1]} position={[2.15, 3.005, 0]}>
<spriteMaterial attach="material" map={loadingBarContainerTex} />
</sprite>
<mesh
scale={[loadingBarState ? loadingBarState.scaleX : 0, 0.195, 1]}
position={[
loadingBarState ? -0.2 + loadingBarState.offsetX : -0.2,
2.945,
0,
]}
>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
ref={loadingBarMatRef}
attach="material"
transparent={true}
map={loadingBarState ? loadingBarState.texture : null}
/>
</mesh>
</>
);
};
export default MediaLoadingBar;

View file

@ -0,0 +1,177 @@
import React, { useMemo, useRef } from "react";
import { useStore } from "../../store";
import progressBarContainer from "../../static/sprites/media/media_loading_bar_container.png";
import progressBar from "../../static/sprites/progressbar/progress_bar0.png";
import progressBar1 from "../../static/sprites/progressbar/progress_bar1.png";
import progressBar2 from "../../static/sprites/progressbar/progress_bar2.png";
import progressBar3 from "../../static/sprites/progressbar/progress_bar3.png";
import progressBar4 from "../../static/sprites/progressbar/progress_bar4.png";
import progressBar5 from "../../static/sprites/progressbar/progress_bar5.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
const MediaProgressBar = () => {
const mediaPercentageElapsed = useStore(
(state) => state.mediaPercentageElapsed
);
const progressBarContainerTex = useLoader(
THREE.TextureLoader,
progressBarContainer
);
const progressBarTex = useLoader(THREE.TextureLoader, progressBar);
const progressBar1Tex = useLoader(THREE.TextureLoader, progressBar1);
const progressBar2Tex = useLoader(THREE.TextureLoader, progressBar2);
const progressBar3Tex = useLoader(THREE.TextureLoader, progressBar3);
const progressBar4Tex = useLoader(THREE.TextureLoader, progressBar4);
const progressBar5Tex = useLoader(THREE.TextureLoader, progressBar5);
// the additions here are very linear, but just +ing the values wouldn't work
// since in case the video were to get rewinded the bar wouldn't react properly
// doing it declaratively like this fixes that concern
const progressBarState = useMemo(() => {
const mediaPercentageDispatch = {
0: {
scaleX: 0,
texture: progressBar1Tex,
offsetX: 0,
},
5: {
scaleX: 0.25,
texture: progressBar1Tex,
offsetX: 0,
},
10: { scaleX: 0.5, texture: progressBar2Tex, offsetX: 0.145 },
15: { scaleX: 0.75, texture: progressBar3Tex, offsetX: 0.25 },
20: {
scaleX: 1,
texture: progressBar4Tex,
offsetX: 0.4,
},
25: {
scaleX: 1.25,
texture: progressBar5Tex,
offsetX: 0.55,
},
30: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 0.8,
},
35: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.05,
},
40: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.3,
},
45: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.55,
},
50: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.8,
},
55: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.05,
},
60: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.3,
},
65: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.55,
},
70: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.8,
},
75: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.05,
},
80: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.3,
},
85: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.55,
},
90: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.65,
},
95: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.85,
},
100: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.95,
},
};
return mediaPercentageDispatch[
mediaPercentageElapsed as keyof typeof mediaPercentageDispatch
];
}, [
progressBar1Tex,
progressBar2Tex,
progressBar3Tex,
progressBar4Tex,
progressBar5Tex,
progressBarTex,
mediaPercentageElapsed,
]);
const progressBarMatRef = useRef<THREE.Material>();
useFrame(() => {
if (progressBarMatRef) {
progressBarMatRef.current!.needsUpdate = true;
}
});
return (
<>
<sprite scale={[5.2, 0.5, 1]} position={[2.15, 3.005, 0]}>
<spriteMaterial attach="material" map={progressBarContainerTex} />
</sprite>
<mesh
scale={[progressBarState ? progressBarState.scaleX : 0, 0.195, 1]}
position={[
progressBarState ? -0.2 + progressBarState.offsetX : -0.2,
2.945,
0,
]}
>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
ref={progressBarMatRef}
attach="material"
transparent={true}
map={progressBarState ? progressBarState.texture : null}
/>
</mesh>
</>
);
};
export default MediaProgressBar;

View file

@ -1,7 +1,7 @@
import React from "react";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import mediaNodeNameContainer from "../../static/sprite/media_node_name_container.png";
import mediaNodeNameContainer from "../../static/sprites/media/media_node_name_container.png";
const NodeNameContainer = () => {
const mediaNodeNameContainerTex = useLoader(

View file

@ -1,7 +1,7 @@
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import grayTextureFile from "../../../../static/sprite/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprite/dark_gray_box.png";
import grayTextureFile from "../../../../static/sprites/media/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprites/media/dark_gray_box.png";
import React, {memo, useRef} from "react";
import { ShapeProps } from "../LeftSide";

View file

@ -1,7 +1,7 @@
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import grayTextureFile from "../../../../static/sprite/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprite/dark_gray_box.png";
import grayTextureFile from "../../../../static/sprites/media/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprites/media/dark_gray_box.png";
import React, { memo, useRef } from "react";
import { ShapeProps } from "../LeftSide";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

View file

@ -1,7 +1,7 @@
import React, { useMemo } from "react";
import * as THREE from "three";
import wordInactiveTexture from "../../../../static/sprite/word_background.png";
import wordActiveTexture from "../../../../static/sprite/word_background_active.png";
import wordInactiveTexture from "../../../../static/sprites/media/word_background.png";
import wordActiveTexture from "../../../../static/sprites/media/word_background_active.png";
import { useLoader } from "react-three-fiber";
import { a, SpringValue } from "@react-spring/three";
@ -13,7 +13,7 @@ type WordProps = {
};
const Word = (props: WordProps) => {
const wordFont = useLoader(THREE.FontLoader, "/3d_fonts/MediaWord.blob");
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,

View file

@ -1,12 +1,12 @@
import React, { useEffect, useMemo, useRef } from "react";
import header from "../../static/sprite/polytan_header.png";
import background from "../../static/sprite/polytan_background.png";
import leftArmHud from "../../static/sprite/poly_larm_hud.png";
import rightArmHud from "../../static/sprite/poly_rarm_hud.png";
import rightLegHud from "../../static/sprite/poly_rleg_hud.png";
import leftLegHud from "../../static/sprite/poly_lleg_hud.png";
import headHud from "../../static/sprite/poly_head_hud.png";
import bodyHud from "../../static/sprite/poly_body_hud.png";
import header from "../../static/sprites/polytan/polytan_header.png";
import background from "../../static/sprites/polytan/polytan_background.png";
import leftArmHud from "../../static/sprites/polytan/poly_larm_hud.png";
import rightArmHud from "../../static/sprites/polytan/poly_rarm_hud.png";
import rightLegHud from "../../static/sprites/polytan/poly_rleg_hud.png";
import leftLegHud from "../../static/sprites/polytan/poly_lleg_hud.png";
import headHud from "../../static/sprites/polytan/poly_head_hud.png";
import bodyHud from "../../static/sprites/polytan/poly_body_hud.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
@ -21,7 +21,7 @@ const PolytanBackground = () => {
const headHudTex = useLoader(THREE.TextureLoader, headHud);
const bodyHudTex = useLoader(THREE.TextureLoader, bodyHud);
const wordFont = useLoader(THREE.FontLoader, "/3d_fonts/MediaWord.blob");
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({

View file

@ -1,26 +1,16 @@
import React from "react";
import body from "../../static/sprite/body.png";
import head from "../../static/sprite/head.png";
import leftLeg from "../../static/sprite/left_leg.png";
import leftArm from "../../static/sprite/left_arm.png";
import rightArm from "../../static/sprite/right_arm.png";
import rightLeg from "../../static/sprite/right_leg.png";
import skeleton from "../../static/sprite/polytan_skeleton.png";
import React, { memo } from "react";
import body from "../../static/sprites/polytan/body.png";
import head from "../../static/sprites/polytan/head.png";
import leftLeg from "../../static/sprites/polytan/left_leg.png";
import leftArm from "../../static/sprites/polytan/left_arm.png";
import rightArm from "../../static/sprites/polytan/right_arm.png";
import rightLeg from "../../static/sprites/polytan/right_leg.png";
import skeleton from "../../static/sprites/polytan/polytan_skeleton.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../store";
type PolytanBearProps = {
unlockedParts: {
body: boolean;
head: boolean;
leftArm: boolean;
rightArm: boolean;
leftLeg: boolean;
rightLeg: boolean;
};
};
const PolytanBear = (props: PolytanBearProps) => {
const PolytanBear = memo(() => {
const skeletonTex = useLoader(THREE.TextureLoader, skeleton);
const headTex = useLoader(THREE.TextureLoader, head);
const bodyTex = useLoader(THREE.TextureLoader, body);
@ -29,6 +19,8 @@ const PolytanBear = (props: PolytanBearProps) => {
const rightArmTex = useLoader(THREE.TextureLoader, rightArm);
const rightLegTex = useLoader(THREE.TextureLoader, rightLeg);
const unlockedParts = useStore((state) => state.polytanUnlockedParts);
return (
<>
<sprite scale={[4, 5, 0]} position={[0, -0.4, 0]}>
@ -39,7 +31,7 @@ const PolytanBear = (props: PolytanBearProps) => {
<spriteMaterial
attach="material"
map={bodyTex}
visible={props.unlockedParts.body}
visible={unlockedParts.body}
/>
</sprite>
@ -47,39 +39,39 @@ const PolytanBear = (props: PolytanBearProps) => {
<spriteMaterial
attach="material"
map={headTex}
visible={props.unlockedParts.head}
visible={unlockedParts.head}
/>
</sprite>
<sprite scale={[1.9, 1, 0]} position={[1, -2.2, 0]}>
<spriteMaterial
attach="material"
map={leftLegTex}
visible={props.unlockedParts.leftLeg}
visible={unlockedParts.leftLeg}
/>
</sprite>
<sprite scale={[1.5, 1.9, 0]} position={[1.2, -0.4, 0]}>
<spriteMaterial
attach="material"
map={leftArmTex}
visible={props.unlockedParts.leftArm}
visible={unlockedParts.leftArm}
/>
</sprite>
<sprite scale={[1.6, 2, 0]} position={[-1.2, -1.2, 0]}>
<spriteMaterial
attach="material"
map={rightArmTex}
visible={props.unlockedParts.rightArm}
visible={unlockedParts.rightArm}
/>
</sprite>
<sprite scale={[1.9, 1, 0]} position={[-1, -2.2, 0]}>
<spriteMaterial
attach="material"
map={rightLegTex}
visible={props.unlockedParts.rightLeg}
visible={unlockedParts.rightLeg}
/>
</sprite>
</>
);
};
});
export default PolytanBear;

View file

@ -1,35 +1,35 @@
import introSpriteSheet from "../static/sprite/intro.png";
import moveDownSpriteSheet from "../static/sprite/jump_down.png";
import moveUpSpriteSheet from "../static/sprite/jump_up.png";
import standingSpriteSheet from "../static/sprite/standing.png";
import moveLeftSpriteSheet from "../static/sprite/move_left.png";
import moveRightSpriteSheet from "../static/sprite/move_right.png";
import bigHudSpriteSheet from "../static/sprite/big_hud.png";
import longHudSpriteSheet from "../static/sprite/long_hud.png";
import boringHudSpriteSheet from "../static/sprite/long_hud_boring.png";
import throwNodeSpriteSheet from "../static/sprite/throw_node.png";
import ripMiddleRingSpriteSheet from "../static/sprite/rip_middle_ring.png";
import ripNodeSpriteSheet from "../static/sprite/rip_node.png";
import prayerSpriteSheet from "../static/sprite/prayer.png";
import knockSpriteSheet from "../static/sprite/knock.png";
import knockAndFallSpriteSheet from "../static/sprite/knock_and_fall.png";
import touchAndScareSpriteSheet from "../static/sprite/touch_node_and_get_scared.png";
import touchSleeveSpriteSheet from "../static/sprite/touch_sleeve.png";
import thinkingSpriteSheet from "../static/sprite/thinking.png";
import stretchSpriteSheet from "../static/sprite/stretch.png";
import stretch2SpriteSheet from "../static/sprite/stretch_2.png";
import spinSpriteSheet from "../static/sprite/spin.png";
import scratchHeadSpriteSheet from "../static/sprite/scratch_head.png";
import blushSpriteSheet from "../static/sprite/blush.png";
import handsBehindHeadSpriteSheet from "../static/sprite/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../static/sprite/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../static/sprite/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../static/sprite/hands_together.png";
import leanForwardSpriteSheet from "../static/sprite/lean_forward.png";
import leanLeftSpriteSheet from "../static/sprite/lean_left.png";
import leanRightSpriteSheet from "../static/sprite/lean_right.png";
import lookAroundSpriteSheet from "../static/sprite/look_around.png";
import playWithHairSpriteSheet from "../static/sprite/play_with_hair.png";
import introSpriteSheet from "../static/sprites/lain/intro.png";
import moveDownSpriteSheet from "../static/sprites/lain/jump_down.png";
import moveUpSpriteSheet from "../static/sprites/lain/jump_up.png";
import standingSpriteSheet from "../static/sprites/lain/standing.png";
import moveLeftSpriteSheet from "../static/sprites/lain/move_left.png";
import moveRightSpriteSheet from "../static/sprites/lain/move_right.png";
import bigHudSpriteSheet from "../static/sprites/big_hud.png";
import longHudSpriteSheet from "../static/sprites/long_hud.png";
import boringHudSpriteSheet from "../static/sprites/long_hud_boring.png";
import throwNodeSpriteSheet from "../static/sprites/lain/throw_node.png";
import ripMiddleRingSpriteSheet from "../static/sprites/lain/rip_middle_ring.png";
import ripNodeSpriteSheet from "../static/sprites/lain/rip_node.png";
import prayerSpriteSheet from "../static/sprites/lain/prayer.png";
import knockSpriteSheet from "../static/sprites/lain/knock.png";
import knockAndFallSpriteSheet from "../static/sprites/lain/knock_and_fall.png";
import touchAndScareSpriteSheet from "../static/sprites/lain/touch_node_and_get_scared.png";
import touchSleeveSpriteSheet from "../static/sprites/lain/touch_sleeve.png";
import thinkingSpriteSheet from "../static/sprites/lain/thinking.png";
import stretchSpriteSheet from "../static/sprites/lain/stretch.png";
import stretch2SpriteSheet from "../static/sprites/lain/stretch_2.png";
import spinSpriteSheet from "../static/sprites/lain/spin.png";
import scratchHeadSpriteSheet from "../static/sprites/lain/scratch_head.png";
import blushSpriteSheet from "../static/sprites/lain/blush.png";
import handsBehindHeadSpriteSheet from "../static/sprites/lain/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../static/sprites/lain/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../static/sprites/lain/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../static/sprites/lain/hands_together.png";
import leanForwardSpriteSheet from "../static/sprites/lain/lean_forward.png";
import leanLeftSpriteSheet from "../static/sprites/lain/lean_left.png";
import leanRightSpriteSheet from "../static/sprites/lain/lean_right.png";
import lookAroundSpriteSheet from "../static/sprites/lain/look_around.png";
import playWithHairSpriteSheet from "../static/sprites/lain/play_with_hair.png";
import * as THREE from "three";
import { useLoader, useThree } from "react-three-fiber";

View file

@ -1,9 +1,9 @@
import React, { memo } from "react";
import answerContainer from "../static/sprite/prompt_answer_container.png";
import questionContainer from "../static/sprite/prompt_question_container.png";
import yes from "../static/sprite/prompt_yes.png";
import no from "../static/sprite/prompt_no.png";
import question from "../static/sprite/prompt_question.png";
import answerContainer from "../static/sprites/prompt/prompt_answer_container.png";
import questionContainer from "../static/sprites/prompt/prompt_question_container.png";
import yes from "../static/sprites/prompt/prompt_yes.png";
import no from "../static/sprites/prompt/prompt_no.png";
import question from "../static/sprites/prompt/prompt_question.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";

View file

@ -1,10 +1,10 @@
import React, { memo } from "react";
import ssknBackground from "../../static/sprite/sskn_background.png";
import ssknBackgroundText from "../../static/sprite/sskn_background_text.png";
import ssknBackground from "../../static/sprites/sskn/sskn_background.png";
import ssknBackgroundText from "../../static/sprites/sskn/sskn_background_text.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import ssknTopLabel from "../../static/sprite/sskn_top_label.png";
import ssknDango from "../../static/sprite/sskn_dango.png";
import ssknTopLabel from "../../static/sprites/sskn/sskn_top_label.png";
import ssknDango from "../../static/sprites/sskn/sskn_dango.png";
const SsknBackground = memo(() => {
const ssknBackgroundTex = useLoader(THREE.TextureLoader, ssknBackground);

View file

@ -1,16 +1,16 @@
import React, { memo } from "react";
import ssknOk from "../../static/sprite/sskn_ok.png";
import ssknOkInactive from "../../static/sprite/sskn_ok_inactive.png";
import ssknCancel from "../../static/sprite/sskn_cancel.png";
import ssknCancelInactive from "../../static/sprite/sskn_cancel_inactive.png";
import ssknUpgrade from "../../static/sprite/sskn_upgrade.png";
import ssknArrow from "../../static/sprite/sskn_arrow.png";
import ssknTextWrapper from "../../static/sprite/sskn_text_wrapper.png";
import ssknTextWrapperInactive from "../../static/sprite/sskn_text_wrapper_inactive.png";
import ssknLine from "../../static/sprite/sskn_line.png";
import ssknOk from "../../static/sprites/sskn/sskn_ok.png";
import ssknOkInactive from "../../static/sprites/sskn/sskn_ok_inactive.png";
import ssknCancel from "../../static/sprites/sskn/sskn_cancel.png";
import ssknCancelInactive from "../../static/sprites/sskn/sskn_cancel_inactive.png";
import ssknUpgrade from "../../static/sprites/sskn/sskn_upgrade.png";
import ssknArrow from "../../static/sprites/sskn/sskn_arrow.png";
import ssknTextWrapper from "../../static/sprites/sskn/sskn_text_wrapper.png";
import ssknTextWrapperInactive from "../../static/sprites/sskn/sskn_text_wrapper_inactive.png";
import ssknLine from "../../static/sprites/sskn/sskn_line.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import SsknLoadingBar from "./SsknLoadingBar";
import SsknProgressBar from "./SsknProgressBar";
import { useStore } from "../../store";
const SsknHUD = memo(() => {
@ -37,7 +37,7 @@ const SsknHUD = memo(() => {
return (
<>
{loading ? (
<SsknLoadingBar />
<SsknProgressBar />
) : (
<group>
<sprite position={[2.8, -2, 0]} scale={[1, 0.5, 0]}>

View file

@ -1,5 +1,5 @@
import React, { memo, useRef } from "react";
import ssknIcon from "../../static/sprite/SSkn_icon.png";
import ssknIcon from "../../static/sprites/sskn/SSkn_icon.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";

View file

@ -1,95 +0,0 @@
import React, { useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import ssknLoadingBarContainer from "../../static/sprite/SSkn_loading_bar.png";
import loadingBar10Perc from "../../static/sprite/media_loading_bar_10perc.png";
import loadingBar20Perc from "../../static/sprite/media_loading_bar_20perc.png";
import loadingBar30Perc from "../../static/sprite/media_loading_bar_30perc.png";
import loadingBar40Perc from "../../static/sprite/media_loading_bar_40perc.png";
import loadingBar50Perc from "../../static/sprite/media_loading_bar_50perc.png";
import loadingBar from "../../static/sprite/media_loading_bar.png";
const SsknLoadingBar = () => {
const ssknLoadingBarContainerTex = useLoader(
THREE.TextureLoader,
ssknLoadingBarContainer
);
const loadingBarTex = useLoader(THREE.TextureLoader, loadingBar);
const loadingBar10PercTex = useLoader(THREE.TextureLoader, loadingBar10Perc);
const loadingBar20PercTex = useLoader(THREE.TextureLoader, loadingBar20Perc);
const loadingBar30PercTex = useLoader(THREE.TextureLoader, loadingBar30Perc);
const loadingBar40PercTex = useLoader(THREE.TextureLoader, loadingBar40Perc);
const loadingBar50PercTex = useLoader(THREE.TextureLoader, loadingBar50Perc);
const loadingBarRef = useRef<THREE.Object3D>();
const loadingBarMatRef = useRef<THREE.SpriteMaterial>();
const percentageElapsed = useRef(0);
const last = useRef(0);
useFrame(() => {
const now = Date.now();
if (
now > last.current + 200 &&
loadingBarRef.current &&
loadingBarMatRef.current
) {
percentageElapsed.current += 5;
switch (percentageElapsed.current) {
case 5:
loadingBarRef.current.scale.x = 0.25;
loadingBarMatRef.current.map = loadingBar10PercTex;
break;
case 10:
loadingBarRef.current.scale.x += 0.25;
loadingBarRef.current.position.x += 0.1;
loadingBarMatRef.current.map = loadingBar20PercTex;
break;
case 15:
loadingBarRef.current.scale.x += 0.25;
loadingBarRef.current.position.x += 0.1;
loadingBarMatRef.current.map = loadingBar30PercTex;
break;
case 20:
loadingBarRef.current.scale.x += 0.25;
loadingBarRef.current.position.x += 0.1;
loadingBarMatRef.current.map = loadingBar40PercTex;
break;
case 25:
loadingBarRef.current.scale.x += 0.25;
loadingBarRef.current.position.x += 0.1;
loadingBarMatRef.current.map = loadingBar50PercTex;
break;
default:
if (loadingBarRef.current.position.x < 4.1) {
loadingBarMatRef.current.map = loadingBarTex;
loadingBarRef.current.position.x += 0.2;
}
}
last.current = now;
}
});
return (
<>
<sprite scale={[5.5, 0.3, 0]} position={[2, -2.7, 0]} renderOrder={4}>
<spriteMaterial attach="material" map={ssknLoadingBarContainerTex} />
</sprite>
<sprite
scale={[0.2, 0.15, 0]}
position={[-0.5, -2.68, 0]}
renderOrder={4}
ref={loadingBarRef}
>
<spriteMaterial
attach="material"
ref={loadingBarMatRef}
map={loadingBar10PercTex}
opacity={0.8}
/>
</sprite>
</>
);
};
export default SsknLoadingBar;

View file

@ -0,0 +1,95 @@
import React, { useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import ssknProgressBarContainer from "../../static/sprites/sskn/sskn_progress_bar.png";
import progressBar1 from "../../static/sprites/progressbar/progress_bar1.png";
import progressBar2 from "../../static/sprites/progressbar/progress_bar2.png";
import progressBar3 from "../../static/sprites/progressbar/progress_bar3.png";
import progressBar4 from "../../static/sprites/progressbar/progress_bar4.png";
import progressBar5 from "../../static/sprites/progressbar/progress_bar5.png";
import progressBar from "../../static/sprites/progressbar/progress_bar0.png";
const SsknProgressBar = () => {
const ssknProgressBarContainerTex = useLoader(
THREE.TextureLoader,
ssknProgressBarContainer
);
const progressBarTex = useLoader(THREE.TextureLoader, progressBar);
const progressBar1Tex = useLoader(THREE.TextureLoader, progressBar1);
const progressBar2Tex = useLoader(THREE.TextureLoader, progressBar2);
const progressBar3Tex = useLoader(THREE.TextureLoader, progressBar3);
const progressBar4Tex = useLoader(THREE.TextureLoader, progressBar4);
const progressBar5Tex = useLoader(THREE.TextureLoader, progressBar5);
const progressBarRef = useRef<THREE.Object3D>();
const progressBarMatRef = useRef<THREE.SpriteMaterial>();
const percentageElapsed = useRef(0);
const last = useRef(0);
useFrame(() => {
const now = Date.now();
if (
now > last.current + 200 &&
progressBarRef.current &&
progressBarMatRef.current
) {
percentageElapsed.current += 5;
switch (percentageElapsed.current) {
case 5:
progressBarRef.current.scale.x = 0.25;
progressBarMatRef.current.map = progressBar1Tex;
break;
case 10:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar2Tex;
break;
case 15:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar3Tex;
break;
case 20:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar4Tex;
break;
case 25:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar5Tex;
break;
default:
if (progressBarRef.current.position.x < 4.1) {
progressBarMatRef.current.map = progressBarTex;
progressBarRef.current.position.x += 0.2;
}
}
last.current = now;
}
});
return (
<>
<sprite scale={[5.5, 0.3, 0]} position={[2, -2.7, 0]} renderOrder={4}>
<spriteMaterial attach="material" map={ssknProgressBarContainerTex} />
</sprite>
<sprite
scale={[0.2, 0.15, 0]}
position={[-0.5, -2.68, 0]}
renderOrder={4}
ref={progressBarRef}
>
<spriteMaterial
attach="material"
ref={progressBarMatRef}
map={progressBar1Tex}
opacity={0.8}
/>
</sprite>
</>
);
};
export default SsknProgressBar;

View file

@ -1,14 +1,14 @@
import React from "react";
import statusContainer from "../static/sprite/status_container.png";
import loadSuccessfulImg from "../static/sprite/load_successful.png";
import loadFailImg from "../static/sprite/load_fail.png";
import saveSuccessfulImg from "../static/sprite/save_successful.png";
import React, { memo } from "react";
import statusContainer from "../static/sprites/status/status_container.png";
import loadSuccessfulImg from "../static/sprites/status/load_successful.png";
import loadFailImg from "../static/sprites/status/load_fail.png";
import saveSuccessfulImg from "../static/sprites/status/save_successful.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";
const Status = () => {
const Status = memo(() => {
const loadSuccessful = useStore((state) => state.loadSuccessful);
const saveSuccessful = useStore((state) => state.saveSuccessful);
@ -62,6 +62,6 @@ const Status = () => {
</sprite>
</group>
);
};
});
export default Status;

View file

@ -1,5 +1,5 @@
import orangeFont from "../../static/sprite/orange_font_texture.png";
import yellowFont from "../../static/sprite/yellow_font_texture.png";
import orangeFont from "../../static/sprites/fonts/orange_font_texture.png";
import yellowFont from "../../static/sprites/fonts/yellow_font_texture.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import orange_font_json from "../../resources/font_data/big_font.json";
@ -80,7 +80,7 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ scene, subscene });
const prevData = usePrevious({ scene, subscene, activeNode });
const [lastMediaLeftComponent, setLastMediaLeftComponent] = useState("play");
const [shrinkState, set] = useSpring(() => ({
@ -91,8 +91,13 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
useEffect(() => {
if (
subscene === "pause" ||
(subscene === "site" && prevData?.subscene === "not_found") ||
(subscene === "site" && prevData?.subscene === "pause")
(subscene === "site" && prevData?.subscene === "pause") ||
(activeNode === prevData?.activeNode &&
!(
subscene === "level_selection" ||
color === "orange" ||
scene === "media"
))
)
return;
if (scene === "main" && prevData?.scene === "main") {
@ -124,6 +129,7 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
lastMediaLeftComponent,
prevData?.scene,
prevData?.subscene,
prevData?.activeNode,
]);
return (

View file

@ -1,6 +1,6 @@
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import greenFont from "../../static/sprite/white_and_green_texture.png";
import greenFont from "../../static/sprites/fonts/white_and_green_texture.png";
import medium_font_json from "../../resources/font_data/medium_font.json";
import { a } from "@react-spring/three";
import React, { memo, useMemo } from "react";

View file

@ -3,7 +3,7 @@ import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import BigLetter from "./BigLetter";
import usePrevious from "../../hooks/usePrevious";
import { getNodeHud } from "../../utils/node-utils";
import { getNodeHud } from "../../helpers/node-helpers";
const MainYellowTextAnimator = (props: { visible?: boolean }) => {
const activeNode = useStore((state) => state.activeNode);

View file

@ -1,41 +1,27 @@
import orangeFont from "../../static/sprite/orange_font_texture.png";
import yellowFont from "../../static/sprite/yellow_font_texture.png";
import whiteFont from "../../static/sprite/white_and_green_texture.png";
import orangeFont from "../../static/sprites/fonts/orange_font_texture.png";
import yellowFont from "../../static/sprites/fonts/yellow_font_texture.png";
import whiteFont from "../../static/sprites/fonts/white_and_green_texture.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import orange_font_json from "../../resources/font_data/big_font.json";
import { a, useSpring } from "@react-spring/three";
import React, { useMemo, memo } from "react";
import { useStore } from "../../store";
const PauseBigLetter = memo(
(props: {
color: string;
letter: string;
letterIdx: number;
position: number[];
scale: number[];
active?: boolean;
rowIdx?: number;
colIdx?: number;
intro?: boolean;
mainLetter?: boolean;
active?: boolean;
introFinished?: boolean;
exit?: boolean;
}) => {
const exitAnimation = useStore(
(state) => state.pauseExitAnimation
);
const tex = useMemo(() => {
switch (props.color) {
case "white":
return whiteFont;
case "yellow":
return yellowFont;
default:
return orangeFont;
}
}, [props.color]);
const colorTexture: THREE.Texture = useLoader(THREE.TextureLoader, tex);
const whiteFontTex = useLoader(THREE.TextureLoader, whiteFont);
const orangeFontTex = useLoader(THREE.TextureLoader, orangeFont);
const yellowFontTex = useLoader(THREE.TextureLoader, yellowFont);
const lineYOffset = useMemo(() => {
const lineOne = "ABCDEFGHIJKLMNOPQ";
@ -93,64 +79,133 @@ const PauseBigLetter = memo(
return geometry;
}, [letterData, lineYOffset]);
const exitAnimValue = useMemo(() => {
let col = 0;
let row = 0;
if (props.colIdx && props.rowIdx) {
if (props.colIdx < 3) col = -1;
else if (props.colIdx > 3) col = 1;
if (props.rowIdx < 3) row = -1;
else if (props.rowIdx > 3) row = 1;
return { row, col };
}
}, [props.colIdx, props.rowIdx]);
const initialState = useSpring({
posX:
props.position[0] +
(exitAnimValue ? exitAnimValue.col * (exitAnimation ? 2.2 : 0) : 0),
posY:
-letterData[4] / 50 +
props.position[1] +
(exitAnimValue ? exitAnimValue.row * (exitAnimation ? 2.2 : 0) : 0),
rotX: props.active ? (exitAnimation ? Math.PI / 2 : 0) : -Math.PI,
rotY: props.active ? (exitAnimation ? Math.PI / 2 : 0) : Math.PI / 2,
const mainLetterIntroSpring = useSpring({
from: {
rotX: Math.PI,
rotY: Math.PI / 2,
},
to: { rotY: 0, rotX: 0 },
delay: (props.rowIdx! + props.colIdx!) * 100 + 500,
config: { duration: 500 },
});
const introState = useSpring({
rotX: 0,
rotY: 0,
from: { rotX: Math.PI, rotY: Math.PI * 2 },
delay: (props.rowIdx! + props.colIdx!) * 100 + 500,
config: { duration: 200 },
const exitAnimValue = useMemo(() => {
let col, row;
if (props.colIdx! < 3) col = -1;
else if (props.colIdx! > 3) col = 1;
else col = 0;
if (props.rowIdx! < 3) row = -1;
else if (props.rowIdx! > 3) row = 1;
else row = 0;
return { row: row * 2.2, col: col * 2.2 };
}, [props.colIdx, props.rowIdx]);
const mainLetterSpring = useSpring({
orangeRotY: props.active ? 0 : Math.PI / 2,
orangeRotX: props.active ? 0 : Math.PI,
whiteRotY: props.active || props.exit ? Math.PI / 2 : 0,
whiteRotX: props.active || props.exit ? Math.PI : 0,
posX: props.colIdx
? props.colIdx / 2.8 + (props.exit ? exitAnimValue.col : 0)
: props.position[0],
posY: props.rowIdx
? props.rowIdx / 2.8 + (props.exit ? exitAnimValue.row : 0)
: -letterData[4] / 50 + props.position[1],
config: { duration: 500 },
});
const nonMainLetterSpring = useSpring({
rotY: props.active ? 0 : Math.PI / 2,
rotX: props.active ? 0 : Math.PI,
config: { duration: 500 },
});
return (
<a.mesh
position={[
props.position[0],
-letterData[4] / 50 + props.position[1],
props.position[2],
]}
position-x={initialState.posX}
position-y={initialState.posY}
scale={props.scale as [number, number, number]}
geometry={geom}
rotation-x={props.intro ? introState.rotX : initialState.rotX}
rotation-y={props.intro ? introState.rotY : initialState.rotY}
renderOrder={100}
>
<meshBasicMaterial
map={colorTexture}
attach="material"
transparent={true}
side={THREE.FrontSide}
depthTest={false}
/>
</a.mesh>
<>
{props.mainLetter ? (
<>
<a.mesh
position={[
props.position[0],
-letterData[4] / 50 + props.position[1],
props.position[2],
]}
scale={[0.25, 0.25, 0]}
geometry={geom}
rotation-x={
props.introFinished
? mainLetterSpring.orangeRotX
: mainLetterIntroSpring.rotX
}
rotation-y={
props.introFinished
? mainLetterSpring.orangeRotY
: mainLetterIntroSpring.rotY
}
position-x={mainLetterSpring.posX}
position-y={mainLetterSpring.posY}
renderOrder={100}
>
<meshBasicMaterial
map={props.introFinished ? orangeFontTex : whiteFontTex}
attach="material"
transparent={true}
side={THREE.FrontSide}
depthTest={false}
/>
</a.mesh>
<a.mesh
position={[
props.position[0],
-letterData[4] / 50 + props.position[1],
props.position[2],
]}
scale={[0.25, 0.25, 0]}
geometry={geom}
position-x={mainLetterSpring.posX}
position-y={mainLetterSpring.posY}
rotation-x={
props.introFinished ? mainLetterSpring.whiteRotX : Math.PI
}
rotation-y={
props.introFinished ? mainLetterSpring.whiteRotY : Math.PI / 2
}
renderOrder={100}
>
<meshBasicMaterial
map={whiteFontTex}
attach="material"
transparent={true}
side={THREE.FrontSide}
depthTest={false}
/>
</a.mesh>
</>
) : (
<a.mesh
position={[
props.position[0],
-letterData[4] / 50 + props.position[1],
props.position[2],
]}
scale={[0.25, 0.25, 0]}
geometry={geom}
rotation-x={nonMainLetterSpring.rotX}
rotation-y={nonMainLetterSpring.rotY}
renderOrder={100}
>
<meshBasicMaterial
map={yellowFontTex}
attach="material"
transparent={true}
side={THREE.FrontSide}
depthTest={false}
/>
</a.mesh>
)}
</>
);
}
);

View file

@ -1,4 +1,4 @@
import orangeFont from "../../static/sprite/orange_jp_font.png";
import orangeFont from "../../static/sprites/fonts/orange_jp_font.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import jp_font_json from "../../resources/font_data/jp_font.json";
@ -34,8 +34,8 @@ const StaticJpCharacter = memo((props: { char: string; charIdx: number }) => {
return (
<mesh
position={[props.charIdx / 4, 0, 0]}
scale={[0.25, 0.25, 0]}
position={[props.charIdx / 5, 0, 0]}
scale={[0.2, 0.2, 0]}
geometry={geom}
renderOrder={205}
>

View file

@ -1,4 +1,4 @@
import orangeFont from "../../static/sprite/orange_font_texture.png";
import orangeFont from "../../static/sprites/fonts/orange_font_texture.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import orange_font_json from "../../resources/font_data/big_font.json";

View file

@ -1,13 +1,32 @@
import { NodeData } from "../components/MainScene/Site/Site";
import * as audio from "../static/sfx";
import * as audio from "../static/audio/sfx";
import {
nodeExplodeAnimation,
nodeKnockAndFallAnimation,
nodeKnockAnimation,
nodeRipAnimation,
nodeThrowAnimation,
} from "../utils/node-animations";
import { playAudio } from "../store";
} from "../helpers/node-animation-helpers";
import { playMediaElement, resetMediaElement } from "../helpers/media-helpers";
import {
ActiveSite,
AuthorizeUserMatrixIndices,
EndComponent,
GameScene,
LeftMediaComponent,
MediaComponent,
MediaSide,
NodeData,
PromptComponent,
RightMediaComponent,
SiteSaveState,
SsknComponent,
UserSaveState,
} from "../types/types";
import { saveUserProgress, useStore } from "../store";
const setNodeViewed = useStore.getState().setNodeViewed;
const resetMediaScene = useStore.getState().resetMediaScene;
const loadUserSaveState = useStore.getState().loadUserSaveState;
export const siteMoveHorizontal = (calculatedState: {
lainMoveAnimation: string;
@ -19,15 +38,13 @@ export const siteMoveHorizontal = (calculatedState: {
mutation: {
lainMoveState: calculatedState.lainMoveAnimation,
siteRot: calculatedState.siteRot,
inputCooldown: true,
inputCooldown: 5500,
},
delay: 0,
},
{
mutation: {
activeNode: calculatedState.activeNode,
lainMoveState: "standing",
inputCooldown: false,
},
delay: 3900,
},
@ -45,37 +62,36 @@ export const siteMoveVertical = (calculatedState: {
mutation: {
lainMoveState: calculatedState.lainMoveAnimation,
activeLevel: calculatedState.activeLevel,
inputCooldown: true,
inputCooldown: 5500,
},
delay: 0,
},
{
mutation: {
activeNode: calculatedState.activeNode,
lainMoveState: "standing",
inputCooldown: false,
},
delay: 3900,
},
],
audio: [
{ sfx: [audio.sound13], delay: 0 },
{ sfx: [audio.sound13] },
{ sfx: [audio.sound10, audio.sound9], delay: 1300 },
{ sfx: [audio.sound8], delay: 2700 },
],
});
export const changeNode = (calculatedState: { activeNode: NodeData }) => ({
state: [{ mutation: { activeNode: calculatedState.activeNode }, delay: 0 }],
audio: [{ sfx: [audio.sound1], delay: 0 }],
});
export const throwNode = (calculatedState: { currentScene: string }) => ({
state: [
{
mutation: { lainMoveState: "throw_node", inputCooldown: true },
delay: 0,
mutation: { activeNode: calculatedState.activeNode, inputCooldown: 1500 },
},
],
audio: [{ sfx: [audio.sound1] }],
});
export const throwNode = (calculatedState: { currentScene: GameScene }) => ({
state: [
{ mutation: { lainMoveState: "throw_node", inputCooldown: -1 } },
{
mutation: {
currentScene: calculatedState.currentScene,
@ -87,18 +103,15 @@ export const throwNode = (calculatedState: { currentScene: string }) => ({
],
effects: [nodeThrowAnimation],
audio: [
{ sfx: [audio.sound0], delay: 0 },
{ sfx: [audio.sound0] },
{ sfx: [audio.sound12], delay: 1600 },
{ sfx: [audio.sound13, audio.sound14], delay: 2800 },
],
});
export const ripNode = (calculatedState: { currentScene: string }) => ({
export const ripNode = (calculatedState: { currentScene: GameScene }) => ({
state: [
{
mutation: { lainMoveState: "rip_node", inputCooldown: true },
delay: 0,
},
{ mutation: { lainMoveState: "rip_node", inputCooldown: -1 } },
{
mutation: {
currentScene: calculatedState.currentScene,
@ -110,7 +123,7 @@ export const ripNode = (calculatedState: { currentScene: string }) => ({
],
effects: [nodeRipAnimation],
audio: [
{ sfx: [audio.sound0], delay: 0 },
{ sfx: [audio.sound0] },
{ sfx: [audio.sound12], delay: 1600 },
{ sfx: [audio.sound13, audio.sound15], delay: 4000 },
],
@ -121,18 +134,17 @@ export const explodeNode = {
{
mutation: {
lainMoveState: "touch_node_and_get_scared",
inputCooldown: true,
inputCooldown: 3800,
},
delay: 0,
},
{
mutation: { lainMoveState: "standing", inputCooldown: false },
mutation: { lainMoveState: "standing" },
delay: 3800,
},
],
effects: [nodeExplodeAnimation],
audio: [
{ sfx: [audio.sound0], delay: 0 },
{ sfx: [audio.sound0] },
{ sfx: [audio.sound17], delay: 2400 },
{ sfx: [audio.sound33], delay: 3150 },
],
@ -140,33 +152,24 @@ export const explodeNode = {
export const knockNode = {
state: [
{ mutation: { lainMoveState: "knock", inputCooldown: true }, delay: 0 },
{ mutation: { lainMoveState: "knock", inputCooldown: 3500 } },
{
mutation: { lainMoveState: "standing", inputCooldown: false },
delay: 2900,
mutation: { lainMoveState: "standing" },
delay: 3500,
},
],
effects: [nodeKnockAnimation],
audio: [
{ sfx: [audio.sound0], delay: 0 },
{ sfx: [audio.sound18], delay: 1200 },
],
audio: [{ sfx: [audio.sound0] }, { sfx: [audio.sound18], delay: 1200 }],
};
export const knockNodeAndFall = {
state: [
{
mutation: { lainMoveState: "knock_and_fall", inputCooldown: true },
delay: 0,
},
{
mutation: { lainMoveState: "standing", inputCooldown: false },
delay: 7500,
},
{ mutation: { lainMoveState: "knock_and_fall", inputCooldown: 6000 } },
{ mutation: { lainMoveState: "standing" }, delay: 6000 },
],
effects: [nodeKnockAndFallAnimation],
audio: [
{ sfx: [audio.sound0], delay: 0 },
{ sfx: [audio.sound0] },
{ sfx: [audio.sound18], delay: 1200 },
{ sfx: [audio.sound19], delay: 2300 },
{ sfx: [audio.sound33], delay: 3150 },
@ -181,23 +184,28 @@ export const enterLevelSelection = (calculatedState: {
mutation: {
selectedLevel: calculatedState.selectedLevel,
mainSubscene: "level_selection",
inputCooldown: 1500,
},
delay: 0,
},
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
audio: [{ sfx: [audio.sound1] }],
});
export const exitLevelSelection = {
state: [{ mutation: { mainSubscene: "site" }, delay: 0 }],
audio: [{ sfx: [audio.sound1], delay: 0 }],
state: [{ mutation: { mainSubscene: "site", inputCooldown: 1500 } }],
audio: [{ sfx: [audio.sound1] }],
};
export const changeSelectedLevel = (calculatedState: {
selectedLevel: number;
}) => ({
state: [
{ mutation: { selectedLevel: calculatedState.selectedLevel }, delay: 0 },
{
mutation: {
selectedLevel: calculatedState.selectedLevel,
inputCooldown: 100,
},
},
],
});
@ -212,15 +220,13 @@ export const selectLevel = (calculatedState: {
lainMoveState: calculatedState.lainMoveState,
activeLevel: calculatedState.activeLevel,
mainSubscene: "site",
inputCooldown: true,
inputCooldown: 5500,
},
delay: 0,
},
{
mutation: {
activeNode: calculatedState.activeNode,
lainMoveState: "standing",
inputCooldown: false,
},
delay: 3900,
},
@ -238,19 +244,15 @@ export const pauseGame = (calculatedState: { siteRot: number[] }) => ({
lainMoveState: "rip_middle_ring",
pauseExitAnimation: false,
mainSubscene: "pause",
inputCooldown: true,
inputCooldown: -1,
},
delay: 0,
},
{
mutation: { siteRot: calculatedState.siteRot },
delay: 3600,
},
],
audio: [
{ sfx: [audio.sound7], delay: 0 },
{ sfx: [audio.sound23], delay: 3600 },
],
audio: [{ sfx: [audio.sound7] }, { sfx: [audio.sound23], delay: 3600 }],
});
export const changePauseComponent = (calculatedState: {
@ -258,29 +260,31 @@ export const changePauseComponent = (calculatedState: {
}) => ({
state: [
{
mutation: { activePauseComponent: calculatedState.activePauseComponent },
delay: 0,
mutation: {
activePauseComponent: calculatedState.activePauseComponent,
inputCooldown: 700,
},
},
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
audio: [{ sfx: [audio.sound1] }],
});
export const showPermissionDenied = {
state: [
{ mutation: { permissionDenied: true }, delay: 0 },
{ mutation: { permissionDenied: true, inputCooldown: 1200 } },
{ mutation: { permissionDenied: false }, delay: 1200 },
],
audio: [{ sfx: [audio.sound0], delay: 0 }],
audio: [{ sfx: [audio.sound0] }],
};
export const displayPrompt = {
state: [{ mutation: { promptVisible: true }, delay: 0 }],
audio: [{ sfx: [audio.sound0], delay: 0 }],
state: [{ mutation: { promptVisible: true, inputCooldown: 0 } }],
audio: [{ sfx: [audio.sound0] }],
};
export const showAbout = {
state: [{ mutation: { showingAbout: true }, delay: 0 }],
audio: [{ sfx: [audio.sound0], delay: 0 }],
state: [{ mutation: { showingAbout: true } }],
audio: [{ sfx: [audio.sound0] }],
};
export const exitPause = (calculatedState: { siteRot: number[] }) => ({
@ -288,103 +292,125 @@ export const exitPause = (calculatedState: { siteRot: number[] }) => ({
{
mutation: {
siteRot: calculatedState.siteRot,
pauseExitAnimation: true,
activePauseComponent: "change",
inputCooldown: true,
inputCooldown: 1400,
mainSubscene: "site",
activePauseComponent: "",
},
delay: 0,
},
{
mutation: {
mainSubscene: "site",
activePauseComponent: "change",
inputCooldown: false,
lainMoveState: "standing",
},
delay: 1200,
},
],
audio: [{ sfx: [audio.sound0], delay: 0 }],
audio: [{ sfx: [audio.sound0] }],
});
export const exitAbout = {
state: [{ mutation: { showingAbout: false }, delay: 0 }],
state: [{ mutation: { showingAbout: false, inputCooldown: 0 } }],
};
export const changePromptComponent = (calculatedState: {
activePromptComponent: "yes" | "no";
activePromptComponent: PromptComponent;
}) => ({
state: [
{
mutation: {
activePromptComponent: calculatedState.activePromptComponent,
inputCooldown: 100,
},
delay: 0,
},
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
audio: [{ sfx: [audio.sound1] }],
});
export const exitPrompt = {
state: [
{
mutation: { activePromptComponent: "no", promptVisible: false },
delay: 0,
mutation: {
activePromptComponent: "no",
promptVisible: false,
inputCooldown: 0,
},
},
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
audio: [{ sfx: [audio.sound28] }],
};
// todo actually save
export const saveGame = () => ({
export const saveGame = (calculatedState: {
userSaveState: UserSaveState;
}) => ({
state: [
{ mutation: { saveSuccessful: true, inputCooldown: 1200 } },
{
mutation: { saveSuccessful: true },
delay: 0,
},
{
mutation: { saveSuccessful: undefined },
mutation: {
saveSuccessful: undefined,
promptVisible: false,
activePromptComponent: "no",
},
delay: 1200,
},
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
audio: [{ sfx: [audio.sound28] }],
effects: [() => saveUserProgress(calculatedState.userSaveState)],
});
// todo actually load
export const loadGame = () => ({
export const loadGameFail = {
state: [
{
mutation: { loadSuccessful: true },
delay: 0,
mutation: {
loadSuccessful: false,
inputCooldown: 1200,
},
},
{ mutation: { loadSuccessful: undefined }, delay: 1200 },
],
audio: [{ sfx: [audio.sound28] }],
};
export const loadGame = (calculatedState: {
userSaveState: UserSaveState;
}) => ({
state: [
{ mutation: { loadSuccessful: true, inputCooldown: 1200 } },
{
mutation: { loadSuccessful: undefined },
mutation: {
loadSuccessful: undefined,
currentScene: "null",
mainSubscene: "site",
lainMoveState: "standing",
promptVisible: false,
activePromptComponent: "no",
activePauseComponent: "change",
},
delay: 1200,
},
{
mutation: { currentScene: "main", intro: true },
delay: 1300,
},
],
audio: [{ sfx: [audio.sound28] }],
effects: [
() =>
setTimeout(() => loadUserSaveState(calculatedState.userSaveState), 1200),
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
});
export const changeSite = (calculatedState: {
newActiveSite: "a" | "b";
newActiveSite: ActiveSite;
newActiveNode: NodeData;
newActiveLevel: string;
newSiteRot: number[];
newSiteSaveState: {
a: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
b: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
};
newSiteSaveState: SiteSaveState;
}) => ({
state: [
{
mutation: {
intro: true,
currentScene: "change_disc",
lainMoveState: "standing",
promptVisible: false,
@ -397,26 +423,338 @@ export const changeSite = (calculatedState: {
activeLevel: calculatedState.newActiveLevel,
// save state
siteSaveState: calculatedState.newSiteSaveState,
inputCooldown: -1,
},
delay: 0,
},
],
});
export const changeLeftMediaComponent = (calculatedState: {
activeComponent: "play" | "exit";
activeComponent: LeftMediaComponent;
}) => ({
state: [
{ mutation: { activeMediaComponent: calculatedState.activeComponent } },
{
mutation: {
activeMediaComponent: calculatedState.activeComponent,
inputCooldown: 1200,
},
},
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
audio: [{ sfx: [audio.sound1] }],
});
export const changeMediaSide = (calculatedState: {
activeMediaComponent: "fstWord" | "sndWord" | "thirdWord" | "exit" | "play";
activeMediaComponent: MediaComponent;
lastActiveMediaComponents: {
left: "play" | "exit";
right: "fstWord" | "sndWord" | "thirdWord";
left: LeftMediaComponent;
right: RightMediaComponent;
};
currentMediaSide: "right" | "left";
}) => ({});
currentMediaSide: MediaSide;
}) => ({
state: [
{
mutation: {
activeMediaComponent: calculatedState.activeMediaComponent,
lastActiveMediaComponents: calculatedState.lastActiveMediaComponents,
currentMediaSide: calculatedState.currentMediaSide,
inputCooldown: 0,
},
},
],
});
export const playMedia = (calculatedState: { activeNode: NodeData }) => ({
state: [{ mutation: { mediaPercentageElapsed: 0, inputCooldown: 500 } }],
effects: [
playMediaElement,
() =>
setNodeViewed(calculatedState.activeNode.node_name, {
is_viewed: 1,
is_visible: 1,
}),
],
});
export const exitMedia = {
state: [
{
mutation: {
currentScene: "main",
inputCooldown: -1,
},
},
],
effects: [resetMediaElement, resetMediaScene],
};
export const changeRightMediaComponent = (calculatedState: {
wordPosStateIdx: number;
activeComponent: RightMediaComponent;
}) => ({
state: [
{
mutation: {
activeMediaComponent: calculatedState.activeComponent,
mediaWordPosStateIdx: calculatedState.wordPosStateIdx,
inputCooldown: 300,
},
},
],
audio: [{ sfx: [audio.sound1] }],
});
export const wordNotFound = {
state: [
{
mutation: {
currentScene: "main",
wordNotFound: true,
inputCooldown: 300,
},
},
],
audio: [{ sfx: [audio.sound30] }],
effects: [resetMediaElement, resetMediaScene],
};
export const hideWordNotFound = {
state: [{ mutation: { wordNotFound: false, inputCooldown: 0 } }],
};
export const selectWord = (calculatedState: {
activeLevel: string;
activeNode: NodeData;
siteRot: number[];
}) => ({
state: [
{
mutation: {
activeLevel: calculatedState.activeLevel,
siteRot: calculatedState.siteRot,
activeNode: calculatedState.activeNode,
wordSelected: true,
currentScene: "main",
inputCooldown: -1,
},
},
],
audio: [{ sfx: [audio.sound29] }],
effects: [resetMediaElement, resetMediaScene],
});
export const changeSsknComponent = (calculatedState: {
activeSsknComponent: SsknComponent;
}) => ({
state: [
{
mutation: {
activeSsknComponent: calculatedState.activeSsknComponent,
inputCooldown: 100,
},
},
],
});
export const upgradeSskn = (calculatedState: { activeNode: NodeData }) => ({
state: [
{
mutation: {
ssknLoading: true,
inputCooldown: -1,
},
},
{ mutation: { currentScene: "main" }, delay: 6000 },
],
effects: [
() =>
setNodeViewed(calculatedState.activeNode.node_name, {
is_viewed: 1,
is_visible: 0,
}),
],
});
export const exitSskn = {
state: [
{
mutation: {
currentScene: "main",
ssknLoading: false,
activeSsknComponent: "ok",
inputCooldown: -1,
},
},
],
};
export const changeEndComponent = (calculatedState: {
activeEndComponent: EndComponent;
}) => ({
state: [
{
mutation: {
activeEndComponent: calculatedState.activeEndComponent,
inputCooldown: 100,
},
},
],
audio: [{ sfx: [audio.sound1] }],
});
export const endGame = (calculatedState: { userSaveState: UserSaveState }) => ({
state: [{ mutation: { currentScene: "boot", inputCooldown: -1 } }],
audio: [{ sfx: [audio.sound0] }],
effects: [() => saveUserProgress(calculatedState.userSaveState)],
});
export const changeMainMenuComponent = (calculatedState: {
activeMainMenuComponent: "authorize_user" | "load_data";
}) => ({
state: [
{
mutation: {
activeMainMenuComponent: calculatedState.activeMainMenuComponent,
inputCooldown: 200,
},
},
],
audio: [{ sfx: [audio.sound1] }],
});
export const exitLoadData = {
state: [
{
mutation: {
bootSubscene: "main_menu",
promptVisible: false,
activePromptComponent: "no",
inputCooldown: 500,
},
},
],
audio: [{ sfx: [audio.sound29] }],
};
export const enterLoadData = {
state: [
{ mutation: { bootSubscene: "load_data", inputCooldown: 500 } },
{ mutation: { promptVisible: true }, delay: 500 },
],
audio: [{ sfx: [audio.sound0] }],
};
export const enterUserAuthorization = {
state: [
{
mutation: {
bootSubscene: "authorize_user",
inputCooldown: 500,
},
},
],
audio: [{ sfx: [audio.sound0] }],
};
export const exitUserAuthorization = {
state: [
{
mutation: {
playerName: "",
bootSubscene: "main_menu",
inputCooldown: 500,
authorizeUserMatrixIndices: { rowIdx: 1, colIdx: 7 },
},
},
],
audio: [{ sfx: [audio.sound29] }],
};
export const startNewGame = {
state: [
{ mutation: { currentScene: "main", intro: true, inputCooldown: -1 } },
],
};
export const updatePlayerName = (calculatedState: { playerName: string }) => ({
state: [{ mutation: { playerName: calculatedState.playerName } }],
audio: [{ sfx: [audio.sound0] }],
});
export const removePlayerNameLastChar = (calculatedState: {
playerName: string;
}) => ({
state: [{ mutation: { playerName: calculatedState.playerName } }],
audio: [{ sfx: [audio.sound29] }],
});
export const failUpdatePlayerName = { audio: [{ sfx: [audio.sound0] }] };
export const updateAuthorizeUserLetterMatrixIndices = (calculatedState: {
authorizeUserLetterMatrixIndices: AuthorizeUserMatrixIndices;
}) => ({
state: [
{
mutation: {
inputCooldown: 300,
authorizeUserMatrixIndices:
calculatedState.authorizeUserLetterMatrixIndices,
},
},
],
});
export const playIdleVideo = (calculatedState: { idleMedia: string }) => ({
state: [
{
mutation: {
idleStarting: true,
idleMedia: calculatedState.idleMedia,
idleImages: undefined,
idleNodeName: undefined,
inputCooldown: -1,
},
},
{ mutation: { currentScene: "idle_media" }, delay: 1200 },
],
});
export const playIdleAudio = (calculatedState: {
idleMedia: string;
idleImages: { "1": string; "2": string; "3": string };
idleNodeName: string;
}) => ({
state: [
{
mutation: {
idleStarting: true,
inputCooldown: -1,
idleMedia: calculatedState.idleMedia,
idleImages: calculatedState.idleImages,
idleNodeName: calculatedState.idleNodeName,
},
},
{ mutation: { currentScene: "idle_media" }, delay: 1200 },
],
});
export const playLainIdleAnim = (calculatedState: {
lainMoveState: string;
duration: number;
}) => ({
state: [
{
mutation: {
lainMoveState: calculatedState.lainMoveState,
canLainMove: false,
},
},
{
mutation: { lainMoveState: "standing", canLainMove: true },
delay: calculatedState.duration,
},
],
});
export const resetInputCooldown = {
state: [{ mutation: { inputCooldown: 0 } }],
};

29
src/core/handleEvent.ts Normal file
View file

@ -0,0 +1,29 @@
import { playAudio, useStore } from "../store";
import sleep from "../utils/sleep";
import { GameEvent } from "../types/types";
// the async/await here might be misleading for some, it functions as a setTimeout that fires
// multiple async calls without stopping the execution, which is what we want.
const handleEvent = (event: GameEvent) => {
const setState = useStore.setState;
const { state, effects, audio } = event;
if (state)
state.forEach(async (mutationData) => {
const { delay, mutation } = mutationData;
if (delay) await sleep(delay);
setState(mutation);
});
if (effects) effects.forEach((effect) => effect());
if (audio)
audio.forEach(async (audio) => {
const { delay, sfx } = audio;
if (delay) await sleep(delay);
sfx.forEach((soundEffect) => playAudio(soundEffect));
});
};
export default handleEvent;

View file

@ -0,0 +1,123 @@
import authorize_user_letters from "../../resources/authorize_user_letters.json";
import {
handleNameSelection,
handleUserAuthorizationMove,
} from "../../helpers/name-selection-helpers";
import {
changeMainMenuComponent,
changePromptComponent,
enterLoadData,
enterUserAuthorization,
exitLoadData,
exitUserAuthorization,
failUpdatePlayerName,
loadGame,
loadGameFail,
removePlayerNameLastChar,
startNewGame,
updateAuthorizeUserLetterMatrixIndices,
updatePlayerName,
} from "../eventTemplates";
import { BootSceneContext, GameEvent } from "../../types/types";
const handleBootSceneInput = (
bootSceneContext: BootSceneContext,
keyPress: string
): GameEvent | undefined => {
const {
subscene,
activeMainMenuComponent,
activePromptComponent,
promptVisible,
playerName,
authorizeUserMatrixIndices,
} = bootSceneContext;
if (promptVisible) {
switch (keyPress) {
case "LEFT":
return changePromptComponent({ activePromptComponent: "yes" });
case "RIGHT":
return changePromptComponent({ activePromptComponent: "no" });
case "CIRCLE":
switch (activePromptComponent) {
case "no":
return exitLoadData;
case "yes":
const stateToLoad = localStorage.getItem("lainSaveState");
if (stateToLoad)
return loadGame({
userSaveState: JSON.parse(stateToLoad),
});
else return loadGameFail;
}
}
} else {
switch (subscene) {
case "main_menu":
switch (keyPress) {
case "UP":
case "DOWN":
const newComponent =
keyPress === "UP" ? "authorize_user" : "load_data";
return changeMainMenuComponent({
activeMainMenuComponent: newComponent,
});
case "CIRCLE":
switch (activeMainMenuComponent) {
case "authorize_user":
return enterUserAuthorization;
case "load_data":
return enterLoadData;
}
}
break;
case "authorize_user":
switch (keyPress) {
case "START":
if (playerName.length > 0) return startNewGame;
return;
case "CROSS":
if (playerName.length > 0) {
return removePlayerNameLastChar({
playerName: playerName.slice(0, -1),
});
} else {
return exitUserAuthorization;
}
case "LEFT":
case "UP":
case "DOWN":
case "RIGHT":
const direction = keyPress.toLowerCase();
const newMatrixIndices = handleUserAuthorizationMove(
authorizeUserMatrixIndices,
direction
);
if (newMatrixIndices)
return updateAuthorizeUserLetterMatrixIndices({
authorizeUserLetterMatrixIndices: newMatrixIndices,
});
break;
case "CIRCLE":
const chosenCharacter =
authorize_user_letters.matrix[authorizeUserMatrixIndices.rowIdx][
authorizeUserMatrixIndices.colIdx
];
if (chosenCharacter) {
const newName = handleNameSelection(playerName, chosenCharacter);
if (newName && newName.length > 8) return;
if (newName !== undefined)
return updatePlayerName({ playerName: newName });
else return failUpdatePlayerName;
}
}
}
}
};
export default handleBootSceneInput;

View file

@ -0,0 +1,52 @@
import { changeEndComponent, changeSite, endGame } from "../eventTemplates";
import { EndSceneContext, GameEvent } from "../../types/types";
import { getCurrentUserState } from "../../store";
const handleEndSceneInput = (
endSceneContext: EndSceneContext,
keyPress: string
): GameEvent | undefined => {
const {
selectionVisible,
activeEndComponent,
siteSaveState,
activeNode,
activeLevel,
siteRot,
} = endSceneContext;
if (selectionVisible) {
switch (keyPress) {
case "UP":
case "DOWN":
const newComponent = keyPress === "UP" ? "end" : "continue";
return changeEndComponent({ activeEndComponent: newComponent });
case "CIRCLE":
switch (activeEndComponent) {
case "end":
return endGame({ userSaveState: getCurrentUserState() });
case "continue":
const siteToLoad = "a";
const stateToLoad = siteSaveState[siteToLoad];
const newSiteSaveState = {
...siteSaveState,
b: {
activeNode: activeNode,
siteRot: [0, siteRot[1], 0],
activeLevel: activeLevel.toString().padStart(2, "0"),
},
};
return changeSite({
newActiveSite: siteToLoad,
newActiveNode: stateToLoad.activeNode,
newSiteRot: stateToLoad.siteRot,
newActiveLevel: stateToLoad.activeLevel,
newSiteSaveState: newSiteSaveState,
});
}
}
}
};
export default handleEndSceneInput;

View file

@ -2,9 +2,9 @@ import {
findNode,
getNodeById,
isNodeVisible,
nodeToScene,
unknownNodeTemplate,
} from "../../utils/node-utils";
import { MainSceneContext } from "../../store";
} from "../../helpers/node-helpers";
import {
changeNode,
changePauseComponent,
@ -18,19 +18,29 @@ import {
exitPause,
exitPrompt,
explodeNode,
hideWordNotFound,
knockNode,
knockNodeAndFall,
loadGame,
loadGameFail,
pauseGame,
resetInputCooldown,
ripNode,
saveGame,
selectLevel,
showAbout,
showPermissionDenied,
siteMoveHorizontal,
siteMoveVertical,
throwNode,
} from "../eventTemplates";
import { GameEvent, MainSceneContext } from "../../types/types";
import { getCurrentUserState } from "../../store";
const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
const handleMainSceneInput = (
mainSceneContext: MainSceneContext,
keyPress: string
): GameEvent | undefined => {
const {
subscene,
selectedLevel,
@ -40,13 +50,12 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
siteRotY,
activeNode,
level,
keyPress,
ssknLvl,
showingAbout,
promptVisible,
activePromptComponent,
gateLvl,
siteSaveState,
wordNotFound,
canLainMove,
} = mainSceneContext;
if (promptVisible) {
@ -61,7 +70,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
return exitPrompt;
case "yes":
switch (activePauseComponent) {
case "change":
case "change": {
const siteToLoad = activeSite === "a" ? "b" : "a";
const stateToLoad = siteSaveState[siteToLoad];
@ -73,8 +82,6 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
activeLevel: level.toString().padStart(2, "0"),
},
};
console.log(newSiteSaveState);
return changeSite({
newActiveSite: siteToLoad,
newActiveNode: stateToLoad.activeNode,
@ -82,24 +89,32 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
newActiveLevel: stateToLoad.activeLevel,
newSiteSaveState: newSiteSaveState,
});
}
case "save":
return saveGame();
case "load":
return loadGame();
return saveGame({ userSaveState: getCurrentUserState() });
case "load": {
const stateToLoad = localStorage.getItem("lainSaveState");
if (stateToLoad)
return loadGame({
userSaveState: JSON.parse(stateToLoad),
});
else return loadGameFail;
}
}
}
}
} else {
switch (subscene) {
case "site":
if (wordNotFound) return hideWordNotFound;
switch (keyPress) {
case "LEFT":
case "RIGHT": {
const direction = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
activeNode,
direction,
activeNode.matrixIndices!,
level,
activeSite,
gameProgress,
@ -124,6 +139,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
};
if (nodeData.didMove) {
if (!canLainMove) return resetInputCooldown;
return siteMoveHorizontal({
lainMoveAnimation: lainMoveAnimation,
siteRot: newSiteRot,
@ -137,10 +153,16 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
case "DOWN": {
const direction = keyPress.toLowerCase();
const upperLimit = activeSite === "a" ? 22 : 13;
if (
(direction === "up" && level === upperLimit) ||
(direction === "down" && level === 1)
)
return;
const nodeData = findNode(
activeNode.id,
activeNode,
direction,
activeNode.matrixIndices!,
level,
activeSite,
gameProgress,
@ -160,19 +182,19 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
matrixIndices: nodeData.matrixIndices,
};
if (nodeData.didMove)
if (nodeData.didMove) {
if (!canLainMove) return resetInputCooldown;
return siteMoveVertical({
lainMoveAnimation: lainMoveAnimation,
activeLevel: newLevel,
activeNode: newNode,
});
else return changeNode({ activeNode: newNode });
} else return changeNode({ activeNode: newNode });
}
case "CIRCLE":
const eventAnimation =
Math.random() < 0.4 ? "rip_node" : "throw_node";
if (!canLainMove) return resetInputCooldown;
const nodeType = activeNode.type;
const eventAnimation = Math.random() < 0.4 ? throwNode : ripNode;
if (
activeNode.id === "" ||
@ -180,53 +202,18 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
)
return;
if (activeNode.upgrade_requirement > ssknLvl) {
const rejectEvents = [explodeNode, knockNode, knockNodeAndFall];
if (activeNode.upgrade_requirement > gameProgress.sskn_level) {
const rejectEvents = [knockNodeAndFall, knockNode, explodeNode];
return rejectEvents[Math.floor(Math.random() * 3)];
}
switch (nodeType) {
case 0:
case 2:
case 4:
case 3:
case 5:
return {
event: `${eventAnimation}_media`,
mutations: { scene: "media" },
};
case 6:
if (activeNode.node_name.substr(0, 3) === "TaK") {
return {
event: `${eventAnimation}_tak`,
mutations: { scene: "tak" },
};
} else {
return {
event: `${eventAnimation}_media`,
mutations: { scene: "media" },
};
}
case 8:
return {
event: `${eventAnimation}_gate`,
mutations: { scene: "gate" },
};
case 7:
return {
event: `${eventAnimation}_sskn`,
mutations: { scene: "sskn" },
};
case 9:
return {
event: `${eventAnimation}_polytan`,
mutations: { scene: "polytan" },
};
}
const newScene = nodeToScene(activeNode);
if (newScene) return eventAnimation({ currentScene: newScene });
break;
case "L2":
return enterLevelSelection({ selectedLevel: level });
case "TRIANGLE":
if (!canLainMove) return resetInputCooldown;
return pauseGame({ siteRot: [Math.PI / 2, siteRotY, 0] });
}
break;
@ -241,19 +228,28 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
if (selectedLevel - 1 >= 1)
return changeSelectedLevel({ selectedLevel: selectedLevel - 1 });
break;
case "X":
case "CROSS":
return exitLevelSelection;
case "CIRCLE":
if (!canLainMove) return resetInputCooldown;
if (level === selectedLevel) return;
const direction = selectedLevel > level ? "up" : "down";
const rowIdx = direction === "up" ? 2 : 0;
const newStartingPoint = {
...activeNode,
matrixIndices: {
matrixIdx: activeNode.matrixIndices!.matrixIdx,
rowIdx: direction === "up" ? 2 : 0,
colIdx: 0,
},
};
const nodeData = findNode(
activeNode.id,
newStartingPoint,
direction,
{ ...activeNode.matrixIndices!, rowIdx: rowIdx },
selectedLevel,
activeSite,
gameProgress,
@ -284,13 +280,12 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
switch (keyPress) {
case "UP":
case "DOWN":
const direction = keyPress.toLowerCase();
const components = ["load", "about", "change", "save", "exit"];
const newComponent =
components[
components.indexOf(activePauseComponent) +
(direction === "up" ? -1 : 1)
(keyPress === "UP" ? -1 : 1)
];
if (newComponent)
@ -308,7 +303,10 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
case "load":
return displayPrompt;
case "change":
if (activePauseComponent === "change" && gateLvl > 4)
if (
activePauseComponent === "change" &&
gameProgress.gate_level > 4
)
return showPermissionDenied;
else return displayPrompt;
}
@ -318,4 +316,4 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
}
};
export default handleMainSceneKeyPress;
export default handleMainSceneInput;

View file

@ -1,10 +1,25 @@
import { findNodeFromWord } from "../../utils/media-utils";
import { MediaSceneContext } from "../../store";
import { changeLeftMediaComponent, changeMediaSide } from "../eventTemplates";
import { findNodeFromWord } from "../../helpers/media-helpers";
import {
changeLeftMediaComponent,
changeMediaSide,
changeRightMediaComponent,
exitMedia,
playMedia,
selectWord,
wordNotFound,
} from "../eventTemplates";
import { isNodeVisible } from "../../helpers/node-helpers";
import {
GameEvent,
MediaSceneContext,
RightMediaComponent,
} from "../../types/types";
const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
const handleMediaSceneInput = (
mediaSceneContext: MediaSceneContext,
keyPress: string
): GameEvent | undefined => {
const {
keyPress,
activeMediaComponent,
wordPosStateIdx,
activeNode,
@ -19,11 +34,13 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
switch (keyPress) {
case "UP":
case "DOWN": {
const direction = keyPress.toLowerCase();
const newComponent = direction === "up" ? "play" : "exit";
const newComponent = keyPress === "UP" ? "play" : "exit";
return changeLeftMediaComponent({ activeComponent: newComponent });
}
case "RIGHT": {
if (!activeNode.media_file.includes("XA")) return;
return changeMediaSide({
activeMediaComponent: lastActiveMediaComponents.right,
lastActiveMediaComponents: {
@ -36,14 +53,9 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
case "CIRCLE":
switch (activeMediaComponent) {
case "play":
return {
event: "media_play_select",
node: activeNode,
};
return playMedia({ activeNode: activeNode });
case "exit":
return {
event: "media_play_select",
};
return exitMedia;
}
}
break;
@ -54,6 +66,7 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
wordPosStateIdx - 1 < 1 ? 6 : wordPosStateIdx - 1;
const newComponent = (() => {
switch (activeMediaComponent) {
default:
case "fstWord":
return "thirdWord";
case "sndWord":
@ -62,17 +75,17 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
return "sndWord";
}
})();
return {
event: "media_rightside_up",
newActiveComponent: newComponent,
return changeRightMediaComponent({
activeComponent: newComponent,
wordPosStateIdx: newWordPosStateIdx,
};
});
}
case "DOWN": {
const newWordPosStateIdx =
wordPosStateIdx + 1 > 6 ? 1 : wordPosStateIdx + 1;
const newComponent = (() => {
switch (activeMediaComponent) {
default:
case "fstWord":
return "sndWord";
case "sndWord":
@ -82,11 +95,10 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
}
})();
return {
event: "media_rightside_down",
newActiveComponent: newComponent,
return changeRightMediaComponent({
activeComponent: newComponent,
wordPosStateIdx: newWordPosStateIdx,
};
});
}
case "LEFT":
@ -94,29 +106,39 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
activeMediaComponent: lastActiveMediaComponents.left,
lastActiveMediaComponents: {
...lastActiveMediaComponents,
right: activeMediaComponent as
| "fstWord"
| "sndWord"
| "thirdWord",
right: activeMediaComponent as RightMediaComponent,
},
currentMediaSide: "left",
});
case "CIRCLE":
const data = findNodeFromWord(
activeMediaComponent,
activeNode,
activeSite,
gameProgress
);
const wordIdx = (() => {
switch (activeMediaComponent as RightMediaComponent) {
case "fstWord":
return 1;
case "sndWord":
return 2;
case "thirdWord":
return 3;
}
})();
if (data) {
return { event: `media_word_select`, ...data };
} else {
return { event: `word_node_not_found` };
}
const nodeName = activeNode.node_name;
const wordToFind = activeNode.words[wordIdx];
const data = findNodeFromWord(wordToFind, nodeName, activeSite);
const { node, level, siteRotY } = { ...data };
if (!isNodeVisible(node, gameProgress)) return wordNotFound;
return selectWord({
activeNode: node,
activeLevel: level,
siteRot: [0, siteRotY, 0],
});
}
}
};
export default handleMediaSceneKeyPress;
export default handleMediaSceneInput;

View file

@ -0,0 +1,26 @@
import { changeSsknComponent, exitSskn, upgradeSskn } from "../eventTemplates";
import { GameEvent, SsknSceneContext } from "../../types/types";
const handleSsknSceneInput = (
ssknSceneContext: SsknSceneContext,
keyPress: string
): GameEvent | undefined => {
const { activeSsknComponent, activeNode } = ssknSceneContext;
switch (keyPress) {
case "UP":
case "DOWN":
const direction = keyPress.toLowerCase();
const newComponent = direction === "up" ? "ok" : "cancel";
return changeSsknComponent({ activeSsknComponent: newComponent });
case "CIRCLE":
switch (activeSsknComponent) {
case "ok":
return upgradeSskn({ activeNode: activeNode });
case "cancel":
return exitSskn;
}
}
};
export default handleSsknSceneInput;

View file

@ -1,84 +0,0 @@
import { playAudio, useStore } from "../../store";
import * as audio from "../../static/sfx";
const handleBootSceneEvent = (eventState: any) => {
const setState = useStore.setState;
switch (eventState.event) {
case "main_menu_up":
setState({ activeMainMenuComponent: "authorize_user" });
playAudio(audio.sound1);
break;
case "main_menu_down":
setState({ activeMainMenuComponent: "load_data" });
playAudio(audio.sound1);
break;
case "main_menu_load_data_select":
setState({ bootSubscene: "load_data" });
playAudio(audio.sound0);
setTimeout(() => setState({ promptVisible: true }), 500);
break;
case "main_menu_authorize_user_select":
setState({ authorizeUserLetterIdx: 0, bootSubscene: "authorize_user" });
playAudio(audio.sound0);
break;
case "authorize_user_up":
case "authorize_user_down":
case "authorize_user_left":
case "authorize_user_right":
setState({
authorizeUserLetterIdx: eventState.authorizeUserLetterIdx,
});
break;
case "authorize_user_back":
setState({
playerName: "",
bootSubscene: "main_menu",
});
playAudio(audio.sound29);
break;
case "update_player_name":
setState({
playerName: eventState.playerName,
});
playAudio(audio.sound0);
break;
case "update_player_name_denied":
playAudio(audio.sound0);
break;
case "remove_last_char":
setState({ playerName: eventState.playerName });
playAudio(audio.sound29);
break;
case "load_data_no":
setState({
bootSubscene: "main_menu",
promptVisible: false,
activePromptComponent: "no",
});
playAudio(audio.sound29);
break;
case "load_data_yes":
// todo check if data exists
setState({ loadSuccessful: true });
playAudio(audio.sound28);
//todo actually load
setTimeout(() => setState({ loadSuccessful: undefined }), 1200);
break;
case "prompt_left":
setState({ activePromptComponent: "yes" });
playAudio(audio.sound1);
break;
case "prompt_right":
setState({ activePromptComponent: "no" });
playAudio(audio.sound1);
break;
case "start_new_game":
setState({ currentScene: "main", intro: true });
break;
}
};
export default handleBootSceneEvent;

View file

@ -1,20 +0,0 @@
import { useStore } from "../../store";
const handleEndSceneEvent = (eventState: any) => {
const setState = useStore.setState;
switch (eventState.event) {
case "end_selection_up":
setState({ activeEndComponent: "end" });
break;
case "end_selection_down":
setState({ activeEndComponent: "continue" });
break;
case "end_continue_select":
setState({ currentScene: "change_disc", intro: true });
break;
case "end_end_select":
setState({ currentScene: "boot" });
}
};
export default handleEndSceneEvent;

View file

@ -1,47 +0,0 @@
import { playAudio, useStore } from "../../store";
import sleep from "../../utils/sleep";
type Mutation = {
mutation: Object;
delay: number;
};
type EventAudio = {
sfx: HTMLAudioElement[];
delay: number;
};
type Event = {
state: Mutation[];
audio?: EventAudio[];
effects?: (() => void)[];
};
// the async/await here might be misleading for some, it functions as a setTimeout that fires
// multiple async calls without stopping the execution, which is what we want.
const handleEvent = (event: Event) => {
const now = performance.now();
const setState = useStore.setState;
const { state, audio, effects } = event;
state.forEach(async (mutationData) => {
const { delay, mutation } = mutationData;
if (delay) await sleep(delay);
setState(mutation);
});
if (effects) effects.forEach((effect) => effect());
if (audio) {
audio.forEach(async (audio) => {
const { delay, sfx } = audio;
if (delay) await sleep(delay);
sfx.forEach((soundEffect) => playAudio(soundEffect));
});
}
// console.log(performance.now() - now);
};
export default handleEvent;

View file

@ -1,84 +0,0 @@
import { playAudio, useStore } from "../../store";
import * as audio from "../../static/sfx";
const handleMediaSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const setNodeViewed = useStore.getState().setNodeViewed;
const updateLeftSide = useStore.getState().updateLeftSide;
const updateRightSide = useStore.getState().updateRightSide;
const setPercentageElapsed = useStore.getState().setPercentageElapsed;
const playMedia = () => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
if (mediaElement && mediaElement.paused) {
setPercentageElapsed(0);
mediaElement.play();
}
};
const exitMedia = () => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
if (mediaElement) {
mediaElement.pause();
mediaElement.currentTime = 0;
}
};
switch (eventState.event) {
case "media_rightside_down":
case "media_rightside_up":
setState({
activeMediaComponent: eventState.newActiveComponent,
mediaWordPosStateIdx: eventState.wordPosStateIdx,
});
playAudio(audio.sound1);
break;
case "media_leftside_right":
updateLeftSide(
eventState.newActiveComponent,
eventState.lastActiveComponent
);
break;
case "media_rightside_left":
updateRightSide(
eventState.newActiveComponent,
eventState.lastActiveComponent
);
break;
case "media_play_select":
setNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: 1,
});
playMedia();
break;
case "media_exit_select":
exitMedia();
playAudio(audio.sound29);
break;
case "media_word_select":
exitMedia();
playAudio(audio.sound29);
setState({
wordSelected: true,
activeLevel: eventState.level,
siteRot: [0, eventState.siteRotY, 0],
activeNode: eventState.node,
currentScene: "main",
});
break;
case "word_node_not_found":
exitMedia();
playAudio(audio.sound30);
setState({
mainSubscene: "not_found",
currentScene: "main",
});
}
};
export default handleMediaSceneEvent;

View file

@ -1,41 +0,0 @@
import { useStore } from "../../store";
const handleSsknSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const setNodeViewed = useStore.getState().setNodeViewed;
switch (eventState.event) {
case "sskn_cancel_up":
setState({
activeSsknComponent: "ok",
});
break;
case "sskn_ok_down":
setState({
activeSsknComponent: "cancel",
});
break;
case "sskn_ok_select":
setState({
ssknLoading: true,
});
setNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: 0,
});
// incrementSsknLvl();
setTimeout(() => setState({ currentScene: "main" }), 6000);
break;
case "sskn_cancel_select":
setState({
ssknLoading: false,
currentScene: "main",
activeSsknComponent: "ok",
});
}
};
export default handleSsknSceneEvent;

View file

@ -1,189 +0,0 @@
import authorize_user_letters from "../../resources/authorize_user_letters.json";
import handleNameSelection from "../../utils/handleNameSelection";
import { BootSceneContext } from "../../store";
const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
const {
keyPress,
subscene,
activeMainMenuComponent,
activePromptComponent,
promptVisible,
authorizeUserLetterIdx,
playerName,
} = bootSceneContext;
if (promptVisible) {
switch (keyPress) {
case "LEFT":
return { event: "prompt_left" };
case "RIGHT":
return { event: "prompt_right" };
case "CIRCLE":
switch (activePromptComponent) {
case "no":
return { event: "load_data_no" };
case "yes":
return {
event: "load_data_yes",
};
}
}
} else {
switch (subscene) {
case "main_menu":
switch (keyPress) {
case "UP":
case "DOWN":
return { event: `main_menu_${keyPress.toLowerCase()}` };
case "CIRCLE":
return { event: `main_menu_${activeMainMenuComponent}_select` };
}
break;
case "authorize_user":
switch (keyPress) {
case "START":
if (playerName.length > 0) {
return {
event: "start_new_game",
};
}
break;
case "X":
if (playerName.length > 0) {
return {
event: "remove_last_char",
playerName: playerName.slice(0, -1),
};
} else {
return { event: "authorize_user_back" };
}
case "LEFT":
// if utmost left, break
if (
[0, 13, 26, 39, 52].includes(authorizeUserLetterIdx) ||
authorizeUserLetterIdx === 15
)
break;
// skip
else if (
authorizeUserLetterIdx === 41 ||
authorizeUserLetterIdx === 17 ||
authorizeUserLetterIdx === 30 ||
authorizeUserLetterIdx === 43 ||
authorizeUserLetterIdx === 19 ||
authorizeUserLetterIdx === 45
) {
return {
event: "authorize_user_left",
authorizeUserLetterIdx: authorizeUserLetterIdx - 2,
};
} else {
return {
event: "authorize_user_left",
authorizeUserLetterIdx: authorizeUserLetterIdx - 1,
};
}
case "RIGHT":
// if utmost right, break
if ([12, 25, 38, 51, 64].includes(authorizeUserLetterIdx)) break;
// skip empty
else if (
authorizeUserLetterIdx === 39 ||
authorizeUserLetterIdx === 41 ||
authorizeUserLetterIdx === 28 ||
authorizeUserLetterIdx === 15 ||
authorizeUserLetterIdx === 43 ||
authorizeUserLetterIdx === 17
) {
return {
event: "authorize_user_right",
authorizeUserLetterIdx: authorizeUserLetterIdx + 2,
};
} else {
return {
event: "authorize_user_right",
authorizeUserLetterIdx: authorizeUserLetterIdx + 1,
};
}
case "DOWN":
// if utmost down, break
if (
Array.from(new Array(13), (x, i) => i + 52).includes(
authorizeUserLetterIdx
)
) {
break;
// skip empty
} else if (
authorizeUserLetterIdx === 0 ||
authorizeUserLetterIdx === 1 ||
authorizeUserLetterIdx === 52 ||
authorizeUserLetterIdx === 27 ||
authorizeUserLetterIdx === 31 ||
authorizeUserLetterIdx === 5
) {
return {
event: "authorize_user_down",
authorizeUserLetterIdx: authorizeUserLetterIdx + 26,
};
} else if (authorizeUserLetterIdx === 3) {
return {
event: "authorize_user_down",
authorizeUserLetterIdx: authorizeUserLetterIdx + 52,
};
} else {
return {
event: "authorize_user_down",
authorizeUserLetterIdx: authorizeUserLetterIdx + 13,
};
}
case "UP":
// if utmost up, break
if (
Array.from(new Array(13), (x, i) => i).includes(
authorizeUserLetterIdx
)
) {
break;
// skip empty
} else if (
authorizeUserLetterIdx === 26 ||
authorizeUserLetterIdx === 27 ||
authorizeUserLetterIdx === 53 ||
authorizeUserLetterIdx === 31 ||
authorizeUserLetterIdx === 57
) {
return {
event: "authorize_user_up",
authorizeUserLetterIdx: authorizeUserLetterIdx - 26,
};
} else if (authorizeUserLetterIdx === 55) {
return {
event: "authorize_user_up",
authorizeUserLetterIdx: authorizeUserLetterIdx - 52,
};
} else {
return {
event: "authorize_user_up",
authorizeUserLetterIdx: authorizeUserLetterIdx - 13,
};
}
case "CIRCLE":
const chosenCharacter =
authorize_user_letters[
authorizeUserLetterIdx.toString() as keyof typeof authorize_user_letters
];
const newName = handleNameSelection(playerName, chosenCharacter);
if (newName !== undefined)
return { event: "update_player_name", playerName: newName };
else return { event: "update_player_name_denied" };
}
break;
}
}
};
export default handleBootSceneKeyPress;

View file

@ -1,17 +0,0 @@
import { EndSceneContext } from "../../store";
const handleEndSceneKeyPress = (endSceneContext: EndSceneContext) => {
const { keyPress, selectionVisible, activeEndComponent } = endSceneContext;
if (selectionVisible) {
switch (keyPress) {
case "UP":
case "DOWN":
return { event: `end_selection_${keyPress.toLowerCase()}` };
case "CIRCLE":
return { event: `end_${activeEndComponent}_select` };
}
}
};
export default handleEndSceneKeyPress;

View file

@ -1,26 +0,0 @@
import { SsknSceneContext } from "../../store";
const handleSsknSceneKeyPress = (ssknSceneContext: SsknSceneContext) => {
const { keyPress, activeSsknComponent, activeNode } = ssknSceneContext;
switch (keyPress) {
case "UP":
case "DOWN":
return {
event: `sskn_${activeSsknComponent}_${keyPress.toLowerCase()}`,
};
case "CIRCLE":
if (activeSsknComponent === "ok") {
return {
event: `sskn_ok_select`,
node: activeNode,
};
} else {
return {
event: `sskn_cancel_select`,
};
}
}
};
export default handleSsknSceneKeyPress;

Some files were not shown because too many files have changed in this diff Show more