event rewrite done, fixed a lot of stuff, renamed/moved some stuff

This commit is contained in:
ad044 2021-02-20 18:35:23 +04:00
parent 7620610097
commit 1d895e64b0
36 changed files with 791 additions and 761 deletions

View file

@ -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;

View file

@ -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.

View file

@ -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);
}
}
},

View file

@ -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>

View file

@ -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

View file

@ -64,7 +64,7 @@ const Pause = () => {
setTimeout(() => {
setShowActiveComponent(true);
setIntro(false);
setInputCooldown(false);
setInputCooldown(1000);
}, 3500);
}, 3400);
}

View file

@ -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"

View file

@ -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;

View file

@ -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 = {

View file

@ -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;

View file

@ -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;

View file

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

View file

@ -1,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,
},
},
],
});

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

@ -1,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;
}
}
};

View file

@ -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;
}
}
}
};

View file

@ -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)

View file

@ -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;
}
}
}

View file

@ -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;
}
}
};

View file

@ -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;
}
};

View file

@ -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];

View file

@ -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,

View file

@ -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} />
</>
);
};

View file

@ -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}>

View file

@ -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>

View file

@ -71,7 +71,7 @@ const MediaScene = () => {
useEffect(() => {
setLoaded(true);
setTimeout(() => setInputCooldown(false), 1000);
setTimeout(() => setInputCooldown(500), 1000);
}, [setInputCooldown]);
return (

View file

@ -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>
</>
);
};

View file

@ -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;
};

View file

@ -0,0 +1,2 @@
import { findNodeFromWord } from "../helpers/media-helpers";