done refactoring state management, fixed some typing and renamed some stuff for clarity

This commit is contained in:
ad044 2021-02-17 20:21:27 +04:00
parent 8e76361374
commit faa34b072c
68 changed files with 1075 additions and 1768 deletions

View file

@ -7,7 +7,7 @@ import MediaScene from "./scenes/MediaScene";
import { useStore } from "./store";
import GateScene from "./scenes/GateScene";
import BootScene from "./scenes/BootScene";
import SSknScene from "./scenes/SSknScene";
import SsknScene from "./scenes/SsknScene";
import PolytanScene from "./scenes/PolytanScene";
import TaKScene from "./scenes/TaKScene";
import ChangeDiscScene from "./scenes/ChangeDiscScene";
@ -30,7 +30,7 @@ const App = () => {
idle_media: <IdleMediaScene />,
gate: <GateScene />,
boot: <BootScene />,
sskn: <SSknScene />,
sskn: <SsknScene />,
polytan: <PolytanScene />,
tak: <TaKScene />,
change_disc: <ChangeDiscScene />,

View file

@ -27,7 +27,7 @@ const BootMainMenuComponents = (props: BootMainMenuProps) => {
);
const activeMainMenuElement = useStore(
(state) => state.mainMenuComponentMatrix[state.mainMenuComponentMatrixIdx]
(state) => state.activeMainMenuComponent
);
const loadDataActiveTex = useLoader(THREE.TextureLoader, loadDataActive);

View file

@ -23,7 +23,7 @@ const EndSelectionScreen = () => {
const continueTextTex = useLoader(THREE.TextureLoader, continueText);
const middleLainTex = useLoader(THREE.TextureLoader, middleLain);
const componentMatrixIdx = useStore((state) => state.endComponentMatrixIdx);
const activeComponent = useStore((state) => state.activeEndComponent);
const [middleSpritesheetAnimator] = useState(() => {
const anim = new PlainAnimator(middleSpritesheetTex, 1, 4, 4, 24);
@ -75,7 +75,7 @@ const EndSelectionScreen = () => {
<meshBasicMaterial attach="material" color={0x000000} />
</mesh>
<sprite
position={componentMatrixIdx === 0 ? [0, 1, 0] : [0, -1.5, 0]}
position={activeComponent === "end" ? [0, 1, 0] : [0, -1.5, 0]}
scale={[0.5, 0.5, 0]}
>
<spriteMaterial attach="material" map={circleSpritesheetTex} />

View file

@ -15,7 +15,7 @@ const Images = () => {
const [sceneImages, setSceneImages] = useState([] as any);
const [activeImage, setActiveImage] = useState<THREE.Texture>();
const currentSite = useStore((state) => state.activeSite);
const activeSite = useStore((state) => state.activeSite);
const dummyTex = useLoader(THREE.TextureLoader, dummy);
@ -49,7 +49,7 @@ const Images = () => {
imgTries++;
if (img[1] !== "-1") {
import(
"../static/media_images/" + currentSite + "/" + img[1] + ".png"
"../static/media_images/" + activeSite + "/" + img[1] + ".png"
).then((imageSrc: { default: string }) => {
imgArr.splice(parseInt(img[0]), 0, imageSrc);
if (imgTries === 3) {
@ -60,7 +60,7 @@ const Images = () => {
}
});
}
}, [currentScene, currentSite, idleNodeImages, nodeImages]);
}, [currentScene, activeSite, idleNodeImages, nodeImages]);
useEffect(() => {
const loadNewImage = (imgIdx: number) => {

View file

@ -1,99 +1,37 @@
import { useCallback, useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useRef } from "react";
import {
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSSknSceneContext,
getSsknSceneContext,
MainSceneContext,
playAudio,
useStore,
} from "../store";
import { getKeyCodeAssociation } from "../utils/keyPressUtils";
import mediaManager from "../core/setters/media/mediaManager";
import handleMediaSceneKeyPress from "../core/scene-keypress-handlers/handleMediaSceneKeyPress";
import sceneManager from "../core/setters/sceneManager";
import levelSelectionManager from "../core/setters/main/level_selection/levelSelectionManager";
import nodeManager from "../core/setters/main/site/nodeManager";
import levelManager from "../core/setters/main/site/levelManager";
import lainManager from "../core/setters/main/site/lainManager";
import siteManager from "../core/setters/main/site/siteManager";
import pauseManager from "../core/setters/main/pause/pauseManager";
import mainSubsceneManager from "../core/setters/main/mainSubsceneManager";
import ssknManager from "../core/setters/sskn/ssknManager";
import handleSSknSceneKeyPress from "../core/scene-keypress-handlers/handleSSknSceneKeyPress";
import handleSsknSceneKeyPress from "../core/scene-keypress-handlers/handleSsknSceneKeyPress";
import handleMainSceneKeyPress from "../core/scene-keypress-handlers/handleMainSceneKeyPress";
import gameLoader from "../core/setters/gameLoader";
import gameSaver from "../core/setters/gameSaver";
import progressManager from "../core/setters/progressManager";
import promptManager from "../core/setters/promptManager";
import bootSubsceneManager from "../core/setters/boot/bootSubsceneManager";
import bootManager from "../core/setters/boot/bootManager";
import handleBootSceneKeyPress from "../core/scene-keypress-handlers/handleBootSceneKeyPress";
import soundManager from "../core/setters/soundManager";
import { useFrame } from "react-three-fiber";
import { getRandomIdleLainAnim, getRandomIdleMedia } from "../utils/idle-utils";
import idleManager from "../core/setters/main/idleManager";
import { getRandomIdleLainAnim } from "../utils/idle-utils";
import * as audio from "../static/sfx";
import handleEndSceneKeyPress from "../core/scene-keypress-handlers/handleEndSceneKeyPress";
import endManager from "../core/setters/end/endManager";
import handleMainSceneEvent from "../core/scene-event-handlers/handleMainSceneEvent";
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";
const KeyPressHandler = () => {
const mediaSceneSetters = useMemo(
() => [
mediaManager,
sceneManager,
nodeManager,
levelManager,
siteManager,
progressManager,
mainSubsceneManager,
soundManager,
],
[]
);
const ssknSceneSetters = useMemo(
() => [ssknManager, sceneManager, progressManager],
[]
);
const mainSceneSetters = useMemo(
() => [
levelSelectionManager,
nodeManager,
levelManager,
lainManager,
siteManager,
pauseManager,
mainSubsceneManager,
sceneManager,
gameLoader,
gameSaver,
progressManager,
promptManager,
soundManager,
],
[]
);
const bootSceneSetters = useMemo(
() => [
bootSubsceneManager,
bootManager,
promptManager,
gameLoader,
soundManager,
sceneManager,
],
[]
);
const endSceneSetters = useMemo(
() => [sceneManager, soundManager, endManager],
[]
);
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);
@ -107,7 +45,7 @@ const KeyPressHandler = () => {
scene === "main"
) {
if (now > lainIdleCounter.current + 10000) {
lainManager({ event: getRandomIdleLainAnim() });
setLainMoveState(getRandomIdleLainAnim());
// after one idle animation plays, the second comes sooner than it would after a regular keypress
lainIdleCounter.current = now - 2500;
}
@ -118,11 +56,11 @@ const KeyPressHandler = () => {
// but i'm way too lazy for that
idleSceneCounter.current = -1;
idleManager(getRandomIdleMedia());
// idleManager(getRandomIdleMedia());
playAudio(audio.sound32);
setTimeout(() => {
sceneManager({ event: "play_idle_media" });
// useStore.setState({ event: "play_idle_media" });
}, 1200);
}
}
@ -140,83 +78,71 @@ const KeyPressHandler = () => {
const now = Date.now();
if (keyPress) {
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,
handler: handleMainSceneKeyPress,
setters: mainSceneSetters,
keyPressHandler: handleMainSceneKeyPress,
eventHandler: handleMainSceneEvent,
};
case "media":
return {
contextProvider: getMediaSceneContext,
handler: handleMediaSceneKeyPress,
setters: mediaSceneSetters,
keyPressHandler: handleMediaSceneKeyPress,
eventHandler: handleMediaSceneEvent,
};
case "sskn":
return {
contextProvider: getSSknSceneContext,
handler: handleSSknSceneKeyPress,
setters: ssknSceneSetters,
contextProvider: getSsknSceneContext,
keyPressHandler: handleSsknSceneKeyPress,
eventHandler: handleSsknSceneEvent,
};
case "boot":
return {
contextProvider: getBootSceneContext,
handler: handleBootSceneKeyPress,
setters: bootSceneSetters,
keyPressHandler: handleBootSceneKeyPress,
eventHandler: handleBootSceneEvent,
};
case "end":
return {
contextProvider: getEndSceneContext,
handler: handleEndSceneKeyPress,
setters: endSceneSetters,
keyPressHandler: handleEndSceneKeyPress,
eventHandler: handleEndSceneEvent,
};
case "gate":
case "polytan":
return {
action: () => useStore.setState({ currentScene: "main" }),
};
useStore.setState({ currentScene: "main" });
break;
case "idle_media":
return {
action: () =>
useStore.setState({
currentScene: "main",
idleStarting: false,
}),
};
useStore.setState({
currentScene: "main",
idleStarting: false,
});
break;
}
})();
if (sceneFns) {
// in case of polytan/gate we only need to do one thing, which is reset the scene.
// we check for that here
if (sceneFns.action) {
sceneFns.action();
} else {
const { contextProvider, handler, setters } = { ...sceneFns };
const ctx = { ...contextProvider(), keyPress: keyPress };
const event = handler(ctx);
if (event) {
setters.forEach((fn) => fn(event));
}
}
const { contextProvider, keyPressHandler, eventHandler } = sceneFns;
const ctx = contextProvider(keyPress);
const event = keyPressHandler(ctx);
if (event) eventHandler(event);
}
}
},
[
bootSceneSetters,
endSceneSetters,
mainSceneSetters,
mediaSceneSetters,
scene,
ssknSceneSetters,
]
[inputCooldown, scene]
);
useEffect(() => {

View file

@ -22,9 +22,7 @@ const Pause = () => {
);
const activeComponent = useStore((state) =>
showActiveComponent
? state.pauseComponentMatrix[state.pauseComponentMatrixIdx]
: ""
showActiveComponent ? state.activePauseComponent : ""
);
const generateSqaureGeom = useCallback((row: number, square: number) => {

View file

@ -11,7 +11,7 @@ import level_y_values from "../../resources/level_y_values.json";
import { filterInvisibleNodes } from "../../utils/node-utils";
import Loading from "../Loading";
export type NodeDataType = {
export type NodeData = {
id: string;
image_table_indices: { 1: string; 2: string; 3: string };
triggers_final_video: number;
@ -32,12 +32,12 @@ export type NodeDataType = {
is_viewed?: number;
};
export type LevelType = {
[key: string]: NodeDataType;
export type Level = {
[key: string]: NodeData;
};
export type SiteType = {
[key: string]: LevelType;
export type SiteData = {
[key: string]: Level;
};
type SiteProps = {
@ -47,11 +47,16 @@ type SiteProps = {
const Site = (props: SiteProps) => {
const wordSelected = useStore((state) => state.wordSelected);
const [rotState, setRot] = useSpring(() => ({
x: wordSelected ? 0 : useStore.getState().siteRot[0],
const [rotXState, setRotX] = useSpring(() => ({
x: 0,
config: { duration: 1200 },
}));
const [rotYState, setRotY] = useSpring(() => ({
y: wordSelected
? useStore.getState().oldSiteRot[1]
: useStore.getState().siteRot[1],
delay: 1100,
config: { duration: 1200 },
}));
@ -68,29 +73,32 @@ const Site = (props: SiteProps) => {
}));
useEffect(() => {
useStore.subscribe(setRot, (state) => ({
x: state.siteRot[0],
useStore.subscribe(setRotY, (state) => ({
y: state.siteRot[1],
delay: 1100,
}));
useStore.subscribe(setRotX, (state) => ({
x: state.siteRot[0],
}));
useStore.subscribe(setPos, (state) => ({
y: -level_y_values[state.activeLevel as keyof typeof level_y_values],
delay: 1300,
}));
}, [setPos, setRot]);
}, [setPos, setRotX, setRotY]);
const currentSite = useStore((state) => state.activeSite);
const activeSite = useStore((state) => state.activeSite);
const gameProgress = useStore((state) => state.gameProgress);
const visibleNodes = useMemo(
() =>
filterInvisibleNodes(currentSite === "a" ? site_a : site_b, gameProgress),
[currentSite, gameProgress]
filterInvisibleNodes(activeSite === "a" ? site_a : site_b, gameProgress),
[activeSite, gameProgress]
);
return (
<Suspense fallback={<Loading />}>
<a.group rotation-x={rotState.x}>
<a.group rotation-y={rotState.y} position-y={posState.y}>
<a.group rotation-x={rotXState.x}>
<a.group rotation-y={rotYState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />
<InactiveLevelNodes visibleNodes={visibleNodes} />
<Rings activateAllRings={props.introFinished} />

View file

@ -2,11 +2,11 @@ import React, { memo, useEffect, useState } from "react";
import Node from "./Node";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import { NodeDataType, SiteType } from "../Site";
import { NodeData, SiteData } from "../Site";
import usePrevious from "../../../hooks/usePrevious";
type ActiveLevelNodesProps = {
visibleNodes: SiteType;
visibleNodes: SiteData;
};
const ActiveLevelNodes = memo((props: ActiveLevelNodesProps) => {
@ -43,7 +43,7 @@ const ActiveLevelNodes = memo((props: ActiveLevelNodesProps) => {
return (
<>
{Object.values(visibleNodes).map((node: NodeDataType) => {
{Object.values(visibleNodes).map((node: NodeData) => {
return (
<Node
nodeName={node.node_name}

View file

@ -6,8 +6,8 @@ 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 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";
@ -29,7 +29,7 @@ type NodeContructorProps = {
const InactiveLevelNode = memo((props: NodeContructorProps) => {
const tex = useMemo(() => {
if (props.nodeName.includes("S")) {
return [SSkn, SSknViewed];
return [Sskn, SsknViewed];
} else if (
props.nodeName.startsWith("P") ||
props.nodeName.startsWith("G") ||

View file

@ -1,13 +1,13 @@
import React, { memo, useEffect, useState } from "react";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import { SiteType } from "../Site";
import { SiteData } from "../Site";
import InactiveLevelNode from "./InactiveLevelNode";
import usePrevious from "../../../hooks/usePrevious";
import { generateInactiveNodes } from "../../../utils/node-utils";
type ActiveLevelNodesProps = {
visibleNodes: SiteType;
visibleNodes: SiteData;
};
const InactiveLevelNodes = memo((props: ActiveLevelNodesProps) => {

View file

@ -8,9 +8,9 @@ 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 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";
@ -38,7 +38,7 @@ type NodeContructorProps = {
const Node = memo((props: NodeContructorProps) => {
const tex = useMemo(() => {
if (props.nodeName.includes("S")) {
return [SSkn, SSKnActive, SSknViewed];
return [Sskn, SsknActive, SsknViewed];
} else if (
props.nodeName.startsWith("P") ||
props.nodeName.startsWith("G") ||

View file

@ -6,8 +6,8 @@ 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 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";
@ -41,7 +41,7 @@ const GoldNode = (props: GoldNodeProps) => {
const tex = useMemo(() => {
if (activeNodeName.includes("S")) {
return [SSkn, SSKnGold];
return [Sskn, SsknGold];
} else if (
activeNodeName.startsWith("P") ||
activeNodeName.startsWith("G") ||

View file

@ -12,10 +12,10 @@ type RingsProps = {
const Rings = memo((props: RingsProps) => {
const activeLevel = useStore((state) => state.activeLevel);
const currentSite = useStore((state) => state.activeSite);
const activeSite = useStore((state) => state.activeSite);
const levelUpperLimit = useMemo(() => (currentSite === "a" ? 22 : 13), [
currentSite,
const levelUpperLimit = useMemo(() => (activeSite === "a" ? 22 : 13), [
activeSite,
]);
const possibleLevels = useMemo(
@ -55,7 +55,7 @@ const Rings = memo((props: RingsProps) => {
<PurpleRing
purpleRingPosY={0.44}
level={level[0]}
site={currentSite}
site={activeSite}
/>
<GrayRing grayRingPosY={-0.29} />
<CyanCrystal crystalRingPosY={-0.45} />

View file

@ -11,14 +11,7 @@ export type ShapeProps = {
};
const LeftSide = memo(() => {
const activeMediaComponent = useStore(
(state) =>
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
]
);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
const cubesActive = useMemo(() => activeMediaComponent === "exit", [
activeMediaComponent,

View file

@ -1,4 +1,4 @@
import React, { memo, useCallback, useMemo } from "react";
import React, { memo, useMemo } from "react";
import { useStore } from "../../../store";
import Word from "./RightSide/Word";
import { a, useSpring } from "@react-spring/three";
@ -37,17 +37,7 @@ const RightSide = memo(() => {
[]
);
const activeMediaComponent = useStore(
useCallback(
(state) =>
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
],
[]
)
);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
return (
<group position={[0, 0, -3]}>

View file

@ -18,9 +18,7 @@ const Prompt = () => {
const yesTex = useLoader(THREE.TextureLoader, yes);
const noTex = useLoader(THREE.TextureLoader, no);
const activeComponent = useStore(
(state) => state.promptComponentMatrix[state.promptComponentMatrixIdx]
);
const activeComponent = useStore((state) => state.activePromptComponent);
return (
<>

View file

@ -6,7 +6,7 @@ import * as THREE from "three";
import ssknTopLabel from "../../static/sprite/sskn_top_label.png";
import ssknDango from "../../static/sprite/sskn_dango.png";
const SSknBackground = memo(() => {
const SsknBackground = memo(() => {
const ssknBackgroundTex = useLoader(THREE.TextureLoader, ssknBackground);
const ssknBackgroundTextTex = useLoader(
THREE.TextureLoader,
@ -43,4 +43,4 @@ const SSknBackground = memo(() => {
);
});
export default SSknBackground;
export default SsknBackground;

View file

@ -10,10 +10,10 @@ import ssknTextWrapperInactive from "../../static/sprite/sskn_text_wrapper_inact
import ssknLine from "../../static/sprite/sskn_line.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import SSknLoadingBar from "./SSknLoadingBar";
import SsknLoadingBar from "./SsknLoadingBar";
import { useStore } from "../../store";
const SSknHUD = memo(() => {
const SsknHUD = memo(() => {
const ssknOkTex = useLoader(THREE.TextureLoader, ssknOk);
const ssknOkInactiveTex = useLoader(THREE.TextureLoader, ssknOkInactive);
const ssknCancelTex = useLoader(THREE.TextureLoader, ssknCancel);
@ -30,29 +30,27 @@ const SSknHUD = memo(() => {
);
const ssknLineTex = useLoader(THREE.TextureLoader, ssknLine);
const activeSSknComponent = useStore(
(state) => state.ssknComponentMatrix[state.ssknComponentMatrixIdx]
);
const activeSsknComponent = useStore((state) => state.activeSsknComponent);
const loading = useStore((state) => state.ssknLoading);
return (
<>
{loading ? (
<SSknLoadingBar />
<SsknLoadingBar />
) : (
<group>
<sprite position={[2.8, -2, 0]} scale={[1, 0.5, 0]}>
<spriteMaterial
attach="material"
map={activeSSknComponent === "ok" ? ssknOkTex : ssknOkInactiveTex}
map={activeSsknComponent === "ok" ? ssknOkTex : ssknOkInactiveTex}
/>
</sprite>
<sprite position={[3.3, -3, 0]} scale={[2, 0.5, 0]}>
<spriteMaterial
attach="material"
map={
activeSSknComponent === "cancel"
activeSsknComponent === "cancel"
? ssknCancelTex
: ssknCancelInactiveTex
}
@ -62,7 +60,7 @@ const SSknHUD = memo(() => {
<spriteMaterial
attach="material"
map={
activeSSknComponent === "ok"
activeSsknComponent === "ok"
? ssknTextWrapperTex
: ssknTextWrapperInactiveTex
}
@ -72,7 +70,7 @@ const SSknHUD = memo(() => {
<spriteMaterial
attach="material"
map={
activeSSknComponent === "cancel"
activeSsknComponent === "cancel"
? ssknTextWrapperTex
: ssknTextWrapperInactiveTex
}
@ -101,4 +99,4 @@ const SSknHUD = memo(() => {
);
});
export default SSknHUD;
export default SsknHUD;

View file

@ -3,7 +3,7 @@ import ssknIcon from "../../static/sprite/SSkn_icon.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
const SSknIcon = memo(() => {
const SsknIcon = memo(() => {
const ssknIconTex = useLoader(THREE.TextureLoader, ssknIcon);
const ssknIconRef = useRef<THREE.Object3D>();
const ssknIconShadowRef = useRef<THREE.Object3D>();
@ -51,4 +51,4 @@ const SSknIcon = memo(() => {
);
});
export default SSknIcon;
export default SsknIcon;

View file

@ -9,7 +9,7 @@ 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 SsknLoadingBar = () => {
const ssknLoadingBarContainerTex = useLoader(
THREE.TextureLoader,
ssknLoadingBarContainer
@ -92,4 +92,4 @@ const SSknLoadingBar = () => {
);
};
export default SSknLoadingBar;
export default SsknLoadingBar;

View file

@ -8,7 +8,7 @@ import React, { memo, useEffect, useMemo, useState } from "react";
import { useStore } from "../../store";
import usePrevious from "../../hooks/usePrevious";
const SiteBigLetter = memo((props: { letter: string; letterIdx: number }) => {
const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
const [color, setColor] = useState("yellow");
const tex = useMemo(
@ -76,14 +76,7 @@ const SiteBigLetter = memo((props: { letter: string; letterIdx: number }) => {
}, [letterData, lineYOffset]);
const activeNode = useStore((state) => state.activeNode);
const activeMediaComponent = useStore(
(state) =>
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
]
);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
@ -150,4 +143,4 @@ const SiteBigLetter = memo((props: { letter: string; letterIdx: number }) => {
);
});
export default SiteBigLetter;
export default BigLetter;

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from "react";
import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import SiteBigLetter from "./SiteBigLetter";
import BigLetter from "./BigLetter";
import usePrevious from "../../hooks/usePrevious";
import { getNodeHud } from "../../utils/node-utils";
@ -45,7 +45,7 @@ const MainYellowTextAnimator = (props: { visible?: boolean }) => {
position-z={-8.7}
scale={[0.04, 0.06, 0.04]}
>
<SiteBigLetter letter={text[idx]} letterIdx={idx} key={idx} />
<BigLetter letter={text[idx]} letterIdx={idx} key={idx} />
</a.group>
))}
</a.group>

View file

@ -1,7 +1,7 @@
import React, { memo, useEffect, useState } from "react";
import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import SiteBigLetter from "./SiteBigLetter";
import BigLetter from "./BigLetter";
const MediaYellowTextAnimator = memo(() => {
const [lastLeftComponent, setLastLeftComponent] = useState("play");
@ -13,14 +13,7 @@ const MediaYellowTextAnimator = memo(() => {
config: { duration: 280 },
});
const activeMediaComponent = useStore(
(state) =>
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
]
);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
useEffect(() => {
if (
@ -66,7 +59,7 @@ const MediaYellowTextAnimator = memo(() => {
position-z={-8.7}
scale={[0.04, 0.06, 0.04]}
>
<SiteBigLetter letter={textArr[idx]} letterIdx={idx} key={idx} />
<BigLetter letter={textArr[idx]} letterIdx={idx} key={idx} />
</a.group>
))}
</group>

View file

@ -0,0 +1,84 @@
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

@ -0,0 +1,20 @@
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,7 +1,7 @@
import { playAudio, useStore } from "../../store";
import sleep from "../../utils/sleep";
import * as audio from "../../static/sfx";
import { NodeDataType } from "../../components/MainScene/Site";
import { NodeData } from "../../components/MainScene/Site";
import {
nodeKnock,
nodeKnockAndFall,
@ -12,12 +12,14 @@ import {
type MainSceneMutations = {
level?: string;
node?: NodeDataType;
node?: NodeData;
};
const handleMainSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const changeSite = useStore.getState().changeSite;
switch (eventState.event) {
case "site_up":
case "site_down":
@ -25,6 +27,7 @@ const handleMainSceneEvent = (eventState: any) => {
setState({
lainMoveState: eventState.event,
activeLevel: eventState.level,
inputCooldown: true,
});
playAudio(audio.sound13);
@ -36,7 +39,11 @@ const handleMainSceneEvent = (eventState: any) => {
playAudio(audio.sound8);
await sleep(1200);
setState({ activeNode: eventState.node });
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "site_left":
@ -45,6 +52,7 @@ const handleMainSceneEvent = (eventState: any) => {
setState({
lainMoveState: eventState.event,
siteRot: [0, eventState.siteRotY, 0],
inputCooldown: true,
});
await sleep(1100);
@ -52,7 +60,11 @@ const handleMainSceneEvent = (eventState: any) => {
playAudio(audio.sound34);
await sleep(2800);
setState({ activeNode: eventState.node });
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "change_node":
@ -69,6 +81,7 @@ const handleMainSceneEvent = (eventState: any) => {
lainMoveState: "throw_node",
oldLevel: eventState.level,
oldSiteRot: [eventState.siteRotY, 0],
inputCooldown: true,
});
nodeThrow(eventState.siteRotY);
@ -87,6 +100,7 @@ const handleMainSceneEvent = (eventState: any) => {
setState({
currentScene: eventState.event.split("_")[2],
intro: false,
lainMoveState: "standing",
});
})();
break;
@ -100,6 +114,7 @@ const handleMainSceneEvent = (eventState: any) => {
lainMoveState: "rip_node",
oldLevel: eventState.level,
oldSiteRot: [eventState.siteRotY, 0],
inputCooldown: true,
});
nodeRip(eventState.siteRotY);
playAudio(audio.sound0);
@ -115,6 +130,7 @@ const handleMainSceneEvent = (eventState: any) => {
setState({
currentScene: eventState.event.split("_")[2],
intro: false,
lainMoveState: "standing",
});
})();
break;
@ -122,6 +138,7 @@ const handleMainSceneEvent = (eventState: any) => {
(async () => {
setState({
lainMoveState: "touch_and_scare",
inputCooldown: true,
});
nodeTouchAndScare(eventState.siteRotY);
@ -130,20 +147,29 @@ const handleMainSceneEvent = (eventState: any) => {
await sleep(750);
playAudio(audio.sound33);
await sleep(650);
setState({
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "knock":
(async () => {
setState({ lainMoveState: "knock" });
setState({ lainMoveState: "knock", inputCooldown: true });
nodeKnock(eventState.siteRotY);
await sleep(1200);
playAudio(audio.sound18);
await sleep(1700);
setState({ lainMoveState: "standing", inputCooldown: false });
})();
break;
case "knock_and_fall":
(async () => {
setState({ lainMoveState: "knock_and_fall" });
setState({ lainMoveState: "knock_and_fall", inputCooldown: true });
nodeKnockAndFall(eventState.siteRotY);
await sleep(1200);
@ -155,16 +181,17 @@ const handleMainSceneEvent = (eventState: any) => {
await sleep(850);
playAudio(audio.sound33);
await sleep(3350);
setState({ lainMoveState: "standing", inputCooldown: false });
})();
break;
case "enter_level_selection":
(async () => {
setState({
selectedLevel: eventState.level,
mainSubscene: "level_selection",
});
playAudio(audio.sound1);
})();
setState({
selectedLevel: eventState.level,
mainSubscene: "level_selection",
});
playAudio(audio.sound1);
break;
case "level_selection_up":
case "level_selection_down":
@ -181,6 +208,7 @@ const handleMainSceneEvent = (eventState: any) => {
lainMoveState: eventState.event,
activeLevel: eventState.level,
mainSubscene: "site",
inputCooldown: true,
});
await sleep(1300);
@ -191,7 +219,11 @@ const handleMainSceneEvent = (eventState: any) => {
playAudio(audio.sound8);
await sleep(1200);
setState({ activeNode: eventState.node });
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "exit_not_found":
@ -203,33 +235,86 @@ const handleMainSceneEvent = (eventState: any) => {
lainMoveState: "pause_game",
pauseExitAnimation: false,
mainSubscene: "pause",
inputCooldown: true,
});
playAudio(audio.sound7);
await sleep(3400);
playAudio(audio.sound23);
await sleep(200);
await sleep(3600);
useStore.getState().setSiteRotX(Math.PI / 2);
playAudio(audio.sound23);
})();
break;
case "pause_up":
case "pause_down":
setState({ pauseComponentMatrixIdx: eventState.pauseMatrixIdx });
setState({ activePauseComponent: eventState.activePauseComponent });
playAudio(audio.sound1);
break;
case "pause_exit_select":
(async () => {
setState({
pauseExitAnimation: true,
pauseComponentMatrixIdx: 2,
siteRot: eventState.siteRot,
});
playAudio(audio.sound0);
setState({
pauseExitAnimation: true,
activePauseComponent: "change",
siteRot: eventState.siteRot,
inputCooldown: true,
});
playAudio(audio.sound0);
await sleep(1100);
setState({ mainSubscene: "site" });
})();
setTimeout(
() =>
setState({
mainSubscene: "site",
inputCooldown: false,
lainMoveState: "standing",
}),
1200
);
break;
case "pause_about_select":
setState({ showingAbout: true });
playAudio(audio.sound0);
break;
case "exit_about":
setState({ showingAbout: false });
break;
case "display_prompt":
setState({ promptVisible: true });
playAudio(audio.sound0);
break;
case "exit_prompt":
setState({ promptVisible: false, activePromptComponent: "no" });
playAudio(audio.sound28);
break;
case "prompt_left":
setState({ activePromptComponent: "yes" });
playAudio(audio.sound1);
break;
case "prompt_right":
setState({ activePromptComponent: "no" });
playAudio(audio.sound1);
break;
case "show_permission_denied":
setState({ permissionDenied: true });
playAudio(audio.sound0);
setTimeout(() => setState({ permissionDenied: false }), 1200);
break;
case "pause_save_select":
setState({ saveSuccessful: true });
playAudio(audio.sound28);
//todo actually save
setTimeout(() => setState({ saveSuccessful: undefined }), 1200);
break;
case "pause_load_select":
// todo check if data exists
setState({ loadSuccessful: true });
playAudio(audio.sound28);
//todo actually load
setTimeout(() => setState({ loadSuccessful: undefined }), 1200);
break;
case "pause_change_select":
const siteToLoad: "a" | "b" = eventState.site;
changeSite(siteToLoad);
}
};

View file

@ -0,0 +1,92 @@
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_down":
setState({ activeMediaComponent: "exit" });
playAudio(audio.sound1);
break;
case "media_leftside_up":
setState({ activeMediaComponent: "play" });
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

@ -0,0 +1,42 @@
import { useStore } from "../../store";
const handleSsknSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const setNodeViewed = useStore.getState().setNodeViewed;
const incrementSsknLvl = useStore.getState().incrementSsknLvl;
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,7 +1,8 @@
import authorize_user_letters from "../../resources/authorize_user_letters.json";
import handleNameSelection from "../../utils/handleNameSelection";
import { BootSceneContext } from "../../store";
const handleBootSceneKeyPress = (bootSceneContext: any) => {
const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
const {
keyPress,
subscene,

View file

@ -4,15 +4,15 @@ import {
isNodeVisible,
unknownNodeTemplate,
} from "../../utils/node-utils";
import { MainSceneContext } from "../../store";
const handleMainSceneKeyPress = (mainSceneContext: any) => {
const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
const {
subscene,
selectedLevel,
pauseMatrixIdx,
activePauseComponent,
gameProgress,
currentSite,
activeSite,
siteRotY,
activeNode,
level,
@ -37,7 +37,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
case "yes":
return {
event: `pause_${activePauseComponent}_select`,
site: currentSite,
site: activeSite === "a" ? "b" : "a",
};
}
}
@ -54,7 +54,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
activeSite,
gameProgress,
true
);
@ -70,7 +70,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
: siteRotY - Math.PI / 4,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
@ -80,7 +80,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
event: "change_node",
nodeMatrixIndices: nodeData.matrixIndices,
node: {
...getNodeById(nodeData.node, currentSite),
...getNodeById(nodeData.node, activeSite),
matrixIndices: nodeData.matrixIndices,
},
};
@ -94,7 +94,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
activeSite,
gameProgress,
true
);
@ -109,7 +109,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
.padStart(2, "0"),
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
@ -118,7 +118,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
return {
event: "change_node",
node: {
...getNodeById(nodeData.node, currentSite),
...getNodeById(nodeData.node, activeSite),
matrixIndices: nodeData.matrixIndices,
},
};
@ -222,7 +222,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
}
break;
case "L2":
return { event: "toggle_level_selection", level: level };
return { event: "enter_level_selection", level: level };
case "TRIANGLE":
return { event: "pause_game" };
case "SPACE":
@ -232,13 +232,13 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
case "level_selection":
switch (keyPress) {
case "UP":
if (currentSite === "a") {
if (activeSite === "a") {
if (selectedLevel + 1 <= 22)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
} else if (currentSite === "b") {
} else if (activeSite === "b") {
if (selectedLevel + 1 <= 13)
return {
event: `level_selection_up`,
@ -269,7 +269,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
direction,
{ ...activeNode.matrixIndices!, rowIdx: rowIdx },
selectedLevel,
currentSite,
activeSite,
gameProgress,
false
);
@ -281,7 +281,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
event: event,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
@ -297,21 +297,50 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
};
else {
switch (keyPress) {
case "UP":
if (pauseMatrixIdx - 1 < 0) break;
return {
event: "pause_up",
pauseMatrixIdx: pauseMatrixIdx - 1,
};
case "DOWN":
if (pauseMatrixIdx + 1 > 4) break;
return {
event: "pause_down",
pauseMatrixIdx: pauseMatrixIdx + 1,
};
case "UP": {
const newComponent = (() => {
switch (activePauseComponent) {
case "exit":
return "save";
case "save":
return "change";
case "change":
return "about";
case "about":
return "load";
}
})();
if (newComponent)
return {
event: "pause_up",
activePauseComponent: newComponent,
};
break;
}
case "DOWN": {
const newComponent = (() => {
switch (activePauseComponent) {
case "load":
return "about";
case "about":
return "change";
case "change":
return "save";
case "save":
return "exit";
}
})();
if (newComponent)
return {
event: "pause_down",
activePauseComponent: newComponent,
};
break;
}
case "CIRCLE":
if (activePauseComponent === "change") {
if (gateLvl < 4) {
if (gateLvl > 4) {
return { event: "show_permission_denied" };
} else {
return {
@ -328,6 +357,7 @@ const handleMainSceneKeyPress = (mainSceneContext: any) => {
} else {
return {
event: `pause_${activePauseComponent}_select`,
siteRot: [0, siteRotY, 0],
};
}
}

View file

@ -1,75 +1,96 @@
import { findNodeFromWord } from "../../utils/media-utils";
import { MediaSceneContext } from "../../store";
const handleMediaSceneKeyPress = (mediaSceneContext: any) => {
const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
const {
keyPress,
activeMediaComponent,
wordPosStateIdx,
rightSideComponentIdx,
activeNode,
activeSite,
gameProgress,
currentMediaSide,
lastActiveMediaComponents,
} = mediaSceneContext;
const calculateNewRightSide = (
direction: string,
wordPosStateIdx: number,
rightSideComponentIdx: number
) => {
if (direction === "UP") {
wordPosStateIdx--;
if (wordPosStateIdx < 1) {
wordPosStateIdx = 6;
switch (currentMediaSide) {
case "left":
switch (keyPress) {
case "UP":
case "DOWN":
return {
event: `media_leftside_${keyPress.toLowerCase()}`,
};
case "RIGHT":
return {
event: "media_leftside_right",
lastActiveComponent: activeMediaComponent,
newActiveComponent: lastActiveMediaComponents.right,
};
case "CIRCLE":
switch (activeMediaComponent) {
case "play":
return {
event: "media_play_select",
node: activeNode,
};
case "exit":
return {
event: "media_play_select",
};
}
}
rightSideComponentIdx--;
if (rightSideComponentIdx < 0) {
rightSideComponentIdx = 2;
}
} else if (direction === "DOWN") {
wordPosStateIdx++;
if (wordPosStateIdx > 6) {
wordPosStateIdx = 1;
}
rightSideComponentIdx++;
if (rightSideComponentIdx > 2) {
rightSideComponentIdx = 0;
}
}
break;
case "right":
switch (keyPress) {
case "UP": {
const newWordPosStateIdx =
wordPosStateIdx - 1 < 1 ? 6 : wordPosStateIdx - 1;
const newComponent = (() => {
switch (activeMediaComponent) {
case "fstWord":
return "thirdWord";
case "sndWord":
return "fstWord";
case "thirdWord":
return "sndWord";
}
})();
return {
event: "media_rightside_up",
newActiveComponent: newComponent,
wordPosStateIdx: newWordPosStateIdx,
};
}
case "DOWN": {
const newWordPosStateIdx =
wordPosStateIdx + 1 > 6 ? 1 : wordPosStateIdx + 1;
const newComponent = (() => {
switch (activeMediaComponent) {
case "fstWord":
return "sndWord";
case "sndWord":
return "thirdWord";
case "thirdWord":
return "fstWord";
}
})();
return {
wordPosStateIdx: wordPosStateIdx,
rightSideComponentIdx: rightSideComponentIdx,
};
};
return {
event: "media_rightside_down",
newActiveComponent: newComponent,
wordPosStateIdx: newWordPosStateIdx,
};
}
switch (keyPress) {
case "UP":
case "DOWN":
case "RIGHT":
case "LEFT":
if (["fstWord", "sndWord", "thirdWord"].includes(activeMediaComponent)) {
const rightSide = calculateNewRightSide(
keyPress,
wordPosStateIdx,
rightSideComponentIdx
);
return {
event: `media_rightside_${keyPress.toLowerCase()}`,
rightSideComponentIdx: rightSide.rightSideComponentIdx,
wordPosStateIdx: rightSide.wordPosStateIdx,
};
} else {
const leftSideComponentIdx = keyPress === "UP" ? 0 : 1;
return {
event: `media_leftside_${keyPress.toLowerCase()}`,
leftSideComponentIdx: leftSideComponentIdx,
};
}
case "CIRCLE":
switch (activeMediaComponent) {
case "fstWord":
case "sndWord":
case "thirdWord":
case "LEFT":
return {
event: "media_rightside_left",
lastActiveComponent: activeMediaComponent,
newActiveComponent: lastActiveMediaComponents.left,
};
case "CIRCLE":
const data = findNodeFromWord(
activeMediaComponent,
activeNode,
@ -78,21 +99,10 @@ const handleMediaSceneKeyPress = (mediaSceneContext: any) => {
);
if (data) {
return { event: `media_${activeMediaComponent}_select`, ...data };
return { event: `media_word_select`, ...data };
} else {
return { event: `word_node_not_found` };
}
default:
if (activeMediaComponent === "play") {
return {
event: `media_play_select`,
node: activeNode,
};
} else {
return {
event: `media_exit_select`,
};
}
}
}
};

View file

@ -1,24 +0,0 @@
const handleSSknSceneKeyPress = (ssknSceneContext: any) => {
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;

View file

@ -0,0 +1,26 @@
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;

View file

@ -1,56 +0,0 @@
import { useStore } from "../../../store";
const bootManager = (eventState: any) => {
const setMainMenuComponentMatrixIdx = useStore.getState()
.setMainMenuComponentMatrixIdx;
const setAuthorizeUserLetterIdx = useStore.getState()
.setAuthorizeUserLetterIdx;
const setPlayerName = useStore.getState().setPlayerName;
const dispatchAction = (eventState: {
event: string;
authorizeUserLetterIdx: number;
playerName: string;
}) => {
switch (eventState.event) {
case "main_menu_up":
return {
action: () => setMainMenuComponentMatrixIdx(0),
};
case "main_menu_down":
return {
action: () => setMainMenuComponentMatrixIdx(1),
};
case "main_menu_authorize_user_select":
return { action: () => setAuthorizeUserLetterIdx(0) };
case "authorize_user_up":
case "authorize_user_down":
case "authorize_user_left":
case "authorize_user_right":
return {
action: () =>
setAuthorizeUserLetterIdx(eventState.authorizeUserLetterIdx),
};
case "authorize_user_back":
return {
action: () => setPlayerName(""),
};
case "update_player_name":
return {
action: () => setPlayerName(eventState.playerName),
};
case "remove_last_char":
return {
action: () => setPlayerName(eventState.playerName),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default bootManager;

View file

@ -1,27 +0,0 @@
import { useStore } from "../../../store";
const bootSubsceneManager = (eventState: any) => {
const setBootSubscene = useStore.getState().setBootSubscene;
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "authorize_user_back":
case "load_data_no":
return {
action: () => setBootSubscene("main_menu"),
};
case "main_menu_authorize_user_select":
return {
action: () => setBootSubscene("authorize_user"),
};
case "main_menu_load_data_select":
return { action: () => setBootSubscene("load_data") };
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default bootSubsceneManager;

View file

@ -1,24 +0,0 @@
import { useStore } from "../../../store";
const endManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setEndComponentMatrixIdx;
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "end_selection_up":
return {
action: () => setComponentMatrixIdx(0),
};
case "end_selection_down":
return {
action: () => setComponentMatrixIdx(1),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default endManager;

View file

@ -1,34 +0,0 @@
import { useStore } from "../../store";
import sleep from "../../utils/sleep";
const gameLoader = (eventState: any) => {
const loadSiteSaveState = useStore.getState().loadSiteSaveState;
const setLoadSuccessful = useStore.getState().setLoadSuccessful;
const dispatchAction = (eventState: { event: string; site: "a" | "b" }) => {
switch (eventState.event) {
case "pause_change_select":
return {
action: () => loadSiteSaveState(eventState.site === "a" ? "b" : "a"),
};
case "pause_load_select":
case "load_data_yes":
return {
action: async () => {
// todo check if data exists
setLoadSuccessful(true);
await sleep(1200);
//todo actually load
setLoadSuccessful(undefined);
},
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default gameLoader;

View file

@ -1,33 +0,0 @@
import { getSiteState, useStore } from "../../store";
import sleep from "../../utils/sleep";
const gameSaver = (eventState: any) => {
const setSiteSaveState = useStore.getState().setSiteSaveState;
const setSaveSuccessful = useStore.getState().setSaveSuccessful;
const dispatchAction = (eventState: { event: string; site: "a" | "b" }) => {
switch (eventState.event) {
case "pause_change_select":
return {
action: () =>
setSiteSaveState(eventState.site, getSiteState(eventState.site)),
};
case "pause_save_select":
return {
action: async () => {
setSaveSuccessful(true);
await sleep(1200);
//todo actually save
setSaveSuccessful(undefined);
},
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default gameSaver;

View file

@ -1,23 +0,0 @@
import { useStore } from "../../../store";
const idleManager = (eventState: any) => {
const setIdleStarting = useStore.getState().setIdleStarting;
const setIdleScene = useStore.getState().setIdleScene;
const dispatchAction = (eventState: {
media: string;
images: { "1": string; "2": string; "3": string } | undefined;
nodeName: string | undefined;
}) => ({
action: () => {
setIdleStarting(true);
setIdleScene(eventState);
},
});
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default idleManager;

View file

@ -1,24 +0,0 @@
import { useStore } from "../../../../store";
const levelSelectionManager = (eventState: any) => {
const setSelectedLevel = useStore.getState().setSelectedLevel;
const dispatchAction = (eventState: any) => {
switch (eventState.event) {
case "toggle_level_selection":
return {
action: () => setSelectedLevel(eventState.level),
};
case "level_selection_up":
case "level_selection_down":
return {
action: () => setSelectedLevel(eventState.selectedLevelIdx),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default levelSelectionManager;

View file

@ -1,48 +0,0 @@
import { useStore } from "../../../store";
import sleep from "../../../utils/sleep";
const mainSubsceneManager = (eventState: any) => {
const setMainSubscene = useStore.getState().setMainSubscene;
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "word_node_not_found":
return {
action: () => setMainSubscene("not_found"),
};
case "level_selection_back":
case "select_level_up":
case "select_level_down":
case "exit_not_found":
return {
action: () => setMainSubscene("site"),
};
case "toggle_level_selection":
return {
action: () => setMainSubscene("level_selection"),
};
case "pause_game":
return {
action: () => setMainSubscene("pause"),
};
case "pause_exit_select":
case "pause_change_select":
return {
action: () => {
setMainSubscene("site");
},
delay: 1800,
};
}
};
const { action, delay } = { ...dispatchAction(eventState) };
if (action)
(async () => {
if (delay) await sleep(delay);
action();
})();
};
export default mainSubsceneManager;

View file

@ -1,52 +0,0 @@
import { useStore } from "../../../../store";
import sleep from "../../../../utils/sleep";
type PauseManagerProps = { event: string; pauseMatrixIdx: number };
const pauseManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setPauseComponentMatrixIdx;
const setExitAnimation = useStore.getState().setPauseExitAnimation;
const setShowingAbout = useStore.getState().setShowingAbout;
const setPermissionDenied = useStore.getState().setPermissionDenied;
const dispatchAction = (eventState: PauseManagerProps) => {
switch (eventState.event) {
case "pause_up":
case "pause_down":
return {
action: () => setComponentMatrixIdx(eventState.pauseMatrixIdx),
};
case "pause_exit_select":
return {
action: () => {
setExitAnimation(true);
setComponentMatrixIdx(2);
},
};
case "show_permission_denied":
return {
action: async () => {
setPermissionDenied(true);
await sleep(1200);
setPermissionDenied(false);
},
};
case "pause_about_select":
return {
action: () => setShowingAbout(true),
};
case "exit_about":
return {
action: () => setShowingAbout(false),
};
case "pause_game":
return { action: () => setExitAnimation(false) };
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default pauseManager;

View file

@ -1,67 +0,0 @@
import { useStore } from "../../../../store";
const lainManager = (eventState: any) => {
const setLainMoveState = useStore.getState().setLainMoveState;
const dispatchAction = (eventState: any) => {
switch (eventState.event) {
case "site_up":
case "site_down":
case "site_left":
case "site_right":
case "select_level_up":
case "select_level_down":
case "pause_game":
case "knock_node":
case "prayer":
case "touch_sleeve":
case "thinking":
case "stretch_2":
case "stretch":
case "spin":
case "scratch_head":
case "blush":
case "hands_behind_head":
case "hands_on_hips":
case "hands_on_hips_2":
case "hands_together":
case "lean_forward":
case "lean_left":
case "lean_right":
case "look_around":
case "play_with_hair":
return {
action: () => setLainMoveState(eventState.event),
duration: 3900,
};
case "throw_node_media":
case "throw_node_gate":
case "throw_node_sskn":
case "throw_node_tak":
case "throw_node_polytan":
return { action: () => setLainMoveState("throw_node"), duration: 3900 };
case "rip_node_media":
case "rip_node_gate":
case "rip_node_sskn":
case "rip_node_tak":
case "rip_node_polytan":
return { action: () => setLainMoveState("rip_node"), duration: 6000 };
case "knock_and_fall":
case "knock":
case "touch_and_scare":
return {
action: () => setLainMoveState(eventState.event),
duration: 6000,
};
}
};
const { action, duration } = { ...dispatchAction(eventState) };
if (action) {
action();
setTimeout(() => setLainMoveState("standing"), duration);
}
};
export default lainManager;

View file

@ -1,30 +0,0 @@
import { useStore } from "../../../../store";
const levelManager = (eventState: any) => {
const setActiveLevel = useStore.getState().setActiveLevel;
const setOldLevel = useStore.getState().setOldLevel;
const dispatchAction = (eventState: any) => {
switch (eventState.event) {
case "throw_node_media":
case "rip_node_media":
return {
action: () => setOldLevel(eventState.level),
};
case "site_up":
case "site_down":
case "select_level_up":
case "select_level_down":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return { action: () => setActiveLevel(eventState.level) };
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default levelManager;

View file

@ -1,191 +0,0 @@
import { useStore } from "../../../../store";
import { NodeDataType } from "../../../../components/MainScene/Site";
import sleep from "../../../../utils/sleep";
const nodeManager = (eventState: any) => {
const setActiveNode = useStore.getState().setNode;
const setActiveNodePos = useStore.getState().setNodePos;
const setActiveNodeRot = useStore.getState().setNodeRot;
const setActiveNodeAttributes = useStore.getState().setNodeAttributes;
const calculateCoordsBasedOnRotation = (
x: number,
z: number,
rotation: number
) => ({
x: x * Math.cos(rotation) - z * Math.sin(rotation),
z: x * Math.sin(rotation) + z * Math.cos(rotation),
});
const animateActiveNodeThrow = async (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(1.55, 0.2, siteRotY);
const fourthCoordSet = calculateCoordsBasedOnRotation(0, 2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(800);
setActiveNodePos([sndCoordSet.x, 0, sndCoordSet.z]);
await sleep(1800);
setActiveNodePos([thirdCoordSet.x, 0, sndCoordSet.z]);
setActiveNodeRot([0, 0, -0.005]);
await sleep(100);
setActiveNodePos([fourthCoordSet.x, 0, fourthCoordSet.z]);
setActiveNodeRot([0, 0, -0.5]);
await sleep(1100);
setActiveNodeRot([0, 0, 0]);
setActiveNodeAttributes(false, "interactedWith");
};
const animateNodeKnock = async (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, -0.6, fstCoordSet.z]);
await sleep(2500);
setActiveNodeAttributes(false, "interactedWith");
};
const animateNodeKnockAndFall = async (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, -0.6, fstCoordSet.z]);
await sleep(2300);
setActiveNodeAttributes(false, "visible");
await sleep(200);
setActiveNodeAttributes(false, "interactedWith");
await sleep(700);
setActiveNodeAttributes(true, "visible");
};
const animateNodeTouchAndScare = async (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(-0.6, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(1200);
setActiveNodeAttributes(true, "exploding");
setActiveNodeAttributes(false, "visible");
await sleep(200);
setActiveNodeAttributes(false, "interactedWith");
setActiveNodeRot([0, 0, 0]);
await sleep(1750);
setActiveNodeAttributes(false, "exploding");
await sleep(350);
setActiveNodeAttributes(true, "visible");
};
const animateShrinkAndRip = async (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(0, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(800);
setActiveNodePos([sndCoordSet.x, 0, sndCoordSet.z]);
await sleep(2000);
setActiveNodePos([thirdCoordSet.x, -0.4, thirdCoordSet.z]);
await sleep(200);
setActiveNodeAttributes(true, "shrinking");
await sleep(200);
setActiveNodePos([thirdCoordSet.x, -1.5, thirdCoordSet.z]);
await sleep(300);
setActiveNodeAttributes(false, "visible");
await sleep(2900);
setActiveNodeAttributes(false, "interactedWith");
setActiveNodeAttributes(false, "shrinking");
setActiveNodeRot([0, 0, 0]);
await sleep(1100);
setActiveNodeAttributes(true, "visible");
};
const updateActiveNode = async (node: NodeDataType) => {
setActiveNode(node);
};
const dispatchAction = (eventState: any) => {
switch (eventState.event) {
case "touch_and_scare":
return {
action: () => animateNodeTouchAndScare(eventState.siteRotY),
};
case "knock_and_fall":
return {
action: () => animateNodeKnockAndFall(eventState.siteRotY),
};
case "knock":
return {
action: () => animateNodeKnock(eventState.siteRotY),
};
case "site_up":
case "site_down":
case "site_left":
case "site_right":
case "select_level_up":
case "select_level_down":
return {
action: () => updateActiveNode(eventState.node),
delay: 3900,
};
case "change_node":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return {
action: () => updateActiveNode(eventState.node),
};
case "throw_node_media":
case "throw_node_gate":
case "throw_node_sskn":
case "throw_node_tak":
case "throw_node_polytan":
return {
action: () => animateActiveNodeThrow(eventState.siteRotY),
};
case "rip_node_media":
case "rip_node_gate":
case "rip_node_sskn":
case "rip_node_tak":
case "rip_node_polytan":
return {
action: () => animateShrinkAndRip(eventState.siteRotY),
};
}
};
const { action, delay } = { ...dispatchAction(eventState) };
(async () => {
if (delay) await sleep(delay);
if (action) action();
})();
};
export default nodeManager;

View file

@ -1,51 +0,0 @@
import { useStore } from "../../../../store";
import sleep from "../../../../utils/sleep";
const siteManager = (eventState: any) => {
const setRotY = useStore.getState().setSiteRotY;
const setRotX = useStore.getState().setSiteRotX;
const setOldRot = useStore.getState().setOldSiteRot;
const dispatchAction = (eventState: any) => {
switch (eventState.event) {
case "throw_node_media":
case "rip_node_media":
return {
action: () => setOldRot([0, eventState.siteRotY, 0]),
};
case "site_left":
case "site_right":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return {
action: async () => {
setRotY(eventState.siteRotY);
},
delay: 1100,
};
case "pause_game":
return {
action: () => {
setRotX(Math.PI / 2);
},
delay: 3600,
};
case "pause_exit_select":
case "pause_change_select":
return {
action: () => setRotX(0),
};
}
};
const { action, delay } = { ...dispatchAction(eventState) };
if (action)
(async () => {
if (delay) await sleep(delay);
action();
})();
};
export default siteManager;

View file

@ -1,80 +0,0 @@
import { useStore } from "../../../store";
const mediaManager = (eventState: any) => {
const toggleSide = useStore.getState().toggleMediaSide;
const setLeftComponentMatrixIdx = useStore.getState()
.setMediaLeftComponentMatrixIdx;
const setWordSelected = useStore.getState().setWordSelected;
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;
}
};
const dispatchAction = (eventState: {
event: string;
leftSideComponentIdx: 0 | 1;
rightSideComponentIdx: 0 | 1 | 2;
wordPosStateIdx: number;
}) => {
switch (eventState.event) {
case "media_rightside_down":
case "media_rightside_up":
return {
action: () =>
updateRightSide(
eventState.rightSideComponentIdx,
eventState.wordPosStateIdx
),
};
case "media_leftside_down":
case "media_leftside_up":
return {
action: () =>
setLeftComponentMatrixIdx(eventState.leftSideComponentIdx),
};
case "media_leftside_right":
case "media_rightside_left":
return {
action: () => toggleSide(),
};
case "media_play_select":
return { action: () => playMedia() };
case "media_exit_select":
return { action: () => exitMedia() };
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return {
action: () => {
exitMedia();
setWordSelected(true);
},
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default mediaManager;

View file

@ -1,101 +0,0 @@
import { useStore } from "../../store";
import { NodeDataType } from "../../components/MainScene/Site";
import sleep from "../../utils/sleep";
const progressManager = (eventState: any) => {
const updateNodeViewed = useStore.getState().setNodeViewed;
const setPolytanPartUnlocked = useStore.getState().setPolytanPartUnlocked;
const incrementGateLvl = useStore.getState().incrementGateLvl;
const incrementSSknLvl = useStore.getState().incrementSSknLvl;
const nodesThatTurnInvisibleAfterWatching = ["SSkn", "GaTE", "P2"];
const dispatchAction = (eventState: {
event: string;
bodyPart: string;
node: NodeDataType;
}) => {
switch (eventState.event) {
case "throw_node_tak":
case "rip_node_tak":
return {
action: () =>
updateNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: Number(
!nodesThatTurnInvisibleAfterWatching.some((node) =>
eventState.node.node_name.includes(node)
)
),
}),
delay: 8000,
};
case "rip_node_gate":
case "throw_node_gate":
return {
action: () => {
updateNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: Number(
!nodesThatTurnInvisibleAfterWatching.some((node) =>
eventState.node.node_name.includes(node)
)
),
});
incrementGateLvl();
},
};
case "throw_node_polytan":
case "rip_node_polytan":
return {
action: () => {
updateNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: Number(
!nodesThatTurnInvisibleAfterWatching.some((node) =>
eventState.node.node_name.includes(node)
)
),
});
setPolytanPartUnlocked(eventState.bodyPart);
},
};
case "media_play_select":
return {
action: () =>
updateNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: Number(
!nodesThatTurnInvisibleAfterWatching.some((node) =>
eventState.node.node_name.includes(node)
)
),
}),
};
case "sskn_ok_select":
return {
action: () => {
updateNodeViewed(eventState.node.node_name, {
is_viewed: 1,
is_visible: Number(
!nodesThatTurnInvisibleAfterWatching.some((node) =>
eventState.node.node_name.includes(node)
)
),
});
incrementSSknLvl();
},
};
}
};
const { action, delay } = { ...dispatchAction(eventState) };
if (action)
(async () => {
if (delay) await sleep(delay);
action();
})();
};
export default progressManager;

View file

@ -1,44 +0,0 @@
import { useStore } from "../../store";
import sleep from "../../utils/sleep";
const promptManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setPromptComponentMatrixIdx;
const setPromptVisible = useStore.getState().setPromptVisible;
const exitAndResetPrompt = () => {
setPromptVisible(false);
setComponentMatrixIdx(1);
};
const dispatchAction = (eventState: { event: string; scene: string }) => {
switch (eventState.event) {
case "display_prompt": {
return { action: () => setPromptVisible(true) };
}
case "prompt_right":
return {
action: () => setComponentMatrixIdx(1),
};
case "prompt_left":
return { action: () => setComponentMatrixIdx(0) };
case "pause_change_select":
return { action: () => exitAndResetPrompt() };
case "exit_prompt":
case "load_data_no":
return { action: () => exitAndResetPrompt() };
case "main_menu_load_data_select":
return {
action: async () => {
await sleep(500);
setPromptVisible(true);
},
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default promptManager;

View file

@ -1,103 +0,0 @@
import { useStore } from "../../store";
import sleep from "../../utils/sleep";
const sceneManager = (eventState: any) => {
const dispatchAction = (eventState: { event: string; scene: string }) => {
switch (eventState.event) {
case "throw_node_sskn":
case "rip_node_sskn":
return {
action: () => {
useStore.setState({
currentScene: eventState.scene,
intro: false,
ssknComponentMatrixIdx: 0,
ssknLoading: false,
});
},
delay: eventState.event === "throw_node_sskn" ? 3450 : 6000,
};
case "throw_node_media":
case "rip_node_media":
return {
action: () => {
useStore.setState({
currentScene: eventState.scene,
intro: false,
mediaWordPosStateIdx: 1,
mediaComponentMatrixIndices: {
sideIdx: 0,
leftSideIdx: 0,
rightSideIdx: 0,
},
});
},
delay: eventState.event === "throw_node_media" ? 3450 : 6000,
};
case "throw_node_gate":
case "throw_node_tak":
case "throw_node_polytan":
return {
action: () => {
useStore.setState({ currentScene: eventState.scene, intro: false });
},
delay: 3450,
};
case "rip_node_gate":
case "rip_node_tak":
case "rip_node_polytan":
return {
action: () => {
useStore.setState({ currentScene: eventState.scene, intro: false });
},
delay: 6000,
};
case "media_exit_select":
case "sskn_cancel_select":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
case "word_node_not_found":
return {
action: () =>
useStore.setState({ currentScene: "main", intro: false }),
};
case "sskn_ok_select":
return {
action: () => {
useStore.setState({ currentScene: "main", intro: false });
},
delay: 6000,
};
case "pause_change_select":
case "end_continue_select":
return {
action: () =>
useStore.setState({ currentScene: "change_disc", intro: true }),
};
case "play_idle_media":
return {
action: () =>
useStore.setState({ currentScene: "idle_media", intro: false }),
};
case "start_new_game":
return {
action: () => useStore.setState({ currentScene: "main" }),
};
case "end_end_select":
return {
action: () => useStore.setState({ currentScene: "boot" }),
};
}
};
const { action, delay } = { ...dispatchAction(eventState) };
if (action)
(async () => {
if (delay) await sleep(delay);
action();
})();
};
export default sceneManager;

View file

@ -1,179 +0,0 @@
import { playAudio } from "../../store";
import * as audio from "../../static/sfx";
import sleep from "../../utils/sleep";
const soundManager = (eventState: any) => {
const dispatchAction = (eventState: { event: string; scene: string }) => {
switch (eventState.event) {
case "knock_and_fall":
return {
action: async () => {
await sleep(1200);
playAudio(audio.sound14);
await sleep(1100);
playAudio(audio.sound19);
await sleep(850);
playAudio(audio.sound33);
},
};
case "knock":
return {
action: async () => {
await sleep(1200);
playAudio(audio.sound18);
},
};
case "touch_and_scare":
return {
action: async () => {
await sleep(2400);
playAudio(audio.sound17);
await sleep(750);
playAudio(audio.sound33);
},
};
case "throw_node_media":
case "throw_node_gate":
case "throw_node_sskn":
case "throw_node_tak":
case "throw_node_polytan":
return {
action: async () => {
playAudio(audio.sound0);
await sleep(1600);
playAudio(audio.sound12);
await sleep(1200);
playAudio(audio.sound13);
playAudio(audio.sound14);
},
};
case "rip_node_media":
case "rip_node_gate":
case "rip_node_sskn":
case "rip_node_tak":
case "rip_node_polytan":
return {
action: async () => {
playAudio(audio.sound0);
await sleep(1600);
playAudio(audio.sound12);
await sleep(2400);
playAudio(audio.sound15);
playAudio(audio.sound13);
},
};
case "update_player_name":
case "update_player_name_denied":
case "main_menu_authorize_user_select":
case "main_menu_load_data_select":
case "show_permission_denied":
case "pause_about_select":
case "display_prompt":
case "pause_exit_select":
case "end_continue_select":
case "end_end_select":
return {
action: () => playAudio(audio.sound0),
};
case "site_left":
case "site_right":
return {
action: async () => {
await sleep(1100);
playAudio(audio.sound6);
playAudio(audio.sound34);
},
};
case "pause_game":
return {
action: async () => {
playAudio(audio.sound7);
await sleep(3400);
playAudio(audio.sound23);
},
};
case "select_level_up":
case "select_level_down":
return {
action: async () => {
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
await sleep(1400);
playAudio(audio.sound8);
},
};
case "site_up":
case "site_down":
return {
action: async () => {
playAudio(audio.sound13);
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
await sleep(1400);
playAudio(audio.sound8);
},
};
case "main_menu_down":
case "main_menu_up":
case "prompt_left":
case "prompt_right":
case "change_node":
case "toggle_level_selection":
case "level_selection_back":
case "pause_up":
case "pause_down":
case "media_leftside_down":
case "media_leftside_up":
case "media_rightside_down":
case "media_rightside_up":
case "end_selection_up":
case "end_selection_down":
return {
action: () => playAudio(audio.sound1),
};
case "authorize_user_back":
case "remove_last_char":
case "load_data_no":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
case "media_exit_select":
return {
action: () => playAudio(audio.sound29),
};
case "load_data_yes":
case "exit_prompt":
case "pause_save_select":
case "pause_load_select":
case "pause_change_select":
return {
action: () => playAudio(audio.sound28),
};
case "word_node_not_found":
return {
action: () => playAudio(audio.sound30),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default soundManager;

View file

@ -1,31 +0,0 @@
import { useStore } from "../../../store";
const ssknManager = (eventState: any) => {
const toggleComponentMatrixIdx = useStore.getState()
.toggleSSknComponentMatrixIdx;
const setSSknLoading = useStore.getState().setSSknLoading;
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "sskn_ok_down":
case "sskn_cancel_up":
return {
action: () => toggleComponentMatrixIdx(),
};
case "sskn_ok_select":
return {
action: () => setSSknLoading(true),
};
case "sskn_cancel_select":
return {
action: () => setSSknLoading(false),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) action();
};
export default ssknManager;

View file

@ -1743,31 +1743,31 @@
"is_viewed": 0,
"is_visible": 1
},
"SSkn01": {
"Sskn01": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn02": {
"Sskn02": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn03": {
"Sskn03": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn04": {
"Sskn04": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn04#": {
"Sskn04#": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn05": {
"Sskn05": {
"is_viewed": 0,
"is_visible": 1
},
"SSkn06": {
"Sskn06": {
"is_viewed": 0,
"is_visible": 1
},

View file

@ -1644,7 +1644,7 @@
"3": "-1"
},
"media_file": "INS01.STR",
"node_name": "SSkn01",
"node_name": "Sskn01",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@ -2748,7 +2748,7 @@
"3": "-1"
},
"media_file": "INS02.STR",
"node_name": "SSkn02",
"node_name": "Sskn02",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@ -4892,7 +4892,7 @@
"3": "-1"
},
"media_file": "INS03.STR",
"node_name": "SSkn03",
"node_name": "Sskn03",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@ -7302,7 +7302,7 @@
"3": "-1"
},
"media_file": "INS04.STR",
"node_name": "SSkn04",
"node_name": "Sskn04",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",

View file

@ -8,7 +8,7 @@
"3": "-1"
},
"media_file": "INS05.STR",
"node_name": "SSkn04#",
"node_name": "Sskn04#",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",
@ -1510,7 +1510,7 @@
"3": "-1"
},
"media_file": "INS06.STR",
"node_name": "SSkn05",
"node_name": "Sskn05",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",
@ -2968,7 +2968,7 @@
"3": "-1"
},
"media_file": "INS07.STR",
"node_name": "SSkn06",
"node_name": "Sskn06",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",

View file

@ -3,13 +3,13 @@ import { useStore } from "../store";
const ChangeDiscScene = () => {
const setScene = useStore((state) => state.setScene);
const currentSite = useStore((state) => state.activeSite);
const activeSite = useStore((state) => state.activeSite);
useEffect(() => {
if (currentSite === "a") {
if (activeSite === "a") {
document.getElementsByTagName("canvas")[0].className =
"change-disc-scene-a-background";
} else if (currentSite === "b") {
} else if (activeSite === "b") {
document.getElementsByTagName("canvas")[0].className =
"change-disc-scene-b-background";
}
@ -20,7 +20,7 @@ const ChangeDiscScene = () => {
document.getElementsByTagName("canvas")[0].className =
"main-scene-background";
};
}, [currentSite, setScene]);
}, [activeSite, setScene]);
return <></>;
};

View file

@ -9,9 +9,16 @@ const GateScene = () => {
const gateLvl = useStore((state) => state.gateLvl);
const [introAnim, setIntroAnim] = useState(true);
const activeNodeName = useStore((state) => state.activeNode.node_name);
const setNodeViewed = useStore((state) => state.setNodeViewed);
useEffect(() => {
setNodeViewed(activeNodeName, {
is_viewed: 1,
is_visible: 0,
});
setTimeout(() => setIntroAnim(false), 2500);
}, []);
}, [activeNodeName, setNodeViewed]);
return (
<perspectiveCamera position-z={3}>

View file

@ -17,11 +17,13 @@ import NotFound from "../components/MainScene/NotFound";
import PausePopUps from "../components/MainScene/PauseSubscene/PausePopUps";
import * as audio from "../static/sfx";
import Loading from "../components/Loading";
import usePrevious from "../hooks/usePrevious";
const MainScene = () => {
const intro = useStore((state) => state.intro);
const [paused, setPaused] = useState(false);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ subscene });
const wordSelected = useStore((state) => state.wordSelected);
const setWordSelected = useStore((state) => state.setWordSelected);
@ -29,10 +31,10 @@ const MainScene = () => {
useEffect(() => {
if (subscene === "pause") {
setTimeout(() => setPaused(true), 3400);
} else {
} else if (prevData?.subscene === "pause" && subscene === "site") {
setPaused(false);
}
}, [subscene]);
}, [prevData?.subscene, subscene]);
useEffect(() => {
if (wordSelected) {

View file

@ -13,6 +13,7 @@ import Loading from "../components/Loading";
const MediaScene = () => {
const percentageElapsed = useStore((state) => state.mediaPercentageElapsed);
const setInputCooldown = useStore((state) => state.setInputCooldown);
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
const activeNode = useStore((state) => state.activeNode);
@ -70,7 +71,8 @@ const MediaScene = () => {
useEffect(() => {
setLoaded(true);
}, []);
setTimeout(() => setInputCooldown(false), 1000);
}, [setInputCooldown]);
return (
<perspectiveCamera position-z={3}>

View file

@ -1,12 +1,37 @@
import React from "react";
import React, { useEffect } from "react";
import PolytanBear from "../components/PolytanScene/PolytanBear";
import PolytanBackground from "../components/PolytanScene/PolytanBackground";
import { useStore } from "../store";
const PolytanScene = () => {
const unlockedParts = useStore(
(state) => state.polytanUnlockedParts
);
const unlockedParts = useStore((state) => state.polytanUnlockedParts);
const setNodeViewed = useStore((state) => state.setNodeViewed);
const setPolytanPartUnlocked = useStore.getState().setPolytanPartUnlocked;
const activeNodeName = useStore((state) => state.activeNode.node_name);
useEffect(() => {
setNodeViewed(activeNodeName, {
is_viewed: 1,
is_visible: 0,
});
const bodyPart = (() => {
switch (parseInt(activeNodeName.slice(-1))) {
case 6:
return "head";
case 5:
return "rightArm";
case 4:
return "leftArm";
case 3:
return "rightLeg";
case 2:
return "leftLeg";
case 1:
return "body";
}
})();
if (bodyPart) setPolytanPartUnlocked(bodyPart);
}, [activeNodeName, setNodeViewed, setPolytanPartUnlocked]);
return (
<perspectiveCamera>

View file

@ -1,16 +0,0 @@
import React from "react";
import SSknIcon from "../components/SSknScene/SSknIcon";
import SSknBackground from "../components/SSknScene/SSknBackground";
import SSknHUD from "../components/SSknScene/SSknHUD";
const SSknScene = () => {
return (
<>
<SSknBackground />
<SSknIcon />
<SSknHUD />
</>
);
};
export default SSknScene;

14
src/scenes/SsknScene.tsx Normal file
View file

@ -0,0 +1,14 @@
import React from "react";
import SsknIcon from "../components/SsknScene/SsknIcon";
import SsknBackground from "../components/SsknScene/SsknBackground";
import SsknHUD from "../components/SsknScene/SsknHUD";
const SsknScene = () => (
<>
<SsknBackground />
<SsknIcon />
<SsknHUD />
</>
);
export default SsknScene;

View file

@ -6,14 +6,22 @@ const TaKScene = () => {
const setScene = useStore((state) => state.setScene);
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
const nodeMedia = useStore((state) => state.activeNode.media_file);
const nodeName = useStore((state) => state.activeNode.node_name);
const activeNode = useStore((state) => state.activeNode);
const [isIntro, setIsIntro] = useState(true);
const [isOutro, setIsOutro] = useState(false);
const percentageElapsed = useStore((state) => state.mediaPercentageElapsed);
const setNodeViewed = useStore((state) => state.setNodeViewed);
useEffect(() => {
setNodeViewed(activeNode.node_name, {
is_viewed: 1,
is_visible: 1,
});
}, [activeNode.node_name, setNodeViewed]);
useEffect(() => {
if (percentageElapsed === 100) {
setIsOutro(true);
@ -30,30 +38,34 @@ const TaKScene = () => {
if (mediaElement) {
setAudioAnalyser(createAudioAnalyser());
mediaElement.currentTime = 0;
import("../static/webvtt/" + nodeName + ".vtt")
import("../static/webvtt/" + activeNode.node_name + ".vtt")
.then((vtt) => {
if (vtt) trackElement.src = vtt.default;
})
// some entries have no spoken words, so the file doesnt exist. we catch that here.
.catch((e) => console.log(e));
if (nodeMedia.includes("XA")) {
import("../static/audio/" + nodeMedia + ".ogg").then((media) => {
mediaElement.src = media.default;
mediaElement.load();
mediaElement.play();
});
if (activeNode.media_file.includes("XA")) {
import("../static/audio/" + activeNode.media_file + ".ogg").then(
(media) => {
mediaElement.src = media.default;
mediaElement.load();
mediaElement.play();
}
);
} else {
import("../static/movie/" + nodeMedia + "[0].webm").then((media) => {
mediaElement.src = media.default;
mediaElement.load();
mediaElement.play();
});
import("../static/movie/" + activeNode.media_file + "[0].webm").then(
(media) => {
mediaElement.src = media.default;
mediaElement.load();
mediaElement.play();
}
);
}
setIsIntro(false);
}
}, 3800);
}, [nodeMedia, nodeName, setAudioAnalyser]);
}, [activeNode.media_file, activeNode.node_name, setAudioAnalyser]);
return <LainSpeak intro={isIntro} outro={isOutro} />;
};

View file

@ -2,20 +2,22 @@ import create from "zustand";
import { combine } from "zustand/middleware";
import * as THREE from "three";
import game_progress from "./resources/initial_progress.json";
import { NodeDataType } from "./components/MainScene/Site";
import { NodeData } from "./components/MainScene/Site";
import { getNodeById } from "./utils/node-utils";
import site_a from "./resources/site_a.json";
export type GameProgress = typeof game_progress;
type State = {
currentScene: string;
gameProgress: typeof game_progress;
gameProgress: GameProgress;
mainSubscene: string;
intro: boolean;
activeNode: NodeDataType;
activeNode: NodeData;
activeNodePos: number[];
activeNodeRot: number[];
activeNodeAttributes: {
@ -41,13 +43,11 @@ type State = {
selectedLevel: number;
// end scene
endComponentMatrix: ["end", "continue"];
endComponentMatrixIdx: 0 | 1;
activeEndComponent: "end" | "continue";
endSceneSelectionVisible: boolean;
// pause
pauseComponentMatrix: ["load", "about", "change", "save", "exit"];
pauseComponentMatrixIdx: number;
activePauseComponent: "load" | "about" | "change" | "save" | "exit";
pauseExitAnimation: boolean;
showingAbout: boolean;
permissionDenied: boolean;
@ -55,12 +55,13 @@ type State = {
// media/media scene
audioAnalyser: any;
mediaPercentageElapsed: number;
mediaComponentMatrix: [["play", "exit"], ["fstWord", "sndWord", "thirdWord"]];
mediaComponentMatrixIndices: {
sideIdx: 0 | 1;
leftSideIdx: 0 | 1;
rightSideIdx: 0 | 1 | 2;
currentMediaSide: "left" | "right";
activeMediaComponent: "play" | "exit" | "fstWord" | "sndWord" | "thirdWord";
lastActiveMediaComponents: {
left: "play" | "exit";
right: "fstWord" | "sndWord" | "thirdWord";
};
mediaWordPosStateIdx: number;
wordSelected: boolean;
@ -71,8 +72,7 @@ type State = {
idleNodeName: string | undefined;
// sskn scene
ssknComponentMatrix: ["ok", "cancel"];
ssknComponentMatrixIdx: 0 | 1;
activeSsknComponent: "ok" | "cancel";
ssknLoading: boolean;
ssknLvl: number;
@ -93,15 +93,13 @@ type State = {
playerName: string;
// boot scene
mainMenuComponentMatrix: ["authorize_user", "load_data"];
mainMenuComponentMatrixIdx: 0 | 1;
activeMainMenuComponent: "authorize_user" | "load_data";
authorizeUserLetterIdx: number;
bootSubscene: "main_menu" | "load_data" | "authorize_user";
// prompt
promptVisible: boolean;
promptComponentMatrix: ["yes", "no"];
promptComponentMatrixIdx: 1 | 0;
activePromptComponent: "yes" | "no";
// status notifiers
loadSuccessful: boolean | undefined;
@ -110,23 +108,25 @@ type State = {
// save state
siteSaveState: {
a: {
activeNode: NodeDataType;
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
b: {
activeNode: NodeDataType;
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
};
inputCooldown: boolean;
};
export const useStore = create(
combine(
{
// scene data
currentScene: "main",
currentScene: "boot",
// game progress
gameProgress: game_progress,
@ -169,13 +169,11 @@ export const useStore = create(
selectedLevel: 4,
// end scene
endComponentMatrix: ["end", "continue"],
endComponentMatrixIdx: 0,
activeEndComponent: "end",
endSceneSelectionVisible: false,
// pause
pauseComponentMatrix: ["load", "about", "change", "save", "exit"],
pauseComponentMatrixIdx: 2,
activePauseComponent: "change",
pauseExitAnimation: false,
showingAbout: false,
permissionDenied: false,
@ -183,17 +181,12 @@ export const useStore = create(
// media scene
audioAnalyser: undefined,
mediaPercentageElapsed: 0,
mediaComponentMatrix: [
["play", "exit"],
["fstWord", "sndWord", "thirdWord"],
],
mediaComponentMatrixIndices: {
// 0 or 1 (left/right)
sideIdx: 0,
// 0 or 1 ("play" or "exit")
leftSideIdx: 0,
// 0 or 1 or 2 ("fstWord", "sndWord" or "thirdWord")
rightSideIdx: 0,
currentMediaSide: "left",
activeMediaComponent: "play",
lastActiveMediaComponents: {
left: "play",
right: "fstWord",
},
mediaWordPosStateIdx: 1,
wordSelected: false,
@ -206,8 +199,7 @@ export const useStore = create(
idleImages: site_a["00"]["0000"].image_table_indices,
// sskn scene
ssknComponentMatrix: ["ok", "cancel"],
ssknComponentMatrixIdx: 0,
activeSsknComponent: "ok",
ssknLoading: false,
ssknLvl: 0,
@ -228,15 +220,13 @@ export const useStore = create(
playerName: "アイウエオ",
// boot scene
mainMenuComponentMatrix: ["authorize_user", "load_data"],
mainMenuComponentMatrixIdx: 0,
activeMainMenuComponent: "authorize_user",
authorizeUserLetterIdx: 0,
bootSubscene: "main_menu",
// prompt
promptVisible: false,
promptComponentMatrix: ["yes", "no"],
promptComponentMatrixIdx: 1,
activePromptComponent: "no",
// status notifiers
loadSuccessful: undefined,
@ -261,6 +251,8 @@ export const useStore = create(
activeLevel: "04",
},
},
inputCooldown: false,
} as State,
(set) => ({
// scene data setters
@ -273,7 +265,7 @@ export const useStore = create(
setIntro: (to: boolean) => set(() => ({ intro: to })),
// node setters
setNode: (to: NodeDataType) => set(() => ({ activeNode: to })),
setNode: (to: NodeData) => set(() => ({ activeNode: to })),
setNodePos: (to: number[]) => set(() => ({ activeNodePos: to })),
setNodeRot: (to: number[]) => set(() => ({ activeNodeRot: to })),
setNodeAttributes: (
@ -314,14 +306,10 @@ export const useStore = create(
setSelectedLevel: (to: number) => set(() => ({ selectedLevel: to })),
// end scene setters
setEndComponentMatrixIdx: (to: 0 | 1) =>
set(() => ({ endComponentMatrixIdx: to })),
setEndSceneSelectionVisible: (to: boolean) =>
set(() => ({ endSceneSelectionVisible: to })),
// pause setters
setPauseComponentMatrixIdx: (to: number) =>
set(() => ({ pauseComponentMatrixIdx: to })),
setPauseExitAnimation: (to: boolean) =>
set(() => ({ pauseExitAnimation: to })),
setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })),
@ -330,33 +318,33 @@ export const useStore = create(
// media scene setters
setAudioAnalyser: (to: any) => set(() => ({ audioAnalyser: to })),
toggleMediaSide: () =>
set((state) => ({
mediaComponentMatrixIndices: {
...state.mediaComponentMatrixIndices,
sideIdx: Number(!state.mediaComponentMatrixIndices.sideIdx) as
| 0
| 1,
},
})),
setMediaLeftComponentMatrixIdx: (to: 0 | 1) =>
set((state) => ({
mediaComponentMatrixIndices: {
...state.mediaComponentMatrixIndices,
leftSideIdx: to,
},
})),
updateRightSide: (matrixIdx: 0 | 1 | 2, wordPosIdx: number) =>
set((state) => ({
mediaComponentMatrixIndices: {
...state.mediaComponentMatrixIndices,
rightSideIdx: matrixIdx,
},
mediaWordPosStateIdx: wordPosIdx,
})),
setPercentageElapsed: (to: number) =>
set(() => ({ mediaPercentageElapsed: to })),
setWordSelected: (to: boolean) => set(() => ({ wordSelected: to })),
updateLeftSide: (
newActiveComponent: "fstWord" | "sndWord" | "thirdWord",
lastActiveComponent: "exit" | "play"
) =>
set((state) => ({
activeMediaComponent: newActiveComponent,
lastActiveMediaComponents: {
...state.lastActiveMediaComponents,
left: lastActiveComponent,
},
currentMediaSide: "right",
})),
updateRightSide: (
newActiveComponent: "play" | "exit",
lastActiveComponent: "fstWord" | "sndWord" | "thirdWord"
) =>
set((state) => ({
activeMediaComponent: newActiveComponent,
lastActiveMediaComponents: {
...state.lastActiveMediaComponents,
right: lastActiveComponent,
},
currentMediaSide: "left",
})),
// idle media setters
setIdleStarting: (to: boolean) => set(() => ({ idleStarting: to })),
@ -379,15 +367,6 @@ export const useStore = create(
[bodyPart]: true,
},
})),
// sskn scene setters
toggleSSknComponentMatrixIdx: () =>
set((state) => ({
ssknComponentMatrixIdx: Number(!state.ssknComponentMatrixIdx) as
| 0
| 1,
})),
setSSknLoading: (to: boolean) => set(() => ({ ssknLoading: to })),
incrementSSknLvl: () => set((state) => ({ ssknLvl: state.ssknLvl + 1 })),
// gate scene setters
incrementGateLvl: () => set((state) => ({ gateLvl: state.gateLvl + 1 })),
@ -398,23 +377,15 @@ export const useStore = create(
// boot scene setters
setBootSubscene: (to: "load_data" | "authorize_user" | "main_menu") =>
set(() => ({ bootSubscene: to })),
setMainMenuComponentMatrixIdx: (to: 0 | 1) =>
set(() => ({
mainMenuComponentMatrixIdx: to,
})),
setAuthorizeUserLetterIdx: (to: number) =>
set(() => ({ authorizeUserLetterIdx: to })),
// prompt setters
setPromptVisible: (to: boolean) => set(() => ({ promptVisible: to })),
setPromptComponentMatrixIdx: (to: 1 | 0) =>
set(() => ({ promptComponentMatrixIdx: to })),
// site state setters
setSiteSaveState: (
site: string,
to: {
activeNode: NodeDataType;
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
}
@ -432,6 +403,30 @@ export const useStore = create(
activeLevel: stateToLoad.activeLevel,
};
}),
changeSite: (to: "a" | "b") =>
set((state) => {
const newState = state.siteSaveState[to];
return {
currentScene: "change_disc",
promptVisible: false,
activePromptComponent: "no",
mainSubscene: "site",
// load new state
activeSite: to,
activeNode: newState.activeNode,
siteRot: newState.siteRot,
activeLevel: newState.activeLevel,
// save current state
siteSaveState: {
...state.siteSaveState,
[to === "a" ? "b" : "a"]: {
activeNode: state.activeNode,
siteRot: [0, state.siteRot[1], 0],
activeLevel: state.activeLevel,
},
},
};
}),
// status notifier setters
setSaveSuccessful: (to: boolean | undefined) =>
@ -450,6 +445,10 @@ export const useStore = create(
[nodeName]: to,
},
})),
setInputCooldown: (to: boolean) => set(() => ({ inputCooldown: to })),
incrementSsknLvl: () => set((state) => ({ ssknLvl: state.ssknLvl + 1 })),
})
)
);
@ -464,28 +463,46 @@ export const getSiteState = (site: "a" | "b") => {
};
};
type PromptContext = {
activePromptComponent: "yes" | "no";
promptVisible: boolean;
};
const getPromptContext = () => {
const state = useStore.getState();
return {
promptVisible: state.promptVisible,
activePromptComponent:
state.promptComponentMatrix[state.promptComponentMatrixIdx],
activePromptComponent: state.activePromptComponent,
};
};
export const getMainSceneContext = () => {
export interface MainSceneContext extends PromptContext {
keyPress: string;
ssknLvl: number;
activeNode: NodeData;
showingAbout: boolean;
level: number;
activePauseComponent: "load" | "about" | "change" | "save" | "exit";
gameProgress: GameProgress;
gateLvl: number;
subscene: string;
siteRotY: number;
activeSite: "a" | "b";
selectedLevel: number;
}
export const getMainSceneContext = (keyPress: string): MainSceneContext => {
const state = useStore.getState();
return {
...getPromptContext(),
keyPress: keyPress,
subscene: state.mainSubscene,
selectedLevel: state.selectedLevel,
pauseMatrixIdx: state.pauseComponentMatrixIdx,
activePauseComponent:
state.pauseComponentMatrix[state.pauseComponentMatrixIdx],
activePauseComponent: state.activePauseComponent,
gameProgress: state.gameProgress,
currentSite: state.activeSite,
activeSite: state.activeSite,
siteRotY: state.siteRot[1],
activeNode: state.activeNode,
level: parseInt(state.activeLevel),
@ -495,26 +512,43 @@ export const getMainSceneContext = () => {
};
};
export const getSSknSceneContext = () => {
export type SsknSceneContext = {
keyPress: string;
activeSsknComponent: "ok" | "cancel";
activeNode: NodeData;
};
export const getSsknSceneContext = (keyPress: string): SsknSceneContext => {
const state = useStore.getState();
return {
activeSSknComponent:
state.ssknComponentMatrix[state.ssknComponentMatrixIdx],
keyPress: keyPress,
activeSsknComponent: state.activeSsknComponent,
activeNode: state.activeNode,
};
};
export const getMediaSceneContext = () => {
export type MediaSceneContext = {
keyPress: string;
wordPosStateIdx: number;
currentMediaSide: "left" | "right";
activeMediaComponent: "play" | "exit" | "fstWord" | "sndWord" | "thirdWord";
activeNode: NodeData;
gameProgress: GameProgress;
lastActiveMediaComponents: {
left: "play" | "exit";
right: "fstWord" | "sndWord" | "thirdWord";
};
activeSite: "a" | "b";
};
export const getMediaSceneContext = (keyPress: string): MediaSceneContext => {
const state = useStore.getState();
return {
activeMediaComponent:
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
],
rightSideComponentIdx: state.mediaComponentMatrixIndices.rightSideIdx,
keyPress: keyPress,
lastActiveMediaComponents: state.lastActiveMediaComponents,
currentMediaSide: state.currentMediaSide,
activeMediaComponent: state.activeMediaComponent,
wordPosStateIdx: state.mediaWordPosStateIdx,
activeNode: state.activeNode,
activeSite: state.activeSite,
@ -522,24 +556,39 @@ export const getMediaSceneContext = () => {
};
};
export const getBootSceneContext = () => {
export interface BootSceneContext extends PromptContext {
keyPress: string;
playerName: string;
subscene: "main_menu" | "load_data" | "authorize_user";
activeMainMenuComponent: "load_data" | "authorize_user";
authorizeUserLetterIdx: number;
}
export const getBootSceneContext = (keyPress: string): BootSceneContext => {
const state = useStore.getState();
return {
...getPromptContext(),
keyPress: keyPress,
playerName: state.playerName,
subscene: state.bootSubscene,
activeMainMenuComponent:
state.mainMenuComponentMatrix[state.mainMenuComponentMatrixIdx],
activeMainMenuComponent: state.activeMainMenuComponent,
authorizeUserLetterIdx: state.authorizeUserLetterIdx,
};
};
export const getEndSceneContext = () => {
export type EndSceneContext = {
keyPress: string;
activeEndComponent: "end" | "continue";
selectionVisible: boolean;
};
export const getEndSceneContext = (keyPress: string): EndSceneContext => {
const state = useStore.getState();
return {
activeEndComponent: state.endComponentMatrix[state.endComponentMatrixIdx],
keyPress: keyPress,
activeEndComponent: state.activeEndComponent,
selectionVisible: state.endSceneSelectionVisible,
};
};
@ -561,3 +610,19 @@ export const createAudioAnalyser = () => {
return new THREE.AudioAnalyser(audio, 2048);
};
export const getSceneResetValues = (scene: string) => {
switch (scene) {
case "media":
return {
mediaWordPosStateIdx: 1,
mediaComponentMatrixIndices: {
sideIdx: 0,
leftSideIdx: 0,
rightSideIdx: 0,
},
};
case "sskn":
return { ssknComponentMatrixIdx: 0, ssknLoading: false };
}
};

View file

@ -1,6 +1,6 @@
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
import { SiteType } from "../components/MainScene/Site";
import { SiteData } from "../components/MainScene/Site";
import { useStore } from "../store";
export const getRandomIdleMedia = () => {
@ -58,7 +58,7 @@ export const getRandomIdleMedia = () => {
const site = useStore.getState().activeSite;
const siteData: SiteType = site === "a" ? site_a : site_b;
const siteData: SiteData = site === "a" ? site_a : site_b;
const idleNodes = site === "a" ? siteAIdleNodes : siteBIdleNodes;
if (Math.random() < 0.5) {

View file

@ -1,12 +1,12 @@
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
import node_matrices from "../resources/node_matrices.json";
import { NodeDataType, SiteType } from "../components/MainScene/Site";
import { NodeData, SiteData } from "../components/MainScene/Site";
import { isNodeVisible } from "./node-utils";
export const findNodeFromWord = (
wordLabel: string,
activeNode: NodeDataType,
activeNode: NodeData,
site: "a" | "b",
gameProgress: any
) => {
@ -23,7 +23,7 @@ export const findNodeFromWord = (
const wordToFind = activeNode.words[labelToIdx!];
const siteData: SiteType = site === "a" ? site_a : site_b;
const siteData: SiteData = site === "a" ? site_a : site_b;
const nodesWithSameWords = Object.values(siteData)
.flatMap((level) =>

View file

@ -0,0 +1,131 @@
import { useStore } from "../store";
import sleep from "./sleep";
const setActiveNodePos = useStore.getState().setNodePos;
const setActiveNodeRot = useStore.getState().setNodeRot;
const setActiveNodeAttributes = useStore.getState().setNodeAttributes;
const calculateCoordsBasedOnRotation = (
x: number,
z: number,
rotation: number
) => ({
x: x * Math.cos(rotation) - z * Math.sin(rotation),
z: x * Math.sin(rotation) + z * Math.cos(rotation),
});
export const nodeThrow = (siteRotY: number) => {
(async () => {
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(1.55, 0.2, siteRotY);
const fourthCoordSet = calculateCoordsBasedOnRotation(0, 2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(800);
setActiveNodePos([sndCoordSet.x, 0, sndCoordSet.z]);
await sleep(1800);
setActiveNodePos([thirdCoordSet.x, 0, sndCoordSet.z]);
setActiveNodeRot([0, 0, -0.005]);
await sleep(100);
setActiveNodePos([fourthCoordSet.x, 0, fourthCoordSet.z]);
setActiveNodeRot([0, 0, -0.5]);
await sleep(1100);
setActiveNodeRot([0, 0, 0]);
setActiveNodeAttributes(false, "interactedWith");
})();
};
export const nodeKnock = (siteRotY: number) => {
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, -0.6, fstCoordSet.z]);
setTimeout(() => setActiveNodeAttributes(false, "interactedWith"), 2500);
};
export const nodeKnockAndFall = (siteRotY: number) => {
(async () => {
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, -0.6, fstCoordSet.z]);
await sleep(2300);
setActiveNodeAttributes(false, "visible");
await sleep(200);
setActiveNodeAttributes(false, "interactedWith");
await sleep(700);
setActiveNodeAttributes(true, "visible");
})();
};
export const nodeTouchAndScare = (siteRotY: number) => {
(async () => {
const fstCoordSet = calculateCoordsBasedOnRotation(-0.6, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(1200);
setActiveNodeAttributes(true, "exploding");
setActiveNodeAttributes(false, "visible");
await sleep(200);
setActiveNodeAttributes(false, "interactedWith");
setActiveNodeRot([0, 0, 0]);
await sleep(1750);
setActiveNodeAttributes(false, "exploding");
await sleep(350);
setActiveNodeAttributes(true, "visible");
})();
};
export const nodeRip = (siteRotY: number) => {
(async () => {
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(0, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
setActiveNodePos([fstCoordSet.x, 0, fstCoordSet.z]);
await sleep(800);
setActiveNodePos([sndCoordSet.x, 0, sndCoordSet.z]);
await sleep(2000);
setActiveNodePos([thirdCoordSet.x, -0.4, thirdCoordSet.z]);
await sleep(200);
setActiveNodeAttributes(true, "shrinking");
await sleep(200);
setActiveNodePos([thirdCoordSet.x, -1.5, thirdCoordSet.z]);
await sleep(300);
setActiveNodeAttributes(false, "visible");
await sleep(2900);
setActiveNodeAttributes(false, "interactedWith");
setActiveNodeAttributes(false, "shrinking");
setActiveNodeRot([0, 0, 0]);
await sleep(1100);
setActiveNodeAttributes(true, "visible");
})();
};

View file

@ -1,13 +1,13 @@
import { NodeDataType, SiteType } from "../components/MainScene/Site";
import { NodeData, SiteData } from "../components/MainScene/Site";
import node_matrices from "../resources/node_matrices.json";
import game_progress from "../resources/initial_progress.json";
import unlocked_nodes from "../resources/initial_progress.json";
import node_huds from "../resources/node_huds.json";
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
import {GameProgress} from "../store";
export const generateInactiveNodes = (
visibleNodes: SiteType,
visibleNodes: SiteData,
activeLevel: string
) => {
const obj = {};
@ -26,10 +26,10 @@ export const generateInactiveNodes = (
return obj;
};
export const getNodeById = (id: string, currentSite: string) => {
const siteData = currentSite === "a" ? site_a : site_b;
export const getNodeById = (id: string, activeSite: string) => {
const siteData = activeSite === "a" ? site_a : site_b;
const level = id.substr(0, 2);
return (siteData as SiteType)[level][id];
return (siteData as SiteData)[level][id];
};
export const getNodeHud = (nodeMatrixIndices: {
matrixIdx: number;
@ -60,7 +60,7 @@ export const getNodeHud = (nodeMatrixIndices: {
//visible = (global_final_viewcount > 0) && (req_final_viewcount <= global_final_viewcount + 1)
export const isNodeVisible = (
node: NodeDataType,
node: NodeData,
gameProgress: typeof unlocked_nodes
) => {
return node
@ -74,7 +74,7 @@ export const isNodeVisible = (
export const getVisibleNodesMatrix = (
matrixIdx: number,
activeLevel: number,
currentSite: string,
activeSite: string,
gameProgress: any
) => {
const formattedLevel = activeLevel.toString().padStart(2, "0");
@ -84,7 +84,7 @@ export const getVisibleNodesMatrix = (
return currentMatrix.map((row: string[]) =>
row.map((nodePos: string) => {
const nodeId = formattedLevel + nodePos;
if (isNodeVisible(getNodeById(nodeId, currentSite), gameProgress))
if (isNodeVisible(getNodeById(nodeId, activeSite), gameProgress))
return nodeId;
else return undefined;
})
@ -174,8 +174,8 @@ export const findNode = (
}: { matrixIdx: number; rowIdx: number; colIdx: number },
level: number,
currentSite: string,
gameProgress: typeof game_progress,
activeSite: string,
gameProgress: GameProgress,
shouldSearchNext: boolean
) => {
const funcs: {
@ -198,7 +198,7 @@ export const findNode = (
const nodes = getVisibleNodesMatrix(
matrixIdx,
level,
currentSite,
activeSite,
gameProgress
);
@ -237,10 +237,10 @@ export const findNode = (
}
};
export const filterInvisibleNodes = (
siteData: SiteType,
gameProgress: typeof game_progress
siteData: SiteData,
gameProgress: GameProgress
) => {
const visibleNodes: SiteType = {};
const visibleNodes: SiteData = {};
Object.entries(siteData).forEach((level) => {
visibleNodes[level[0]] = {};
Object.entries(level[1]).forEach((node) => {