mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 15:09:05 +00:00
event rewrite done, fixed a lot of stuff, renamed/moved some stuff
This commit is contained in:
parent
7620610097
commit
1d895e64b0
36 changed files with 791 additions and 761 deletions
|
@ -1,4 +1,4 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import React, { memo, useRef, useState } from "react";
|
||||
import middleSpritesheet from "../../static/sprite/end_middle_spritesheet.png";
|
||||
import middleLain from "../../static/sprite/end_middle_lain.png";
|
||||
import circleSpritesheet from "../../static/sprite/end_circle_spritesheet.png";
|
||||
|
@ -10,7 +10,11 @@ import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
|
|||
import { a, useSpring } from "@react-spring/three";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
const EndSelectionScreen = () => {
|
||||
type EndSelectionScreenProps = {
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
const EndSelectionScreen = memo((props: EndSelectionScreenProps) => {
|
||||
const middleSpritesheetTex: any = useLoader(
|
||||
THREE.TextureLoader,
|
||||
middleSpritesheet
|
||||
|
@ -63,7 +67,7 @@ const EndSelectionScreen = () => {
|
|||
const lainOpacity = lainOpacityToggle.to([0, 1], [0, 0.5]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<group visible={props.visible}>
|
||||
<sprite position={[-3.5, 0, -3]} scale={[10, 0.8, 0]}>
|
||||
<spriteMaterial attach="material" map={middleSpritesheetTex} />
|
||||
</sprite>
|
||||
|
@ -93,8 +97,8 @@ const EndSelectionScreen = () => {
|
|||
opacity={lainOpacity}
|
||||
/>
|
||||
</sprite>
|
||||
</>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default EndSelectionScreen;
|
||||
|
|
|
@ -31,13 +31,7 @@ const Images = () => {
|
|||
const textureLoader = useMemo(() => new THREE.TextureLoader(), []);
|
||||
|
||||
useEffect(() => {
|
||||
let images;
|
||||
if (currentScene === "media" || currentScene === "tak") {
|
||||
images = nodeImages;
|
||||
} else if (currentScene === "idle_media") {
|
||||
images = idleNodeImages;
|
||||
}
|
||||
|
||||
const images = currentScene === "idle_media" ? idleNodeImages : nodeImages;
|
||||
if (images) {
|
||||
// checking the length of the img arr doesn't work in some cases
|
||||
// since the amount of images varies from 1 to 3.
|
||||
|
|
|
@ -1,32 +1,23 @@
|
|||
import { useCallback, useEffect, useRef } from "react";
|
||||
import {
|
||||
BootSceneContext,
|
||||
EndSceneContext,
|
||||
getBootSceneContext,
|
||||
getEndSceneContext,
|
||||
getMainSceneContext,
|
||||
getMediaSceneContext,
|
||||
getSsknSceneContext,
|
||||
MainSceneContext,
|
||||
MediaSceneContext,
|
||||
playAudio,
|
||||
SsknSceneContext,
|
||||
useStore,
|
||||
} from "../store";
|
||||
import { getKeyCodeAssociation } from "../utils/keyPressUtils";
|
||||
import { getKeyCodeAssociation } from "../utils/getKey";
|
||||
import handleMediaSceneKeyPress from "../core/scene-keypress-handlers/handleMediaSceneKeyPress";
|
||||
import handleSsknSceneKeyPress from "../core/scene-keypress-handlers/handleSsknSceneKeyPress";
|
||||
import handleMainSceneKeyPress from "../core/scene-keypress-handlers/handleMainSceneKeyPress";
|
||||
import handleBootSceneKeyPress from "../core/scene-keypress-handlers/handleBootSceneKeyPress";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import { getRandomIdleLainAnim } from "../utils/idle-utils";
|
||||
import * as audio from "../static/sfx";
|
||||
import { getRandomIdleLainAnim } from "../helpers/idle-helpers";
|
||||
import * as audio from "../static/audio/sfx";
|
||||
import handleEndSceneKeyPress from "../core/scene-keypress-handlers/handleEndSceneKeyPress";
|
||||
import handleMediaSceneEvent from "../core/scene-event-handlers/handleMediaSceneEvent";
|
||||
import handleSsknSceneEvent from "../core/scene-event-handlers/handleSsknSceneEvent";
|
||||
import handleBootSceneEvent from "../core/scene-event-handlers/handleBootSceneEvent";
|
||||
import handleEndSceneEvent from "../core/scene-event-handlers/handleEndSceneEvent";
|
||||
import handleEvent from "../core/scene-event-handlers/handleEvent";
|
||||
import handleEvent, { GameEvent } from "../core/handleEvent";
|
||||
|
||||
const KeyPressHandler = () => {
|
||||
const scene = useStore((state) => state.currentScene);
|
||||
|
@ -83,9 +74,9 @@ const KeyPressHandler = () => {
|
|||
const now = Date.now();
|
||||
|
||||
if (
|
||||
keyPress
|
||||
// !inputCooldown &&
|
||||
// now > timeSinceLastKeyPress.current + 1500
|
||||
keyPress &&
|
||||
now > timeSinceLastKeyPress.current + inputCooldown &&
|
||||
inputCooldown !== -1
|
||||
) {
|
||||
if (scene === "main") {
|
||||
lainIdleCounter.current = now;
|
||||
|
@ -105,34 +96,31 @@ const KeyPressHandler = () => {
|
|||
contextProvider: getMediaSceneContext,
|
||||
keyPressHandler: handleMediaSceneKeyPress,
|
||||
};
|
||||
// case "sskn":
|
||||
// return {
|
||||
// contextProvider: getSsknSceneContext,
|
||||
// keyPressHandler: handleSsknSceneKeyPress,
|
||||
// eventHandler: handleSsknSceneEvent,
|
||||
// };
|
||||
// case "boot":
|
||||
// return {
|
||||
// contextProvider: getBootSceneContext,
|
||||
// keyPressHandler: handleBootSceneKeyPress,
|
||||
// eventHandler: handleBootSceneEvent,
|
||||
// };
|
||||
// case "end":
|
||||
// return {
|
||||
// contextProvider: getEndSceneContext,
|
||||
// keyPressHandler: handleEndSceneKeyPress,
|
||||
// eventHandler: handleEndSceneEvent,
|
||||
// };
|
||||
// case "gate":
|
||||
// case "polytan":
|
||||
// useStore.setState({ currentScene: "main" });
|
||||
// break;
|
||||
// case "idle_media":
|
||||
// useStore.setState({
|
||||
// currentScene: "main",
|
||||
// idleStarting: false,
|
||||
// });
|
||||
// break;
|
||||
case "sskn":
|
||||
return {
|
||||
contextProvider: getSsknSceneContext,
|
||||
keyPressHandler: handleSsknSceneKeyPress,
|
||||
};
|
||||
case "boot":
|
||||
return {
|
||||
contextProvider: getBootSceneContext,
|
||||
keyPressHandler: handleBootSceneKeyPress,
|
||||
};
|
||||
case "end":
|
||||
return {
|
||||
contextProvider: getEndSceneContext,
|
||||
keyPressHandler: handleEndSceneKeyPress,
|
||||
};
|
||||
case "gate":
|
||||
case "polytan":
|
||||
useStore.setState({ currentScene: "main" });
|
||||
break;
|
||||
case "idle_media":
|
||||
useStore.setState({
|
||||
currentScene: "main",
|
||||
idleStarting: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -140,9 +128,8 @@ const KeyPressHandler = () => {
|
|||
const { contextProvider, keyPressHandler } = sceneFns;
|
||||
|
||||
const ctx = contextProvider(keyPress);
|
||||
const event = keyPressHandler(ctx as any) as any;
|
||||
const event: GameEvent | undefined = keyPressHandler(ctx as any);
|
||||
if (event) handleEvent(event);
|
||||
// if (event) eventHandler(event.event, event.mutations);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -21,6 +21,9 @@ const Loading = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<sprite scale={[5, 5, 5]}>
|
||||
<spriteMaterial attach="material" color={0x000000} />
|
||||
</sprite>
|
||||
<sprite scale={[0.35, 0.6, 0.35]} position={[0, 0.2, 0]}>
|
||||
<spriteMaterial attach="material" map={loadingTex} />
|
||||
</sprite>
|
||||
|
|
|
@ -8,7 +8,7 @@ import { useStore } from "../../store";
|
|||
import lerp from "../../utils/lerp";
|
||||
import GreenTextRenderer from "../TextRenderer/GreenTextRenderer";
|
||||
import usePrevious from "../../hooks/usePrevious";
|
||||
import { getNodeHud } from "../../utils/node-utils";
|
||||
import { getNodeHud } from "../../helpers/node-helpers";
|
||||
|
||||
export type HUDType = {
|
||||
mirrored: number;
|
||||
|
@ -130,7 +130,6 @@ const HUD = memo(() => {
|
|||
if (
|
||||
!(scene === "main" && prevData?.scene === "main") ||
|
||||
(subscene === "site" && prevData?.subscene === "pause") ||
|
||||
(subscene === "site" && prevData?.subscene === "not_found") ||
|
||||
subscene === "pause"
|
||||
) {
|
||||
// set to final pos instantly
|
||||
|
|
|
@ -64,7 +64,7 @@ const Pause = () => {
|
|||
setTimeout(() => {
|
||||
setShowActiveComponent(true);
|
||||
setIntro(false);
|
||||
setInputCooldown(false);
|
||||
setInputCooldown(1000);
|
||||
}, 3500);
|
||||
}, 3400);
|
||||
}
|
||||
|
|
|
@ -3,13 +3,16 @@ import notFound from "../../../static/sprite/not_found.png";
|
|||
import notFoundLof from "../../../static/sprite/not_found_lof.png";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import { useStore } from "../../../store";
|
||||
|
||||
const NotFound = memo(() => {
|
||||
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
|
||||
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
|
||||
|
||||
const wordNotFound = useStore((state) => state.wordNotFound);
|
||||
|
||||
return (
|
||||
<group visible={false}>
|
||||
<group visible={wordNotFound}>
|
||||
<sprite scale={[1, 0.25, 0]} renderOrder={106} position={[-1, -0.05, 0]}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useStore } from "../../../store";
|
|||
import { SiteData } from "./Site";
|
||||
import InactiveLevelNode from "./InactiveLevelNode";
|
||||
import usePrevious from "../../../hooks/usePrevious";
|
||||
import { generateInactiveNodes } from "../../../utils/node-utils";
|
||||
import { generateInactiveNodes } from "../../../helpers/node-helpers";
|
||||
|
||||
type ActiveLevelNodesProps = {
|
||||
visibleNodes: SiteData;
|
||||
|
|
|
@ -8,7 +8,7 @@ import InactiveLevelNodes from "./InactiveLevelNodes";
|
|||
import site_a from "../../../resources/site_a.json";
|
||||
import site_b from "../../../resources/site_b.json";
|
||||
import level_y_values from "../../../resources/level_y_values.json";
|
||||
import { filterInvisibleNodes } from "../../../utils/node-utils";
|
||||
import { filterInvisibleNodes } from "../../../helpers/node-helpers";
|
||||
import Loading from "../../Loading";
|
||||
|
||||
export type NodeData = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { memo } from "react";
|
||||
import body from "../../static/sprite/body.png";
|
||||
import head from "../../static/sprite/head.png";
|
||||
import leftLeg from "../../static/sprite/left_leg.png";
|
||||
|
@ -8,19 +8,9 @@ import rightLeg from "../../static/sprite/right_leg.png";
|
|||
import skeleton from "../../static/sprite/polytan_skeleton.png";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
type PolytanBearProps = {
|
||||
unlockedParts: {
|
||||
body: boolean;
|
||||
head: boolean;
|
||||
leftArm: boolean;
|
||||
rightArm: boolean;
|
||||
leftLeg: boolean;
|
||||
rightLeg: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const PolytanBear = (props: PolytanBearProps) => {
|
||||
const PolytanBear = memo(() => {
|
||||
const skeletonTex = useLoader(THREE.TextureLoader, skeleton);
|
||||
const headTex = useLoader(THREE.TextureLoader, head);
|
||||
const bodyTex = useLoader(THREE.TextureLoader, body);
|
||||
|
@ -29,6 +19,8 @@ const PolytanBear = (props: PolytanBearProps) => {
|
|||
const rightArmTex = useLoader(THREE.TextureLoader, rightArm);
|
||||
const rightLegTex = useLoader(THREE.TextureLoader, rightLeg);
|
||||
|
||||
const unlockedParts = useStore((state) => state.polytanUnlockedParts);
|
||||
|
||||
return (
|
||||
<>
|
||||
<sprite scale={[4, 5, 0]} position={[0, -0.4, 0]}>
|
||||
|
@ -39,7 +31,7 @@ const PolytanBear = (props: PolytanBearProps) => {
|
|||
<spriteMaterial
|
||||
attach="material"
|
||||
map={bodyTex}
|
||||
visible={props.unlockedParts.body}
|
||||
visible={unlockedParts.body}
|
||||
/>
|
||||
</sprite>
|
||||
|
||||
|
@ -47,39 +39,39 @@ const PolytanBear = (props: PolytanBearProps) => {
|
|||
<spriteMaterial
|
||||
attach="material"
|
||||
map={headTex}
|
||||
visible={props.unlockedParts.head}
|
||||
visible={unlockedParts.head}
|
||||
/>
|
||||
</sprite>
|
||||
<sprite scale={[1.9, 1, 0]} position={[1, -2.2, 0]}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={leftLegTex}
|
||||
visible={props.unlockedParts.leftLeg}
|
||||
visible={unlockedParts.leftLeg}
|
||||
/>
|
||||
</sprite>
|
||||
<sprite scale={[1.5, 1.9, 0]} position={[1.2, -0.4, 0]}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={leftArmTex}
|
||||
visible={props.unlockedParts.leftArm}
|
||||
visible={unlockedParts.leftArm}
|
||||
/>
|
||||
</sprite>
|
||||
<sprite scale={[1.6, 2, 0]} position={[-1.2, -1.2, 0]}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={rightArmTex}
|
||||
visible={props.unlockedParts.rightArm}
|
||||
visible={unlockedParts.rightArm}
|
||||
/>
|
||||
</sprite>
|
||||
<sprite scale={[1.9, 1, 0]} position={[-1, -2.2, 0]}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={rightLegTex}
|
||||
visible={props.unlockedParts.rightLeg}
|
||||
visible={unlockedParts.rightLeg}
|
||||
/>
|
||||
</sprite>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default PolytanBear;
|
||||
|
|
|
@ -91,7 +91,6 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
|
|||
useEffect(() => {
|
||||
if (
|
||||
subscene === "pause" ||
|
||||
(subscene === "site" && prevData?.subscene === "not_found") ||
|
||||
(subscene === "site" && prevData?.subscene === "pause")
|
||||
)
|
||||
return;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useStore } from "../../store";
|
|||
import { a, useTrail } from "@react-spring/three";
|
||||
import BigLetter from "./BigLetter";
|
||||
import usePrevious from "../../hooks/usePrevious";
|
||||
import { getNodeHud } from "../../utils/node-utils";
|
||||
import { getNodeHud } from "../../helpers/node-helpers";
|
||||
|
||||
const MainYellowTextAnimator = (props: { visible?: boolean }) => {
|
||||
const activeNode = useStore((state) => state.activeNode);
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
import { NodeData } from "../components/MainScene/Site/Site";
|
||||
import * as audio from "../static/sfx";
|
||||
import * as audio from "../static/audio/sfx";
|
||||
import {
|
||||
nodeExplodeAnimation,
|
||||
nodeKnockAndFallAnimation,
|
||||
nodeKnockAnimation,
|
||||
nodeRipAnimation,
|
||||
nodeThrowAnimation,
|
||||
} from "../utils/node-animations";
|
||||
import { playAudio } from "../store";
|
||||
} from "../helpers/node-animation-helpers";
|
||||
import { playMediaElement, resetMediaElement } from "../helpers/media-helpers";
|
||||
import {
|
||||
ActiveSite,
|
||||
EndComponent,
|
||||
GameProgress,
|
||||
GameScene,
|
||||
LeftMediaComponent,
|
||||
MediaComponent,
|
||||
MediaSide,
|
||||
PromptComponent,
|
||||
RightMediaComponent,
|
||||
SiteSaveState,
|
||||
SsknComponent,
|
||||
} from "../store";
|
||||
|
||||
export const siteMoveHorizontal = (calculatedState: {
|
||||
lainMoveAnimation: string;
|
||||
|
@ -19,15 +32,13 @@ export const siteMoveHorizontal = (calculatedState: {
|
|||
mutation: {
|
||||
lainMoveState: calculatedState.lainMoveAnimation,
|
||||
siteRot: calculatedState.siteRot,
|
||||
inputCooldown: true,
|
||||
inputCooldown: 5500,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: {
|
||||
activeNode: calculatedState.activeNode,
|
||||
lainMoveState: "standing",
|
||||
inputCooldown: false,
|
||||
},
|
||||
delay: 3900,
|
||||
},
|
||||
|
@ -45,37 +56,36 @@ export const siteMoveVertical = (calculatedState: {
|
|||
mutation: {
|
||||
lainMoveState: calculatedState.lainMoveAnimation,
|
||||
activeLevel: calculatedState.activeLevel,
|
||||
inputCooldown: true,
|
||||
inputCooldown: 5500,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: {
|
||||
activeNode: calculatedState.activeNode,
|
||||
lainMoveState: "standing",
|
||||
inputCooldown: false,
|
||||
},
|
||||
delay: 3900,
|
||||
},
|
||||
],
|
||||
audio: [
|
||||
{ sfx: [audio.sound13], delay: 0 },
|
||||
{ sfx: [audio.sound13] },
|
||||
{ sfx: [audio.sound10, audio.sound9], delay: 1300 },
|
||||
{ sfx: [audio.sound8], delay: 2700 },
|
||||
],
|
||||
});
|
||||
|
||||
export const changeNode = (calculatedState: { activeNode: NodeData }) => ({
|
||||
state: [{ mutation: { activeNode: calculatedState.activeNode }, delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
});
|
||||
|
||||
export const throwNode = (calculatedState: { currentScene: string }) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: { lainMoveState: "throw_node", inputCooldown: true },
|
||||
delay: 0,
|
||||
mutation: { activeNode: calculatedState.activeNode, inputCooldown: 1500 },
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const throwNode = (calculatedState: { currentScene: GameScene }) => ({
|
||||
state: [
|
||||
{ mutation: { lainMoveState: "throw_node", inputCooldown: -1 } },
|
||||
{
|
||||
mutation: {
|
||||
currentScene: calculatedState.currentScene,
|
||||
|
@ -87,18 +97,15 @@ export const throwNode = (calculatedState: { currentScene: string }) => ({
|
|||
],
|
||||
effects: [nodeThrowAnimation],
|
||||
audio: [
|
||||
{ sfx: [audio.sound0], delay: 0 },
|
||||
{ sfx: [audio.sound0] },
|
||||
{ sfx: [audio.sound12], delay: 1600 },
|
||||
{ sfx: [audio.sound13, audio.sound14], delay: 2800 },
|
||||
],
|
||||
});
|
||||
|
||||
export const ripNode = (calculatedState: { currentScene: string }) => ({
|
||||
export const ripNode = (calculatedState: { currentScene: GameScene }) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: { lainMoveState: "rip_node", inputCooldown: true },
|
||||
delay: 0,
|
||||
},
|
||||
{ mutation: { lainMoveState: "rip_node", inputCooldown: -1 } },
|
||||
{
|
||||
mutation: {
|
||||
currentScene: calculatedState.currentScene,
|
||||
|
@ -110,7 +117,7 @@ export const ripNode = (calculatedState: { currentScene: string }) => ({
|
|||
],
|
||||
effects: [nodeRipAnimation],
|
||||
audio: [
|
||||
{ sfx: [audio.sound0], delay: 0 },
|
||||
{ sfx: [audio.sound0] },
|
||||
{ sfx: [audio.sound12], delay: 1600 },
|
||||
{ sfx: [audio.sound13, audio.sound15], delay: 4000 },
|
||||
],
|
||||
|
@ -121,18 +128,17 @@ export const explodeNode = {
|
|||
{
|
||||
mutation: {
|
||||
lainMoveState: "touch_node_and_get_scared",
|
||||
inputCooldown: true,
|
||||
inputCooldown: 3800,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: { lainMoveState: "standing", inputCooldown: false },
|
||||
mutation: { lainMoveState: "standing" },
|
||||
delay: 3800,
|
||||
},
|
||||
],
|
||||
effects: [nodeExplodeAnimation],
|
||||
audio: [
|
||||
{ sfx: [audio.sound0], delay: 0 },
|
||||
{ sfx: [audio.sound0] },
|
||||
{ sfx: [audio.sound17], delay: 2400 },
|
||||
{ sfx: [audio.sound33], delay: 3150 },
|
||||
],
|
||||
|
@ -140,33 +146,26 @@ export const explodeNode = {
|
|||
|
||||
export const knockNode = {
|
||||
state: [
|
||||
{ mutation: { lainMoveState: "knock", inputCooldown: true }, delay: 0 },
|
||||
{ mutation: { lainMoveState: "knock", inputCooldown: 3500 } },
|
||||
{
|
||||
mutation: { lainMoveState: "standing", inputCooldown: false },
|
||||
delay: 2900,
|
||||
mutation: { lainMoveState: "standing" },
|
||||
delay: 3500,
|
||||
},
|
||||
],
|
||||
effects: [nodeKnockAnimation],
|
||||
audio: [
|
||||
{ sfx: [audio.sound0], delay: 0 },
|
||||
{ sfx: [audio.sound18], delay: 1200 },
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0] }, { sfx: [audio.sound18], delay: 1200 }],
|
||||
};
|
||||
|
||||
export const knockNodeAndFall = {
|
||||
state: [
|
||||
{ mutation: { lainMoveState: "knock_and_fall", inputCooldown: 6000 } },
|
||||
{
|
||||
mutation: { lainMoveState: "knock_and_fall", inputCooldown: true },
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: { lainMoveState: "standing", inputCooldown: false },
|
||||
delay: 7500,
|
||||
mutation: { lainMoveState: "standing" },
|
||||
},
|
||||
],
|
||||
effects: [nodeKnockAndFallAnimation],
|
||||
audio: [
|
||||
{ sfx: [audio.sound0], delay: 0 },
|
||||
{ sfx: [audio.sound0] },
|
||||
{ sfx: [audio.sound18], delay: 1200 },
|
||||
{ sfx: [audio.sound19], delay: 2300 },
|
||||
{ sfx: [audio.sound33], delay: 3150 },
|
||||
|
@ -181,23 +180,28 @@ export const enterLevelSelection = (calculatedState: {
|
|||
mutation: {
|
||||
selectedLevel: calculatedState.selectedLevel,
|
||||
mainSubscene: "level_selection",
|
||||
inputCooldown: 1500,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const exitLevelSelection = {
|
||||
state: [{ mutation: { mainSubscene: "site" }, delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
state: [{ mutation: { mainSubscene: "site", inputCooldown: 1500 } }],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
};
|
||||
|
||||
export const changeSelectedLevel = (calculatedState: {
|
||||
selectedLevel: number;
|
||||
}) => ({
|
||||
state: [
|
||||
{ mutation: { selectedLevel: calculatedState.selectedLevel }, delay: 0 },
|
||||
{
|
||||
mutation: {
|
||||
selectedLevel: calculatedState.selectedLevel,
|
||||
inputCooldown: 300,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -212,15 +216,13 @@ export const selectLevel = (calculatedState: {
|
|||
lainMoveState: calculatedState.lainMoveState,
|
||||
activeLevel: calculatedState.activeLevel,
|
||||
mainSubscene: "site",
|
||||
inputCooldown: true,
|
||||
inputCooldown: 5500,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: {
|
||||
activeNode: calculatedState.activeNode,
|
||||
lainMoveState: "standing",
|
||||
inputCooldown: false,
|
||||
},
|
||||
delay: 3900,
|
||||
},
|
||||
|
@ -238,19 +240,15 @@ export const pauseGame = (calculatedState: { siteRot: number[] }) => ({
|
|||
lainMoveState: "rip_middle_ring",
|
||||
pauseExitAnimation: false,
|
||||
mainSubscene: "pause",
|
||||
inputCooldown: true,
|
||||
inputCooldown: -1,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: { siteRot: calculatedState.siteRot },
|
||||
delay: 3600,
|
||||
},
|
||||
],
|
||||
audio: [
|
||||
{ sfx: [audio.sound7], delay: 0 },
|
||||
{ sfx: [audio.sound23], delay: 3600 },
|
||||
],
|
||||
audio: [{ sfx: [audio.sound7] }, { sfx: [audio.sound23], delay: 3600 }],
|
||||
});
|
||||
|
||||
export const changePauseComponent = (calculatedState: {
|
||||
|
@ -258,29 +256,31 @@ export const changePauseComponent = (calculatedState: {
|
|||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: { activePauseComponent: calculatedState.activePauseComponent },
|
||||
delay: 0,
|
||||
mutation: {
|
||||
activePauseComponent: calculatedState.activePauseComponent,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const showPermissionDenied = {
|
||||
state: [
|
||||
{ mutation: { permissionDenied: true }, delay: 0 },
|
||||
{ mutation: { permissionDenied: true, inputCooldown: 1200 } },
|
||||
{ mutation: { permissionDenied: false }, delay: 1200 },
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const displayPrompt = {
|
||||
state: [{ mutation: { promptVisible: true }, delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound0], delay: 0 }],
|
||||
state: [{ mutation: { promptVisible: true, inputCooldown: 500 } }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const showAbout = {
|
||||
state: [{ mutation: { showingAbout: true }, delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound0], delay: 0 }],
|
||||
state: [{ mutation: { showingAbout: true } }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const exitPause = (calculatedState: { siteRot: number[] }) => ({
|
||||
|
@ -290,9 +290,8 @@ export const exitPause = (calculatedState: { siteRot: number[] }) => ({
|
|||
siteRot: calculatedState.siteRot,
|
||||
pauseExitAnimation: true,
|
||||
activePauseComponent: "change",
|
||||
inputCooldown: true,
|
||||
inputCooldown: 1400,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
{
|
||||
mutation: {
|
||||
|
@ -303,84 +302,70 @@ export const exitPause = (calculatedState: { siteRot: number[] }) => ({
|
|||
delay: 1200,
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
});
|
||||
|
||||
export const exitAbout = {
|
||||
state: [{ mutation: { showingAbout: false }, delay: 0 }],
|
||||
state: [{ mutation: { showingAbout: false, inputCooldown: 500 } }],
|
||||
};
|
||||
|
||||
export const changePromptComponent = (calculatedState: {
|
||||
activePromptComponent: "yes" | "no";
|
||||
activePromptComponent: PromptComponent;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activePromptComponent: calculatedState.activePromptComponent,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const exitPrompt = {
|
||||
state: [
|
||||
{
|
||||
mutation: { activePromptComponent: "no", promptVisible: false },
|
||||
delay: 0,
|
||||
mutation: {
|
||||
activePromptComponent: "no",
|
||||
promptVisible: false,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound28], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound28] }],
|
||||
};
|
||||
|
||||
// todo actually save
|
||||
export const saveGame = () => ({
|
||||
state: [
|
||||
{
|
||||
mutation: { saveSuccessful: true },
|
||||
delay: 0,
|
||||
},
|
||||
{ mutation: { saveSuccessful: true, inputCooldown: 1200 } },
|
||||
{
|
||||
mutation: { saveSuccessful: undefined },
|
||||
delay: 1200,
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound28], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound28] }],
|
||||
});
|
||||
|
||||
// todo actually load
|
||||
export const loadGame = () => ({
|
||||
state: [
|
||||
{
|
||||
mutation: { loadSuccessful: true },
|
||||
delay: 0,
|
||||
},
|
||||
{ mutation: { loadSuccessful: true, inputCooldown: 1200 } },
|
||||
{
|
||||
mutation: { loadSuccessful: undefined },
|
||||
delay: 1200,
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound28], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound28] }],
|
||||
});
|
||||
|
||||
export const changeSite = (calculatedState: {
|
||||
newActiveSite: "a" | "b";
|
||||
newActiveSite: ActiveSite;
|
||||
newActiveNode: NodeData;
|
||||
newActiveLevel: string;
|
||||
newSiteRot: number[];
|
||||
newSiteSaveState: {
|
||||
a: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
b: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
};
|
||||
newSiteSaveState: SiteSaveState;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
|
@ -397,26 +382,274 @@ export const changeSite = (calculatedState: {
|
|||
activeLevel: calculatedState.newActiveLevel,
|
||||
// save state
|
||||
siteSaveState: calculatedState.newSiteSaveState,
|
||||
inputCooldown: -1,
|
||||
},
|
||||
delay: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const changeLeftMediaComponent = (calculatedState: {
|
||||
activeComponent: "play" | "exit";
|
||||
activeComponent: LeftMediaComponent;
|
||||
}) => ({
|
||||
state: [
|
||||
{ mutation: { activeMediaComponent: calculatedState.activeComponent } },
|
||||
{
|
||||
mutation: {
|
||||
activeMediaComponent: calculatedState.activeComponent,
|
||||
inputCooldown: 1200,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1], delay: 0 }],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const changeMediaSide = (calculatedState: {
|
||||
activeMediaComponent: "fstWord" | "sndWord" | "thirdWord" | "exit" | "play";
|
||||
activeMediaComponent: MediaComponent;
|
||||
lastActiveMediaComponents: {
|
||||
left: "play" | "exit";
|
||||
right: "fstWord" | "sndWord" | "thirdWord";
|
||||
left: LeftMediaComponent;
|
||||
right: RightMediaComponent;
|
||||
};
|
||||
currentMediaSide: "right" | "left";
|
||||
}) => ({});
|
||||
currentMediaSide: MediaSide;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeMediaComponent: calculatedState.activeMediaComponent,
|
||||
lastActiveMediaComponents: calculatedState.lastActiveMediaComponents,
|
||||
currentMediaSide: calculatedState.currentMediaSide,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const playMedia = {
|
||||
state: [{ mutation: { mediaPercentageElapsed: 0, inputCooldown: 500 } }],
|
||||
effects: [playMediaElement],
|
||||
};
|
||||
|
||||
export const exitMedia = {
|
||||
state: [{ mutation: { currentScene: "main", inputCooldown: -1 } }],
|
||||
effects: [resetMediaElement],
|
||||
};
|
||||
|
||||
export const changeRightMediaComponent = (calculatedState: {
|
||||
wordPosStateIdx: number;
|
||||
activeComponent: RightMediaComponent;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeMediaComponent: calculatedState.activeComponent,
|
||||
mediaWordPosStateIdx: calculatedState.wordPosStateIdx,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const wordNotFound = {
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
currentScene: "main",
|
||||
wordNotFound: true,
|
||||
inputCooldown: 300,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound30] }],
|
||||
effects: [resetMediaElement],
|
||||
};
|
||||
|
||||
export const hideWordNotFound = {
|
||||
state: [{ mutation: { wordNotFound: false, inputCooldown: 300 } }],
|
||||
};
|
||||
|
||||
export const selectWord = (calculatedState: {
|
||||
activeLevel: string;
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeLevel: calculatedState.activeLevel,
|
||||
siteRot: calculatedState.siteRot,
|
||||
activeNode: calculatedState.activeNode,
|
||||
wordSelected: true,
|
||||
currentScene: "main",
|
||||
inputCooldown: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound29] }],
|
||||
effects: [resetMediaElement],
|
||||
});
|
||||
|
||||
export const changeSsknComponent = (calculatedState: {
|
||||
activeSsknComponent: SsknComponent;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeSsknComponent: calculatedState.activeSsknComponent,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const upgradeSskn = (calculatedState: {
|
||||
gameProgress: GameProgress;
|
||||
ssknLvl: number;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
gameProgress: calculatedState.gameProgress,
|
||||
ssknLvl: calculatedState.ssknLvl,
|
||||
ssknLoading: true,
|
||||
inputCooldown: -1,
|
||||
},
|
||||
},
|
||||
{ mutation: { currentScene: "main" }, delay: 6000 },
|
||||
],
|
||||
});
|
||||
|
||||
export const exitSskn = {
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
currentScene: "main",
|
||||
ssknLoading: false,
|
||||
activeSsknComponent: "ok",
|
||||
inputCooldown: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const changeEndComponent = (calculatedState: {
|
||||
activeEndComponent: EndComponent;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeEndComponent: calculatedState.activeEndComponent,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const endGame = {
|
||||
state: [{ mutation: { currentScene: "boot", inputCooldown: -1 } }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
// todo this is probably buggy
|
||||
export const continueGameAfterEnd = {
|
||||
state: [
|
||||
{
|
||||
mutation: { currentScene: "change_disc", intro: true, inputCooldown: -1 },
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const changeMainMenuComponent = (calculatedState: {
|
||||
activeMainMenuComponent: "authorize_user" | "load_data";
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
activeMainMenuComponent: calculatedState.activeMainMenuComponent,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound1] }],
|
||||
});
|
||||
|
||||
export const exitLoadData = {
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
bootSubscene: "main_menu",
|
||||
promptVisible: false,
|
||||
activePromptComponent: "no",
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound29] }],
|
||||
};
|
||||
|
||||
export const enterLoadData = {
|
||||
state: [
|
||||
{ mutation: { bootSubscene: "load_data", inputCooldown: 500 } },
|
||||
{ mutation: { promptVisible: true }, delay: 500 },
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const enterUserAuthorization = {
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
bootSubscene: "authorize_user",
|
||||
authorizeUserLetterIdx: 0,
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
};
|
||||
|
||||
export const exitUserAuthorization = {
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
playerName: "",
|
||||
bootSubscene: "main_menu",
|
||||
inputCooldown: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
audio: [{ sfx: [audio.sound29] }],
|
||||
};
|
||||
|
||||
export const startNewGame = {
|
||||
state: [
|
||||
{ mutation: { currentScene: "main", intro: true, inputCooldown: -1 } },
|
||||
],
|
||||
};
|
||||
|
||||
export const updatePlayerName = (calculatedState: { playerName: string }) => ({
|
||||
state: [{ mutation: { playerName: calculatedState.playerName } }],
|
||||
audio: [{ sfx: [audio.sound0] }],
|
||||
});
|
||||
|
||||
export const removePlayerNameLastChar = (calculatedState: {
|
||||
playerName: string;
|
||||
}) => ({
|
||||
state: [{ mutation: { playerName: calculatedState.playerName } }],
|
||||
audio: [{ sfx: [audio.sound29] }],
|
||||
});
|
||||
|
||||
export const failUpdatePlayerName = { audio: [{ sfx: [audio.sound0] }] };
|
||||
|
||||
export const updateAuthorizeUserLetterIdx = (calculatedState: {
|
||||
authorizeUserLetterIdx: number;
|
||||
}) => ({
|
||||
state: [
|
||||
{
|
||||
mutation: {
|
||||
inputCooldown: 300,
|
||||
authorizeUserLetterIdx: calculatedState.authorizeUserLetterIdx,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,47 +1,44 @@
|
|||
import { playAudio, useStore } from "../../store";
|
||||
import sleep from "../../utils/sleep";
|
||||
import { playAudio, useStore } from "../store";
|
||||
import sleep from "../utils/sleep";
|
||||
|
||||
type Mutation = {
|
||||
mutation: Object;
|
||||
delay: number;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
type EventAudio = {
|
||||
sfx: HTMLAudioElement[];
|
||||
delay: number;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
type Event = {
|
||||
state: Mutation[];
|
||||
export type GameEvent = {
|
||||
state?: Mutation[];
|
||||
audio?: EventAudio[];
|
||||
effects?: (() => void)[];
|
||||
};
|
||||
|
||||
// the async/await here might be misleading for some, it functions as a setTimeout that fires
|
||||
// multiple async calls without stopping the execution, which is what we want.
|
||||
const handleEvent = (event: Event) => {
|
||||
const now = performance.now();
|
||||
const handleEvent = (event: GameEvent) => {
|
||||
const setState = useStore.setState;
|
||||
|
||||
const { state, audio, effects } = event;
|
||||
const { state, effects, audio } = event;
|
||||
|
||||
state.forEach(async (mutationData) => {
|
||||
const { delay, mutation } = mutationData;
|
||||
if (delay) await sleep(delay);
|
||||
setState(mutation);
|
||||
});
|
||||
if (state)
|
||||
state.forEach(async (mutationData) => {
|
||||
const { delay, mutation } = mutationData;
|
||||
if (delay) await sleep(delay);
|
||||
setState(mutation);
|
||||
});
|
||||
|
||||
if (effects) effects.forEach((effect) => effect());
|
||||
|
||||
if (audio) {
|
||||
if (audio)
|
||||
audio.forEach(async (audio) => {
|
||||
const { delay, sfx } = audio;
|
||||
if (delay) await sleep(delay);
|
||||
sfx.forEach((soundEffect) => playAudio(soundEffect));
|
||||
});
|
||||
}
|
||||
|
||||
// console.log(performance.now() - now);
|
||||
};
|
||||
|
||||
export default handleEvent;
|
|
@ -1,84 +0,0 @@
|
|||
import { playAudio, useStore } from "../../store";
|
||||
import * as audio from "../../static/sfx";
|
||||
|
||||
const handleBootSceneEvent = (eventState: any) => {
|
||||
const setState = useStore.setState;
|
||||
|
||||
switch (eventState.event) {
|
||||
case "main_menu_up":
|
||||
setState({ activeMainMenuComponent: "authorize_user" });
|
||||
playAudio(audio.sound1);
|
||||
break;
|
||||
case "main_menu_down":
|
||||
setState({ activeMainMenuComponent: "load_data" });
|
||||
playAudio(audio.sound1);
|
||||
break;
|
||||
case "main_menu_load_data_select":
|
||||
setState({ bootSubscene: "load_data" });
|
||||
playAudio(audio.sound0);
|
||||
|
||||
setTimeout(() => setState({ promptVisible: true }), 500);
|
||||
break;
|
||||
case "main_menu_authorize_user_select":
|
||||
setState({ authorizeUserLetterIdx: 0, bootSubscene: "authorize_user" });
|
||||
playAudio(audio.sound0);
|
||||
break;
|
||||
case "authorize_user_up":
|
||||
case "authorize_user_down":
|
||||
case "authorize_user_left":
|
||||
case "authorize_user_right":
|
||||
setState({
|
||||
authorizeUserLetterIdx: eventState.authorizeUserLetterIdx,
|
||||
});
|
||||
break;
|
||||
case "authorize_user_back":
|
||||
setState({
|
||||
playerName: "",
|
||||
bootSubscene: "main_menu",
|
||||
});
|
||||
playAudio(audio.sound29);
|
||||
break;
|
||||
case "update_player_name":
|
||||
setState({
|
||||
playerName: eventState.playerName,
|
||||
});
|
||||
playAudio(audio.sound0);
|
||||
break;
|
||||
case "update_player_name_denied":
|
||||
playAudio(audio.sound0);
|
||||
break;
|
||||
case "remove_last_char":
|
||||
setState({ playerName: eventState.playerName });
|
||||
playAudio(audio.sound29);
|
||||
break;
|
||||
case "load_data_no":
|
||||
setState({
|
||||
bootSubscene: "main_menu",
|
||||
promptVisible: false,
|
||||
activePromptComponent: "no",
|
||||
});
|
||||
playAudio(audio.sound29);
|
||||
break;
|
||||
case "load_data_yes":
|
||||
// todo check if data exists
|
||||
setState({ loadSuccessful: true });
|
||||
playAudio(audio.sound28);
|
||||
|
||||
//todo actually load
|
||||
setTimeout(() => setState({ loadSuccessful: undefined }), 1200);
|
||||
break;
|
||||
case "prompt_left":
|
||||
setState({ activePromptComponent: "yes" });
|
||||
playAudio(audio.sound1);
|
||||
break;
|
||||
case "prompt_right":
|
||||
setState({ activePromptComponent: "no" });
|
||||
playAudio(audio.sound1);
|
||||
break;
|
||||
case "start_new_game":
|
||||
setState({ currentScene: "main", intro: true });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export default handleBootSceneEvent;
|
|
@ -1,20 +0,0 @@
|
|||
import { useStore } from "../../store";
|
||||
|
||||
const handleEndSceneEvent = (eventState: any) => {
|
||||
const setState = useStore.setState;
|
||||
switch (eventState.event) {
|
||||
case "end_selection_up":
|
||||
setState({ activeEndComponent: "end" });
|
||||
break;
|
||||
case "end_selection_down":
|
||||
setState({ activeEndComponent: "continue" });
|
||||
break;
|
||||
case "end_continue_select":
|
||||
setState({ currentScene: "change_disc", intro: true });
|
||||
break;
|
||||
case "end_end_select":
|
||||
setState({ currentScene: "boot" });
|
||||
}
|
||||
};
|
||||
|
||||
export default handleEndSceneEvent;
|
|
@ -1,84 +0,0 @@
|
|||
import { playAudio, useStore } from "../../store";
|
||||
import * as audio from "../../static/sfx";
|
||||
|
||||
const handleMediaSceneEvent = (eventState: any) => {
|
||||
const setState = useStore.setState;
|
||||
|
||||
const setNodeViewed = useStore.getState().setNodeViewed;
|
||||
const updateLeftSide = useStore.getState().updateLeftSide;
|
||||
const updateRightSide = useStore.getState().updateRightSide;
|
||||
|
||||
const setPercentageElapsed = useStore.getState().setPercentageElapsed;
|
||||
|
||||
const playMedia = () => {
|
||||
const mediaElement = document.getElementById("media") as HTMLMediaElement;
|
||||
|
||||
if (mediaElement && mediaElement.paused) {
|
||||
setPercentageElapsed(0);
|
||||
|
||||
mediaElement.play();
|
||||
}
|
||||
};
|
||||
|
||||
const exitMedia = () => {
|
||||
const mediaElement = document.getElementById("media") as HTMLMediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.pause();
|
||||
mediaElement.currentTime = 0;
|
||||
}
|
||||
};
|
||||
|
||||
switch (eventState.event) {
|
||||
case "media_rightside_down":
|
||||
case "media_rightside_up":
|
||||
setState({
|
||||
activeMediaComponent: eventState.newActiveComponent,
|
||||
mediaWordPosStateIdx: eventState.wordPosStateIdx,
|
||||
});
|
||||
playAudio(audio.sound1);
|
||||
break;
|
||||
case "media_leftside_right":
|
||||
updateLeftSide(
|
||||
eventState.newActiveComponent,
|
||||
eventState.lastActiveComponent
|
||||
);
|
||||
break;
|
||||
case "media_rightside_left":
|
||||
updateRightSide(
|
||||
eventState.newActiveComponent,
|
||||
eventState.lastActiveComponent
|
||||
);
|
||||
break;
|
||||
case "media_play_select":
|
||||
setNodeViewed(eventState.node.node_name, {
|
||||
is_viewed: 1,
|
||||
is_visible: 1,
|
||||
});
|
||||
playMedia();
|
||||
break;
|
||||
case "media_exit_select":
|
||||
exitMedia();
|
||||
playAudio(audio.sound29);
|
||||
break;
|
||||
case "media_word_select":
|
||||
exitMedia();
|
||||
playAudio(audio.sound29);
|
||||
setState({
|
||||
wordSelected: true,
|
||||
activeLevel: eventState.level,
|
||||
siteRot: [0, eventState.siteRotY, 0],
|
||||
activeNode: eventState.node,
|
||||
currentScene: "main",
|
||||
});
|
||||
break;
|
||||
case "word_node_not_found":
|
||||
exitMedia();
|
||||
playAudio(audio.sound30);
|
||||
setState({
|
||||
mainSubscene: "not_found",
|
||||
currentScene: "main",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handleMediaSceneEvent;
|
|
@ -1,41 +0,0 @@
|
|||
import { useStore } from "../../store";
|
||||
|
||||
const handleSsknSceneEvent = (eventState: any) => {
|
||||
const setState = useStore.setState;
|
||||
|
||||
const setNodeViewed = useStore.getState().setNodeViewed;
|
||||
|
||||
switch (eventState.event) {
|
||||
case "sskn_cancel_up":
|
||||
setState({
|
||||
activeSsknComponent: "ok",
|
||||
});
|
||||
break;
|
||||
case "sskn_ok_down":
|
||||
setState({
|
||||
activeSsknComponent: "cancel",
|
||||
});
|
||||
break;
|
||||
case "sskn_ok_select":
|
||||
setState({
|
||||
ssknLoading: true,
|
||||
});
|
||||
setNodeViewed(eventState.node.node_name, {
|
||||
is_viewed: 1,
|
||||
is_visible: 0,
|
||||
});
|
||||
// incrementSsknLvl();
|
||||
|
||||
setTimeout(() => setState({ currentScene: "main" }), 6000);
|
||||
|
||||
break;
|
||||
case "sskn_cancel_select":
|
||||
setState({
|
||||
ssknLoading: false,
|
||||
currentScene: "main",
|
||||
activeSsknComponent: "ok",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handleSsknSceneEvent;
|
|
@ -1,8 +1,25 @@
|
|||
import authorize_user_letters from "../../resources/authorize_user_letters.json";
|
||||
import handleNameSelection from "../../utils/handleNameSelection";
|
||||
import handleNameSelection from "../../helpers/name-selection-helpers";
|
||||
import { BootSceneContext } from "../../store";
|
||||
import {
|
||||
changeMainMenuComponent,
|
||||
changePromptComponent,
|
||||
enterLoadData,
|
||||
enterUserAuthorization,
|
||||
exitLoadData,
|
||||
exitUserAuthorization,
|
||||
failUpdatePlayerName,
|
||||
loadGame,
|
||||
removePlayerNameLastChar,
|
||||
startNewGame,
|
||||
updateAuthorizeUserLetterIdx,
|
||||
updatePlayerName,
|
||||
} from "../eventTemplates";
|
||||
import { GameEvent } from "../handleEvent";
|
||||
|
||||
const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
||||
const handleBootSceneKeyPress = (
|
||||
bootSceneContext: BootSceneContext
|
||||
): GameEvent | undefined => {
|
||||
const {
|
||||
keyPress,
|
||||
subscene,
|
||||
|
@ -16,17 +33,15 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
if (promptVisible) {
|
||||
switch (keyPress) {
|
||||
case "LEFT":
|
||||
return { event: "prompt_left" };
|
||||
return changePromptComponent({ activePromptComponent: "yes" });
|
||||
case "RIGHT":
|
||||
return { event: "prompt_right" };
|
||||
return changePromptComponent({ activePromptComponent: "no" });
|
||||
case "CIRCLE":
|
||||
switch (activePromptComponent) {
|
||||
case "no":
|
||||
return { event: "load_data_no" };
|
||||
return exitLoadData;
|
||||
case "yes":
|
||||
return {
|
||||
event: "load_data_yes",
|
||||
};
|
||||
return loadGame();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -35,28 +50,34 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
switch (keyPress) {
|
||||
case "UP":
|
||||
case "DOWN":
|
||||
return { event: `main_menu_${keyPress.toLowerCase()}` };
|
||||
const newComponent =
|
||||
keyPress === "UP" ? "authorize_user" : "load_data";
|
||||
return changeMainMenuComponent({
|
||||
activeMainMenuComponent: newComponent,
|
||||
});
|
||||
case "CIRCLE":
|
||||
return { event: `main_menu_${activeMainMenuComponent}_select` };
|
||||
switch (activeMainMenuComponent) {
|
||||
case "authorize_user":
|
||||
return enterUserAuthorization;
|
||||
case "load_data":
|
||||
return enterLoadData;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "authorize_user":
|
||||
switch (keyPress) {
|
||||
case "START":
|
||||
if (playerName.length > 0) {
|
||||
return {
|
||||
event: "start_new_game",
|
||||
};
|
||||
return startNewGame;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case "X":
|
||||
if (playerName.length > 0) {
|
||||
return {
|
||||
event: "remove_last_char",
|
||||
return removePlayerNameLastChar({
|
||||
playerName: playerName.slice(0, -1),
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return { event: "authorize_user_back" };
|
||||
return exitUserAuthorization;
|
||||
}
|
||||
case "LEFT":
|
||||
// if utmost left, break
|
||||
|
@ -64,7 +85,7 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
[0, 13, 26, 39, 52].includes(authorizeUserLetterIdx) ||
|
||||
authorizeUserLetterIdx === 15
|
||||
)
|
||||
break;
|
||||
return;
|
||||
// skip
|
||||
else if (
|
||||
authorizeUserLetterIdx === 41 ||
|
||||
|
@ -74,19 +95,17 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx === 19 ||
|
||||
authorizeUserLetterIdx === 45
|
||||
) {
|
||||
return {
|
||||
event: "authorize_user_left",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx - 2,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
event: "authorize_user_left",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx - 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
case "RIGHT":
|
||||
// if utmost right, break
|
||||
if ([12, 25, 38, 51, 64].includes(authorizeUserLetterIdx)) break;
|
||||
if ([12, 25, 38, 51, 64].includes(authorizeUserLetterIdx)) return;
|
||||
// skip empty
|
||||
else if (
|
||||
authorizeUserLetterIdx === 39 ||
|
||||
|
@ -96,15 +115,13 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx === 43 ||
|
||||
authorizeUserLetterIdx === 17
|
||||
) {
|
||||
return {
|
||||
event: "authorize_user_right",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx + 2,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
event: "authorize_user_right",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx + 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
case "DOWN":
|
||||
// if utmost down, break
|
||||
|
@ -113,7 +130,7 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx
|
||||
)
|
||||
) {
|
||||
break;
|
||||
return;
|
||||
// skip empty
|
||||
} else if (
|
||||
authorizeUserLetterIdx === 0 ||
|
||||
|
@ -123,20 +140,17 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx === 31 ||
|
||||
authorizeUserLetterIdx === 5
|
||||
) {
|
||||
return {
|
||||
event: "authorize_user_down",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx + 26,
|
||||
};
|
||||
});
|
||||
} else if (authorizeUserLetterIdx === 3) {
|
||||
return {
|
||||
event: "authorize_user_down",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx + 52,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
event: "authorize_user_down",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx + 13,
|
||||
};
|
||||
});
|
||||
}
|
||||
case "UP":
|
||||
// if utmost up, break
|
||||
|
@ -145,7 +159,7 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx
|
||||
)
|
||||
) {
|
||||
break;
|
||||
return;
|
||||
// skip empty
|
||||
} else if (
|
||||
authorizeUserLetterIdx === 26 ||
|
||||
|
@ -154,20 +168,17 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
authorizeUserLetterIdx === 31 ||
|
||||
authorizeUserLetterIdx === 57
|
||||
) {
|
||||
return {
|
||||
event: "authorize_user_up",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx - 26,
|
||||
};
|
||||
});
|
||||
} else if (authorizeUserLetterIdx === 55) {
|
||||
return {
|
||||
event: "authorize_user_up",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx - 52,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
event: "authorize_user_up",
|
||||
return updateAuthorizeUserLetterIdx({
|
||||
authorizeUserLetterIdx: authorizeUserLetterIdx - 13,
|
||||
};
|
||||
});
|
||||
}
|
||||
case "CIRCLE":
|
||||
const chosenCharacter =
|
||||
|
@ -178,10 +189,9 @@ const handleBootSceneKeyPress = (bootSceneContext: BootSceneContext) => {
|
|||
const newName = handleNameSelection(playerName, chosenCharacter);
|
||||
|
||||
if (newName !== undefined)
|
||||
return { event: "update_player_name", playerName: newName };
|
||||
else return { event: "update_player_name_denied" };
|
||||
return updatePlayerName({ playerName: newName });
|
||||
else return failUpdatePlayerName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
import { EndSceneContext } from "../../store";
|
||||
import {
|
||||
changeEndComponent,
|
||||
continueGameAfterEnd,
|
||||
endGame,
|
||||
} from "../eventTemplates";
|
||||
import { GameEvent } from "../handleEvent";
|
||||
|
||||
const handleEndSceneKeyPress = (endSceneContext: EndSceneContext) => {
|
||||
const handleEndSceneKeyPress = (
|
||||
endSceneContext: EndSceneContext
|
||||
): GameEvent | undefined => {
|
||||
const { keyPress, selectionVisible, activeEndComponent } = endSceneContext;
|
||||
|
||||
if (selectionVisible) {
|
||||
switch (keyPress) {
|
||||
case "UP":
|
||||
case "DOWN":
|
||||
return { event: `end_selection_${keyPress.toLowerCase()}` };
|
||||
const newComponent = keyPress === "UP" ? "end" : "continue";
|
||||
return changeEndComponent({ activeEndComponent: newComponent });
|
||||
case "CIRCLE":
|
||||
return { event: `end_${activeEndComponent}_select` };
|
||||
switch (activeEndComponent) {
|
||||
case "end":
|
||||
return endGame;
|
||||
case "continue":
|
||||
return continueGameAfterEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
getNodeById,
|
||||
isNodeVisible,
|
||||
unknownNodeTemplate,
|
||||
} from "../../utils/node-utils";
|
||||
} from "../../helpers/node-helpers";
|
||||
import { MainSceneContext } from "../../store";
|
||||
import {
|
||||
changeNode,
|
||||
|
@ -18,19 +18,25 @@ import {
|
|||
exitPause,
|
||||
exitPrompt,
|
||||
explodeNode,
|
||||
hideWordNotFound,
|
||||
knockNode,
|
||||
knockNodeAndFall,
|
||||
loadGame,
|
||||
pauseGame,
|
||||
ripNode,
|
||||
saveGame,
|
||||
selectLevel,
|
||||
showAbout,
|
||||
showPermissionDenied,
|
||||
siteMoveHorizontal,
|
||||
siteMoveVertical,
|
||||
throwNode,
|
||||
} from "../eventTemplates";
|
||||
import { GameEvent } from "../handleEvent";
|
||||
|
||||
const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
||||
const handleMainSceneKeyPress = (
|
||||
mainSceneContext: MainSceneContext
|
||||
): GameEvent | undefined => {
|
||||
const {
|
||||
subscene,
|
||||
selectedLevel,
|
||||
|
@ -47,6 +53,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
activePromptComponent,
|
||||
gateLvl,
|
||||
siteSaveState,
|
||||
wordNotFound,
|
||||
} = mainSceneContext;
|
||||
|
||||
if (promptVisible) {
|
||||
|
@ -73,8 +80,6 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
activeLevel: level.toString().padStart(2, "0"),
|
||||
},
|
||||
};
|
||||
console.log(newSiteSaveState);
|
||||
|
||||
return changeSite({
|
||||
newActiveSite: siteToLoad,
|
||||
newActiveNode: stateToLoad.activeNode,
|
||||
|
@ -92,6 +97,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
} else {
|
||||
switch (subscene) {
|
||||
case "site":
|
||||
if (wordNotFound) return hideWordNotFound;
|
||||
switch (keyPress) {
|
||||
case "LEFT":
|
||||
case "RIGHT": {
|
||||
|
@ -169,8 +175,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
else return changeNode({ activeNode: newNode });
|
||||
}
|
||||
case "CIRCLE":
|
||||
const eventAnimation =
|
||||
Math.random() < 0.4 ? "rip_node" : "throw_node";
|
||||
const eventAnimation = Math.random() < 0.4 ? throwNode : ripNode;
|
||||
|
||||
const nodeType = activeNode.type;
|
||||
|
||||
|
@ -181,7 +186,7 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
return;
|
||||
|
||||
if (activeNode.upgrade_requirement > ssknLvl) {
|
||||
const rejectEvents = [explodeNode, knockNode, knockNodeAndFall];
|
||||
const rejectEvents = [knockNodeAndFall, knockNode, explodeNode];
|
||||
return rejectEvents[Math.floor(Math.random() * 3)];
|
||||
}
|
||||
|
||||
|
@ -191,37 +196,19 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
case 4:
|
||||
case 3:
|
||||
case 5:
|
||||
return {
|
||||
event: `${eventAnimation}_media`,
|
||||
mutations: { scene: "media" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "media" });
|
||||
case 6:
|
||||
if (activeNode.node_name.substr(0, 3) === "TaK") {
|
||||
return {
|
||||
event: `${eventAnimation}_tak`,
|
||||
mutations: { scene: "tak" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "tak" });
|
||||
} else {
|
||||
return {
|
||||
event: `${eventAnimation}_media`,
|
||||
mutations: { scene: "media" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "media" });
|
||||
}
|
||||
case 8:
|
||||
return {
|
||||
event: `${eventAnimation}_gate`,
|
||||
mutations: { scene: "gate" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "gate" });
|
||||
case 7:
|
||||
return {
|
||||
event: `${eventAnimation}_sskn`,
|
||||
mutations: { scene: "sskn" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "gate" });
|
||||
case 9:
|
||||
return {
|
||||
event: `${eventAnimation}_polytan`,
|
||||
mutations: { scene: "polytan" },
|
||||
};
|
||||
return eventAnimation({ currentScene: "polytan" });
|
||||
}
|
||||
break;
|
||||
case "L2":
|
||||
|
@ -284,13 +271,12 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
|
|||
switch (keyPress) {
|
||||
case "UP":
|
||||
case "DOWN":
|
||||
const direction = keyPress.toLowerCase();
|
||||
const components = ["load", "about", "change", "save", "exit"];
|
||||
|
||||
const newComponent =
|
||||
components[
|
||||
components.indexOf(activePauseComponent) +
|
||||
(direction === "up" ? -1 : 1)
|
||||
(keyPress === "UP" ? -1 : 1)
|
||||
];
|
||||
|
||||
if (newComponent)
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
import { findNodeFromWord } from "../../utils/media-utils";
|
||||
import { findNodeFromWord } from "../../helpers/media-helpers";
|
||||
import { MediaSceneContext } from "../../store";
|
||||
import { changeLeftMediaComponent, changeMediaSide } from "../eventTemplates";
|
||||
import {
|
||||
changeLeftMediaComponent,
|
||||
changeMediaSide,
|
||||
changeRightMediaComponent,
|
||||
exitMedia,
|
||||
playMedia,
|
||||
selectWord,
|
||||
wordNotFound,
|
||||
} from "../eventTemplates";
|
||||
import { GameEvent } from "../handleEvent";
|
||||
|
||||
const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
||||
const handleMediaSceneKeyPress = (
|
||||
mediaSceneContext: MediaSceneContext
|
||||
): GameEvent | undefined => {
|
||||
const {
|
||||
keyPress,
|
||||
activeMediaComponent,
|
||||
|
@ -19,8 +30,8 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
switch (keyPress) {
|
||||
case "UP":
|
||||
case "DOWN": {
|
||||
const direction = keyPress.toLowerCase();
|
||||
const newComponent = direction === "up" ? "play" : "exit";
|
||||
const newComponent = keyPress === "UP" ? "play" : "exit";
|
||||
|
||||
return changeLeftMediaComponent({ activeComponent: newComponent });
|
||||
}
|
||||
case "RIGHT": {
|
||||
|
@ -36,14 +47,9 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
case "CIRCLE":
|
||||
switch (activeMediaComponent) {
|
||||
case "play":
|
||||
return {
|
||||
event: "media_play_select",
|
||||
node: activeNode,
|
||||
};
|
||||
return playMedia;
|
||||
case "exit":
|
||||
return {
|
||||
event: "media_play_select",
|
||||
};
|
||||
return exitMedia;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -54,6 +60,7 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
wordPosStateIdx - 1 < 1 ? 6 : wordPosStateIdx - 1;
|
||||
const newComponent = (() => {
|
||||
switch (activeMediaComponent) {
|
||||
default:
|
||||
case "fstWord":
|
||||
return "thirdWord";
|
||||
case "sndWord":
|
||||
|
@ -62,17 +69,17 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
return "sndWord";
|
||||
}
|
||||
})();
|
||||
return {
|
||||
event: "media_rightside_up",
|
||||
newActiveComponent: newComponent,
|
||||
return changeRightMediaComponent({
|
||||
activeComponent: newComponent,
|
||||
wordPosStateIdx: newWordPosStateIdx,
|
||||
};
|
||||
});
|
||||
}
|
||||
case "DOWN": {
|
||||
const newWordPosStateIdx =
|
||||
wordPosStateIdx + 1 > 6 ? 1 : wordPosStateIdx + 1;
|
||||
const newComponent = (() => {
|
||||
switch (activeMediaComponent) {
|
||||
default:
|
||||
case "fstWord":
|
||||
return "sndWord";
|
||||
case "sndWord":
|
||||
|
@ -82,11 +89,10 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
event: "media_rightside_down",
|
||||
newActiveComponent: newComponent,
|
||||
return changeRightMediaComponent({
|
||||
activeComponent: newComponent,
|
||||
wordPosStateIdx: newWordPosStateIdx,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
case "LEFT":
|
||||
|
@ -111,9 +117,14 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
|
|||
);
|
||||
|
||||
if (data) {
|
||||
return { event: `media_word_select`, ...data };
|
||||
const { node, level, siteRotY } = { ...data };
|
||||
return selectWord({
|
||||
activeNode: node,
|
||||
activeLevel: level,
|
||||
siteRot: [0, siteRotY, 0],
|
||||
});
|
||||
} else {
|
||||
return { event: `word_node_not_found` };
|
||||
return wordNotFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,42 @@
|
|||
import { SsknSceneContext } from "../../store";
|
||||
import { changeSsknComponent, exitSskn, upgradeSskn } from "../eventTemplates";
|
||||
import { GameEvent } from "../handleEvent";
|
||||
|
||||
const handleSsknSceneKeyPress = (ssknSceneContext: SsknSceneContext) => {
|
||||
const { keyPress, activeSsknComponent, activeNode } = ssknSceneContext;
|
||||
const handleSsknSceneKeyPress = (
|
||||
ssknSceneContext: SsknSceneContext
|
||||
): GameEvent | undefined => {
|
||||
const {
|
||||
keyPress,
|
||||
activeSsknComponent,
|
||||
activeNode,
|
||||
gameProgress,
|
||||
ssknLvl,
|
||||
} = ssknSceneContext;
|
||||
|
||||
switch (keyPress) {
|
||||
case "UP":
|
||||
case "DOWN":
|
||||
return {
|
||||
event: `sskn_${activeSsknComponent}_${keyPress.toLowerCase()}`,
|
||||
};
|
||||
const direction = keyPress.toLowerCase();
|
||||
const newComponent = direction === "up" ? "ok" : "cancel";
|
||||
return changeSsknComponent({ activeSsknComponent: newComponent });
|
||||
case "CIRCLE":
|
||||
if (activeSsknComponent === "ok") {
|
||||
return {
|
||||
event: `sskn_ok_select`,
|
||||
node: activeNode,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
event: `sskn_cancel_select`,
|
||||
};
|
||||
switch (activeSsknComponent) {
|
||||
case "ok":
|
||||
const newGameProgress = {
|
||||
...gameProgress,
|
||||
[activeNode.node_name]: {
|
||||
is_viewed: 1,
|
||||
is_visible: 0,
|
||||
},
|
||||
};
|
||||
const newSsknLvl = ssknLvl + 1;
|
||||
|
||||
return upgradeSskn({
|
||||
gameProgress: newGameProgress,
|
||||
ssknLvl: newSsknLvl,
|
||||
});
|
||||
case "cancel":
|
||||
return exitSskn;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,12 +2,13 @@ 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 { NodeData, SiteData } from "../components/MainScene/Site/Site";
|
||||
import { isNodeVisible } from "./node-utils";
|
||||
import { isNodeVisible } from "./node-helpers";
|
||||
import { ActiveSite, RightMediaComponent } from "../store";
|
||||
|
||||
export const findNodeFromWord = (
|
||||
wordLabel: string,
|
||||
wordLabel: RightMediaComponent,
|
||||
activeNode: NodeData,
|
||||
site: "a" | "b",
|
||||
site: ActiveSite,
|
||||
gameProgress: any
|
||||
) => {
|
||||
const labelToIdx = (() => {
|
||||
|
@ -73,3 +74,18 @@ export const findNodeFromWord = (
|
|||
level: chosenNode.id.substr(0, 2),
|
||||
};
|
||||
};
|
||||
|
||||
export const playMediaElement = () => {
|
||||
const mediaElement = document.getElementById("media") as HTMLMediaElement;
|
||||
|
||||
if (mediaElement && mediaElement.paused) mediaElement.play();
|
||||
};
|
||||
|
||||
export const resetMediaElement = () => {
|
||||
const mediaElement = document.getElementById("media") as HTMLMediaElement;
|
||||
if (mediaElement) {
|
||||
mediaElement.pause();
|
||||
|
||||
mediaElement.currentTime = 0;
|
||||
}
|
||||
};
|
|
@ -1,9 +1,5 @@
|
|||
import { useStore } from "../store";
|
||||
import sleep from "./sleep";
|
||||
|
||||
const setActiveNodePos = useStore.getState().setNodePos;
|
||||
const setActiveNodeRot = useStore.getState().setNodeRot;
|
||||
const setActiveNodeAttributes = useStore.getState().setNodeAttributes;
|
||||
import sleep from "../utils/sleep";
|
||||
|
||||
const calculateCoordsBasedOnRotation = (
|
||||
x: number,
|
||||
|
@ -18,6 +14,10 @@ const calculateCoordsBasedOnRotation = (
|
|||
// throw a warning about an unhandled promise, and we dont care about that.
|
||||
// async/awaits here are used simply to improve readability, nothing else.
|
||||
|
||||
const setActiveNodePos = useStore.getState().setNodePos;
|
||||
const setActiveNodeRot = useStore.getState().setNodeRot;
|
||||
const setActiveNodeAttributes = useStore.getState().setNodeAttributes;
|
||||
|
||||
export const nodeThrowAnimation = () => {
|
||||
(async () => {
|
||||
const siteRotY = useStore.getState().siteRot[1];
|
|
@ -1,10 +1,10 @@
|
|||
import { NodeData, SiteData } from "../components/MainScene/Site/Site";
|
||||
import node_matrices from "../resources/node_matrices.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";
|
||||
import node_huds from "../resources/node_huds.json";
|
||||
import unlocked_nodes from "../resources/initial_progress.json";
|
||||
import node_matrices from "../resources/node_matrices.json";
|
||||
import { GameProgress } from "../store";
|
||||
|
||||
export const generateInactiveNodes = (
|
||||
visibleNodes: SiteData,
|
|
@ -15,7 +15,6 @@ import sleep from "../utils/sleep";
|
|||
const EndScene = () => {
|
||||
const mainCylinderRef = useRef<THREE.Object3D>();
|
||||
|
||||
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
|
||||
const setSelectionVisible = useStore(
|
||||
(state) => state.setEndSceneSelectionVisible
|
||||
);
|
||||
|
@ -110,7 +109,7 @@ const EndScene = () => {
|
|||
mediaElement.load();
|
||||
mediaElement.play();
|
||||
}
|
||||
}, [setAudioAnalyser]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -128,9 +127,7 @@ const EndScene = () => {
|
|||
<EndSphere position={[2, 1.7, -0.5]} outroAnim={sceneOutro} />
|
||||
<LainSpeak intro={isIntro} outro={isOutro} />
|
||||
</group>
|
||||
<group visible={showSelectionScreen}>
|
||||
<EndSelectionScreen />
|
||||
</group>
|
||||
<EndSelectionScreen visible={showSelectionScreen} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,18 +7,20 @@ import { useStore } from "../store";
|
|||
|
||||
const GateScene = () => {
|
||||
const gateLvl = useStore((state) => state.gateLvl);
|
||||
const incrementGateLvl = useStore((state) => state.incrementGateLvl);
|
||||
const [introAnim, setIntroAnim] = useState(true);
|
||||
|
||||
const activeNodeName = useStore((state) => state.activeNode.node_name);
|
||||
const setNodeViewed = useStore((state) => state.setNodeViewed);
|
||||
|
||||
useEffect(() => {
|
||||
incrementGateLvl();
|
||||
setNodeViewed(activeNodeName, {
|
||||
is_viewed: 1,
|
||||
is_visible: 0,
|
||||
});
|
||||
setTimeout(() => setIntroAnim(false), 2500);
|
||||
}, [activeNodeName, setNodeViewed]);
|
||||
}, [activeNodeName, incrementGateLvl, setNodeViewed]);
|
||||
|
||||
return (
|
||||
<perspectiveCamera position-z={3}>
|
||||
|
|
|
@ -14,7 +14,7 @@ import Lain from "../components/MainScene/Lain";
|
|||
import * as THREE from "three";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import Popups from "../components/MainScene/Popups/Popups";
|
||||
import * as audio from "../static/sfx";
|
||||
import * as audio from "../static/audio/sfx";
|
||||
import Loading from "../components/Loading";
|
||||
import usePrevious from "../hooks/usePrevious";
|
||||
|
||||
|
@ -26,6 +26,8 @@ const MainScene = () => {
|
|||
|
||||
const wordSelected = useStore((state) => state.wordSelected);
|
||||
const setWordSelected = useStore((state) => state.setWordSelected);
|
||||
const setInputCooldown = useStore((state) => state.setInputCooldown);
|
||||
const wordNotFound = useStore((state) => state.wordNotFound);
|
||||
|
||||
useEffect(() => {
|
||||
if (subscene === "pause") {
|
||||
|
@ -78,13 +80,27 @@ const MainScene = () => {
|
|||
introWrapperRef.current.rotation.x -= 0.008;
|
||||
}
|
||||
|
||||
// introWrapperRef.current.position.z = THREE.MathUtils.lerp(
|
||||
// introWrapperRef.current.position.z,
|
||||
// intro ? 0 : -10,
|
||||
// 0.01
|
||||
// );
|
||||
//
|
||||
// introWrapperRef.current.rotation.x = THREE.MathUtils.lerp(
|
||||
// introWrapperRef.current.rotation.x,
|
||||
// intro ? 0 : Math.PI / 2,
|
||||
// 0.01
|
||||
// );
|
||||
|
||||
if (
|
||||
!introFinished &&
|
||||
!(
|
||||
introWrapperRef.current.rotation.x > 0 &&
|
||||
introWrapperRef.current.position.z < 0
|
||||
)
|
||||
) {
|
||||
setIntroFinished(true);
|
||||
setInputCooldown(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -97,7 +113,7 @@ const MainScene = () => {
|
|||
<Pause />
|
||||
<group visible={!paused}>
|
||||
<group visible={!wordSelected && (intro ? introFinished : true)}>
|
||||
<group visible={subscene !== "not_found"}>
|
||||
<group visible={!wordNotFound}>
|
||||
<HUD />
|
||||
<MainYellowTextAnimator />
|
||||
</group>
|
||||
|
|
|
@ -71,7 +71,7 @@ const MediaScene = () => {
|
|||
|
||||
useEffect(() => {
|
||||
setLoaded(true);
|
||||
setTimeout(() => setInputCooldown(false), 1000);
|
||||
setTimeout(() => setInputCooldown(500), 1000);
|
||||
}, [setInputCooldown]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -4,7 +4,6 @@ import PolytanBackground from "../components/PolytanScene/PolytanBackground";
|
|||
import { useStore } from "../store";
|
||||
|
||||
const PolytanScene = () => {
|
||||
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);
|
||||
|
@ -34,10 +33,10 @@ const PolytanScene = () => {
|
|||
}, [activeNodeName, setNodeViewed, setPolytanPartUnlocked]);
|
||||
|
||||
return (
|
||||
<perspectiveCamera>
|
||||
<PolytanBear unlockedParts={unlockedParts} />
|
||||
<>
|
||||
<PolytanBear />
|
||||
<PolytanBackground />
|
||||
</perspectiveCamera>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
315
src/store.ts
315
src/store.ts
|
@ -3,35 +3,103 @@ import { combine } from "zustand/middleware";
|
|||
import * as THREE from "three";
|
||||
import game_progress from "./resources/initial_progress.json";
|
||||
import { NodeData } from "./components/MainScene/Site/Site";
|
||||
import { getNodeById } from "./utils/node-utils";
|
||||
import { getNodeById } from "./helpers/node-helpers";
|
||||
import site_a from "./resources/site_a.json";
|
||||
import { AudioAnalyser } from "three";
|
||||
import MainScene from "./scenes/MainScene";
|
||||
import MediaScene from "./scenes/MediaScene";
|
||||
import IdleMediaScene from "./scenes/IdleMediaScene";
|
||||
import GateScene from "./scenes/GateScene";
|
||||
import BootScene from "./scenes/BootScene";
|
||||
import SsknScene from "./scenes/SsknScene";
|
||||
import PolytanScene from "./scenes/PolytanScene";
|
||||
import TaKScene from "./scenes/TaKScene";
|
||||
import ChangeDiscScene from "./scenes/ChangeDiscScene";
|
||||
import EndScene from "./scenes/EndScene";
|
||||
import React from "react";
|
||||
|
||||
export type GameProgress = typeof game_progress;
|
||||
|
||||
type NodeAttributes = {
|
||||
interactedWith: boolean;
|
||||
exploding: boolean;
|
||||
shrinking: boolean;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
export type GameScene =
|
||||
| "main"
|
||||
| "media"
|
||||
| "tak"
|
||||
| "sskn"
|
||||
| "polytan"
|
||||
| "idle_media"
|
||||
| "gate"
|
||||
| "boot"
|
||||
| "change_disc"
|
||||
| "end";
|
||||
|
||||
type MainSubscene = "site" | "pause" | "level_selection";
|
||||
|
||||
export type ActiveSite = "a" | "b";
|
||||
|
||||
export type EndComponent = "end" | "continue";
|
||||
|
||||
export type PauseComponent = "load" | "about" | "change" | "save" | "exit";
|
||||
|
||||
export type MediaSide = "left" | "right";
|
||||
export type LeftMediaComponent = "play" | "exit";
|
||||
export type RightMediaComponent = "fstWord" | "sndWord" | "thirdWord";
|
||||
export type MediaComponent = LeftMediaComponent | RightMediaComponent;
|
||||
|
||||
export type SiteSaveState = {
|
||||
a: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
b: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type SsknComponent = "ok" | "cancel";
|
||||
|
||||
export type MainMenuComponent = "authorize_user" | "load_data";
|
||||
export type BootSubscene = "main_menu" | "load_data" | "authorize_user";
|
||||
|
||||
export type PromptComponent = "yes" | "no";
|
||||
|
||||
type PolytanBodyParts = {
|
||||
body: boolean;
|
||||
head: boolean;
|
||||
leftArm: boolean;
|
||||
rightArm: boolean;
|
||||
leftLeg: boolean;
|
||||
rightLeg: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
currentScene: string;
|
||||
currentScene: GameScene;
|
||||
|
||||
gameProgress: GameProgress;
|
||||
|
||||
mainSubscene: string;
|
||||
mainSubscene: MainSubscene;
|
||||
|
||||
intro: boolean;
|
||||
|
||||
activeNode: NodeData;
|
||||
activeNodePos: number[];
|
||||
activeNodeRot: number[];
|
||||
activeNodeAttributes: {
|
||||
interactedWith: boolean;
|
||||
exploding: boolean;
|
||||
shrinking: boolean;
|
||||
visible: boolean;
|
||||
};
|
||||
activeNodeAttributes: NodeAttributes;
|
||||
|
||||
// lain
|
||||
lainMoveState: string;
|
||||
|
||||
// site
|
||||
activeSite: "a" | "b";
|
||||
activeSite: ActiveSite;
|
||||
siteRot: number[];
|
||||
oldSiteRot: number[];
|
||||
|
||||
|
@ -43,23 +111,23 @@ type State = {
|
|||
selectedLevel: number;
|
||||
|
||||
// end scene
|
||||
activeEndComponent: "end" | "continue";
|
||||
activeEndComponent: EndComponent;
|
||||
endSceneSelectionVisible: boolean;
|
||||
|
||||
// pause
|
||||
activePauseComponent: "load" | "about" | "change" | "save" | "exit";
|
||||
activePauseComponent: PauseComponent;
|
||||
pauseExitAnimation: boolean;
|
||||
showingAbout: boolean;
|
||||
permissionDenied: boolean;
|
||||
|
||||
// media/media scene
|
||||
audioAnalyser: any;
|
||||
audioAnalyser: AudioAnalyser | undefined;
|
||||
mediaPercentageElapsed: number;
|
||||
currentMediaSide: "left" | "right";
|
||||
activeMediaComponent: "play" | "exit" | "fstWord" | "sndWord" | "thirdWord";
|
||||
currentMediaSide: MediaSide;
|
||||
activeMediaComponent: MediaComponent;
|
||||
lastActiveMediaComponents: {
|
||||
left: "play" | "exit";
|
||||
right: "fstWord" | "sndWord" | "thirdWord";
|
||||
left: LeftMediaComponent;
|
||||
right: RightMediaComponent;
|
||||
};
|
||||
|
||||
mediaWordPosStateIdx: number;
|
||||
|
@ -72,19 +140,12 @@ type State = {
|
|||
idleNodeName: string | undefined;
|
||||
|
||||
// sskn scene
|
||||
activeSsknComponent: "ok" | "cancel";
|
||||
activeSsknComponent: SsknComponent;
|
||||
ssknLoading: boolean;
|
||||
ssknLvl: number;
|
||||
|
||||
// polytan scene
|
||||
polytanUnlockedParts: {
|
||||
body: boolean;
|
||||
head: boolean;
|
||||
leftArm: boolean;
|
||||
rightArm: boolean;
|
||||
leftLeg: boolean;
|
||||
rightLeg: boolean;
|
||||
};
|
||||
polytanUnlockedParts: PolytanBodyParts;
|
||||
|
||||
// gate scene
|
||||
gateLvl: number;
|
||||
|
@ -93,40 +154,32 @@ type State = {
|
|||
playerName: string;
|
||||
|
||||
// boot scene
|
||||
activeMainMenuComponent: "authorize_user" | "load_data";
|
||||
activeMainMenuComponent: MainMenuComponent;
|
||||
authorizeUserLetterIdx: number;
|
||||
bootSubscene: "main_menu" | "load_data" | "authorize_user";
|
||||
bootSubscene: BootSubscene;
|
||||
|
||||
// prompt
|
||||
promptVisible: boolean;
|
||||
activePromptComponent: "yes" | "no";
|
||||
activePromptComponent: PromptComponent;
|
||||
|
||||
// status notifiers
|
||||
loadSuccessful: boolean | undefined;
|
||||
saveSuccessful: boolean | undefined;
|
||||
|
||||
// save state
|
||||
siteSaveState: {
|
||||
a: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
b: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
};
|
||||
// word not found notification thing
|
||||
wordNotFound: boolean;
|
||||
|
||||
inputCooldown: boolean;
|
||||
// save state
|
||||
siteSaveState: SiteSaveState;
|
||||
|
||||
inputCooldown: number;
|
||||
};
|
||||
|
||||
export const useStore = create(
|
||||
combine(
|
||||
{
|
||||
// scene data
|
||||
currentScene: "media",
|
||||
currentScene: "main",
|
||||
|
||||
// game progress
|
||||
gameProgress: game_progress,
|
||||
|
@ -232,6 +285,9 @@ export const useStore = create(
|
|||
loadSuccessful: undefined,
|
||||
saveSuccessful: undefined,
|
||||
|
||||
// word not found notification thing
|
||||
wordNotFound: false,
|
||||
|
||||
// save states for loading the game/changing sites
|
||||
siteSaveState: {
|
||||
a: {
|
||||
|
@ -252,13 +308,11 @@ export const useStore = create(
|
|||
},
|
||||
},
|
||||
|
||||
inputCooldown: false,
|
||||
inputCooldown: -1,
|
||||
} as State,
|
||||
(set) => ({
|
||||
// scene data setters
|
||||
setScene: (to: string) => set(() => ({ currentScene: to })),
|
||||
setScene: (to: GameScene) => set(() => ({ currentScene: to })),
|
||||
|
||||
// node setters
|
||||
setNodePos: (to: number[]) => set(() => ({ activeNodePos: to })),
|
||||
setNodeRot: (to: number[]) => set(() => ({ activeNodeRot: to })),
|
||||
setNodeAttributes: (
|
||||
|
@ -269,102 +323,6 @@ export const useStore = create(
|
|||
activeNodeAttributes: { ...state.activeNodeAttributes, [at]: to },
|
||||
})),
|
||||
|
||||
// lain setters
|
||||
setLainMoveState: (to: string) => set(() => ({ lainMoveState: to })),
|
||||
|
||||
// site setters
|
||||
setSiteRotX: (to: number) =>
|
||||
set((prev) => {
|
||||
const nextRot = [...prev.siteRot];
|
||||
nextRot[0] = to;
|
||||
return { siteRot: nextRot };
|
||||
}),
|
||||
|
||||
// end scene setters
|
||||
setEndSceneSelectionVisible: (to: boolean) =>
|
||||
set(() => ({ endSceneSelectionVisible: to })),
|
||||
|
||||
// pause setters
|
||||
setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })),
|
||||
|
||||
// media scene setters
|
||||
setAudioAnalyser: (to: any) => set(() => ({ audioAnalyser: to })),
|
||||
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 })),
|
||||
setIdleScene: (to: {
|
||||
images: { "1": string; "2": string; "3": string } | undefined;
|
||||
media: string | undefined;
|
||||
nodeName: string | undefined;
|
||||
}) =>
|
||||
set(() => ({
|
||||
idleMedia: to.media,
|
||||
idleImages: to.images,
|
||||
idleNodeName: to.nodeName,
|
||||
})),
|
||||
|
||||
//polytan setters
|
||||
setPolytanPartUnlocked: (bodyPart: string) =>
|
||||
set((state) => ({
|
||||
polytanUnlockedParts: {
|
||||
...state.polytanUnlockedParts,
|
||||
[bodyPart]: true,
|
||||
},
|
||||
})),
|
||||
|
||||
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,
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
|
||||
// progress setters
|
||||
setNodeViewed: (
|
||||
nodeName: string,
|
||||
to: { is_viewed: number; is_visible: number }
|
||||
|
@ -376,13 +334,37 @@ export const useStore = create(
|
|||
},
|
||||
})),
|
||||
|
||||
setInputCooldown: (to: boolean) => set(() => ({ inputCooldown: to })),
|
||||
setLainMoveState: (to: string) => set(() => ({ lainMoveState: to })),
|
||||
|
||||
setEndSceneSelectionVisible: (to: boolean) =>
|
||||
set(() => ({ endSceneSelectionVisible: to })),
|
||||
|
||||
setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })),
|
||||
|
||||
setAudioAnalyser: (to: AudioAnalyser) =>
|
||||
set(() => ({ audioAnalyser: to })),
|
||||
setPercentageElapsed: (to: number) =>
|
||||
set(() => ({ mediaPercentageElapsed: to })),
|
||||
setWordSelected: (to: boolean) => set(() => ({ wordSelected: to })),
|
||||
|
||||
setPolytanPartUnlocked: (bodyPart: string) =>
|
||||
set((state) => ({
|
||||
polytanUnlockedParts: {
|
||||
...state.polytanUnlockedParts,
|
||||
[bodyPart]: true,
|
||||
},
|
||||
})),
|
||||
|
||||
setInputCooldown: (to: number) => set(() => ({ inputCooldown: to })),
|
||||
|
||||
incrementGateLvl: () => set((state) => ({ gateLvl: state.gateLvl + 1 })),
|
||||
incrementSsknLvl: () => set((state) => ({ ssknLvl: state.ssknLvl + 1 })),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
type PromptContext = {
|
||||
activePromptComponent: "yes" | "no";
|
||||
activePromptComponent: PromptComponent;
|
||||
promptVisible: boolean;
|
||||
};
|
||||
|
||||
|
@ -401,25 +383,15 @@ export interface MainSceneContext extends PromptContext {
|
|||
activeNode: NodeData;
|
||||
showingAbout: boolean;
|
||||
level: number;
|
||||
activePauseComponent: "load" | "about" | "change" | "save" | "exit";
|
||||
activePauseComponent: PauseComponent;
|
||||
gameProgress: GameProgress;
|
||||
gateLvl: number;
|
||||
subscene: string;
|
||||
siteRotY: number;
|
||||
activeSite: "a" | "b";
|
||||
activeSite: ActiveSite;
|
||||
selectedLevel: number;
|
||||
siteSaveState: {
|
||||
a: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
b: {
|
||||
activeNode: NodeData;
|
||||
siteRot: number[];
|
||||
activeLevel: string;
|
||||
};
|
||||
};
|
||||
wordNotFound: boolean;
|
||||
siteSaveState: SiteSaveState;
|
||||
}
|
||||
|
||||
export const getMainSceneContext = (keyPress: string): MainSceneContext => {
|
||||
|
@ -440,13 +412,16 @@ export const getMainSceneContext = (keyPress: string): MainSceneContext => {
|
|||
showingAbout: state.showingAbout,
|
||||
gateLvl: state.gateLvl,
|
||||
siteSaveState: state.siteSaveState,
|
||||
wordNotFound: state.wordNotFound,
|
||||
};
|
||||
};
|
||||
|
||||
export type SsknSceneContext = {
|
||||
keyPress: string;
|
||||
activeSsknComponent: "ok" | "cancel";
|
||||
activeSsknComponent: SsknComponent;
|
||||
activeNode: NodeData;
|
||||
gameProgress: GameProgress;
|
||||
ssknLvl: number;
|
||||
};
|
||||
|
||||
export const getSsknSceneContext = (keyPress: string): SsknSceneContext => {
|
||||
|
@ -455,21 +430,23 @@ export const getSsknSceneContext = (keyPress: string): SsknSceneContext => {
|
|||
keyPress: keyPress,
|
||||
activeSsknComponent: state.activeSsknComponent,
|
||||
activeNode: state.activeNode,
|
||||
gameProgress: state.gameProgress,
|
||||
ssknLvl: state.ssknLvl,
|
||||
};
|
||||
};
|
||||
|
||||
export type MediaSceneContext = {
|
||||
keyPress: string;
|
||||
wordPosStateIdx: number;
|
||||
currentMediaSide: "left" | "right";
|
||||
activeMediaComponent: "play" | "exit" | "fstWord" | "sndWord" | "thirdWord";
|
||||
currentMediaSide: MediaSide;
|
||||
activeMediaComponent: MediaComponent;
|
||||
activeNode: NodeData;
|
||||
gameProgress: GameProgress;
|
||||
lastActiveMediaComponents: {
|
||||
left: "play" | "exit";
|
||||
right: "fstWord" | "sndWord" | "thirdWord";
|
||||
left: LeftMediaComponent;
|
||||
right: RightMediaComponent;
|
||||
};
|
||||
activeSite: "a" | "b";
|
||||
activeSite: ActiveSite;
|
||||
};
|
||||
|
||||
export const getMediaSceneContext = (keyPress: string): MediaSceneContext => {
|
||||
|
@ -490,8 +467,8 @@ export const getMediaSceneContext = (keyPress: string): MediaSceneContext => {
|
|||
export interface BootSceneContext extends PromptContext {
|
||||
keyPress: string;
|
||||
playerName: string;
|
||||
subscene: "main_menu" | "load_data" | "authorize_user";
|
||||
activeMainMenuComponent: "load_data" | "authorize_user";
|
||||
subscene: BootSubscene;
|
||||
activeMainMenuComponent: MainMenuComponent;
|
||||
authorizeUserLetterIdx: number;
|
||||
}
|
||||
|
||||
|
@ -510,7 +487,7 @@ export const getBootSceneContext = (keyPress: string): BootSceneContext => {
|
|||
|
||||
export type EndSceneContext = {
|
||||
keyPress: string;
|
||||
activeEndComponent: "end" | "continue";
|
||||
activeEndComponent: EndComponent;
|
||||
selectionVisible: boolean;
|
||||
};
|
||||
|
||||
|
|
2
src/tests/media-helpers.test.ts
Normal file
2
src/tests/media-helpers.test.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { findNodeFromWord } from "../helpers/media-helpers";
|
||||
|
Loading…
Reference in a new issue