merged popups, main scene events done moving on to media

This commit is contained in:
ad044 2021-02-19 21:57:02 +04:00
parent 93d1b442ea
commit 7620610097
32 changed files with 561 additions and 862 deletions

View file

@ -1,12 +1,16 @@
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";
@ -18,11 +22,11 @@ import { useFrame } from "react-three-fiber";
import { getRandomIdleLainAnim } from "../utils/idle-utils";
import * as audio from "../static/sfx";
import handleEndSceneKeyPress from "../core/scene-keypress-handlers/handleEndSceneKeyPress";
import handleMainSceneEvent from "../core/scene-event-handlers/handleMainSceneEvent";
import handleMediaSceneEvent from "../core/scene-event-handlers/handleMediaSceneEvent";
import handleSsknSceneEvent from "../core/scene-event-handlers/handleSsknSceneEvent";
import handleBootSceneEvent from "../core/scene-event-handlers/handleBootSceneEvent";
import handleEndSceneEvent from "../core/scene-event-handlers/handleEndSceneEvent";
import handleEvent from "../core/scene-event-handlers/handleEvent";
const KeyPressHandler = () => {
const scene = useStore((state) => state.currentScene);
@ -79,66 +83,66 @@ const KeyPressHandler = () => {
const now = Date.now();
if (
keyPress &&
!inputCooldown &&
now > timeSinceLastKeyPress.current + 1500
keyPress
// !inputCooldown &&
// now > timeSinceLastKeyPress.current + 1500
) {
if (scene === "main") {
lainIdleCounter.current = now;
idleSceneCounter.current = now;
timeSinceLastKeyPress.current = now;
}
const sceneFns = (() => {
switch (scene) {
case "main":
return {
contextProvider: getMainSceneContext,
keyPressHandler: handleMainSceneKeyPress,
eventHandler: handleMainSceneEvent,
};
case "media":
return {
contextProvider: getMediaSceneContext,
keyPressHandler: handleMediaSceneKeyPress,
eventHandler: handleMediaSceneEvent,
};
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,
// eventHandler: handleSsknSceneEvent,
// };
// case "boot":
// return {
// contextProvider: getBootSceneContext,
// keyPressHandler: handleBootSceneKeyPress,
// eventHandler: handleBootSceneEvent,
// };
// case "end":
// return {
// contextProvider: getEndSceneContext,
// keyPressHandler: handleEndSceneKeyPress,
// eventHandler: handleEndSceneEvent,
// };
// case "gate":
// case "polytan":
// useStore.setState({ currentScene: "main" });
// break;
// case "idle_media":
// useStore.setState({
// currentScene: "main",
// idleStarting: false,
// });
// break;
}
})();
if (sceneFns) {
const { contextProvider, keyPressHandler, eventHandler } = sceneFns;
const { contextProvider, keyPressHandler } = sceneFns;
const ctx = contextProvider(keyPress);
const event = keyPressHandler(ctx);
if (event) eventHandler(event);
const event = keyPressHandler(ctx as any) as any;
if (event) handleEvent(event);
// if (event) eventHandler(event.event, event.mutations);
}
}
},

View file

@ -1,7 +1,7 @@
import React, { useMemo, useRef, memo } from "react";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import GrayPlane from "./GrayPlanes/GrayPlane";
import GrayPlane from "./GrayPlane";
const GrayPlanes = memo(() => {
const grayPlaneGroupRef = useRef<THREE.Object3D>();

View file

@ -1,7 +1,7 @@
import React, {Suspense, useEffect, useMemo, useRef, useState} from "react";
import {useFrame, useLoader} from "react-three-fiber";
import React, { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import {PlainSingularAnimator} from "three-plain-animator/lib/plain-singular-animator";
import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-animator";
import moveDownSpriteSheet from "../../static/sprite/jump_down.png";
import moveUpSpriteSheet from "../../static/sprite/jump_up.png";
import moveLeftSpriteSheet from "../../static/sprite/move_left.png";
@ -12,7 +12,7 @@ import throwNodeSpriteSheet from "../../static/sprite/throw_node.png";
import ripMiddleRingSpriteSheet from "../../static/sprite/rip_middle_ring.png";
import knockSpriteSheet from "../../static/sprite/knock.png";
import knockAndFallSpriteSheet from "../../static/sprite/knock_and_fall.png";
import touchAndScareSpriteSheet from "../../static/sprite/touch_and_scare.png";
import touchAndScareSpriteSheet from "../../static/sprite/touch_node_and_get_scared.png";
import ripNodeSpriteSheet from "../../static/sprite/rip_node.png";
import touchSleeveSpriteSheet from "../../static/sprite/touch_sleeve.png";
import prayerSpriteSheet from "../../static/sprite/prayer.png";
@ -32,7 +32,7 @@ import leanRightSpriteSheet from "../../static/sprite/lean_right.png";
import lookAroundSpriteSheet from "../../static/sprite/look_around.png";
import playWithHairSpriteSheet from "../../static/sprite/play_with_hair.png";
import {useStore} from "../../store";
import { useStore } from "../../store";
type LainConstructorProps = {
sprite: string;
@ -368,17 +368,17 @@ const Lain = (props: LainProps) => {
const lainAnimationDispatch = useMemo(() => {
const anims = {
standing: <LainStanding />,
site_left: <LainMoveLeft />,
site_right: <LainMoveRight />,
site_up: <LainMoveUp />,
site_down: <LainMoveDown />,
move_left: <LainMoveLeft />,
move_right: <LainMoveRight />,
jump_up: <LainMoveUp />,
jump_down: <LainMoveDown />,
knock_and_fall: <LainKnockAndFall />,
touch_and_scare: <LainTouchAndScare />,
touch_node_and_get_scared: <LainTouchAndScare />,
knock: <LainKnock />,
select_level_down: <LainMoveDown />,
select_level_up: <LainMoveUp />,
throw_node: <LainThrowNode />,
pause_game: <LainRipMiddleRing />,
rip_middle_ring: <LainRipMiddleRing />,
rip_node: <LainRipNode />,
prayer: <LainPrayer />,
scratch_head: <LainScratchHead />,

View file

@ -1,13 +1,13 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import middleRingTexture from "../../static/sprite/middle_ring_tex.png";
import middleRingTexture from "../../../static/sprite/middle_ring_tex.png";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../store";
import MiddleRingPart from "./MiddleRing/MiddleRingPart";
import usePrevious from "../../hooks/usePrevious";
import lerp from "../../utils/lerp";
import sleep from "../../utils/sleep";
import { useStore } from "../../../store";
import MiddleRingPart from "./MiddleRingPart";
import usePrevious from "../../../hooks/usePrevious";
import lerp from "../../../utils/lerp";
import sleep from "../../../utils/sleep";
const MiddleRing = () => {
const middleRingTex = useLoader(THREE.TextureLoader, middleRingTexture);

View file

@ -1,48 +0,0 @@
import React from "react";
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";
type NotFoundProps = {
visible: boolean;
};
const NotFound = (props: NotFoundProps) => {
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
return (
<>
{props.visible && (
<>
<sprite
scale={[1, 0.25, 0]}
renderOrder={106}
position={[-1, -0.05, 0]}
>
<spriteMaterial
attach="material"
map={notFoundLofTex}
depthTest={false}
/>
</sprite>
<sprite
scale={[4.1, 0.6, 0]}
renderOrder={105}
position={[0, -0.15, 0]}
>
<spriteMaterial
attach="material"
map={notFoundTex}
depthTest={false}
/>
</sprite>
</>
)}
</>
);
};
export default NotFound;

View file

@ -50,6 +50,8 @@ const Pause = () => {
const subscene = useStore((state) => state.mainSubscene);
const setInputCooldown = useStore((state) => state.setInputCooldown);
useEffect(() => {
setAnimation(false);
setIntro(true);
@ -62,10 +64,11 @@ const Pause = () => {
setTimeout(() => {
setShowActiveComponent(true);
setIntro(false);
setInputCooldown(false);
}, 3500);
}, 3400);
}
}, [subscene]);
}, [setInputCooldown, subscene]);
return (
<>

View file

@ -1,42 +0,0 @@
import React from "react";
import About from "./About";
import Prompt from "../../Prompt";
import PermissionDenied from "./PermissionDenied";
import { useStore } from "../../../store";
import Status from "../../Status";
const PausePopUps = () => {
const subscene = useStore((state) => state.mainSubscene);
const showingAbout = useStore((state) => state.showingAbout);
const promptVisible = useStore((state) => state.promptVisible);
const permissionDenied = useStore((state) => state.permissionDenied);
return (
<group
position={[-0.85, -0.7, 0]}
scale={[0.85, 0.85, 0]}
visible={subscene === "pause"}
>
{showingAbout && <About />}
<group
position={[1, 0.6, 0]}
scale={[1.2, 1.2, 0]}
visible={promptVisible}
>
<Prompt />
</group>
<group
position={[1, 0.6, 0]}
scale={[1.2, 1.2, 0]}
visible={permissionDenied}
>
<PermissionDenied />
</group>
<Status />
</group>
);
};
export default PausePopUps;

View file

@ -5,6 +5,7 @@ import * as THREE from "three";
import { useStore } from "../../../store";
const About = () => {
const showingAbout = useStore((state) => state.showingAbout);
const setShowingAbout = useStore((state) => state.setShowingAbout);
const aboutBgTex = useLoader(THREE.TextureLoader, aboutBg);
@ -23,17 +24,29 @@ const About = () => {
return (
<>
<sprite renderOrder={199} scale={[100, 100, 0]}>
<spriteMaterial attach="material" color={0x000000} depthTest={false} />
</sprite>
<sprite
ref={bgRef}
scale={[10.5 / 2.5, 52.8 / 2.5, 0]}
position={[1.1, -13, 0.1]}
renderOrder={200}
>
<spriteMaterial attach="material" map={aboutBgTex} depthTest={false} />
</sprite>
{showingAbout && (
<>
<sprite renderOrder={199} scale={[100, 100, 0]}>
<spriteMaterial
attach="material"
color={0x000000}
depthTest={false}
/>
</sprite>
<sprite
ref={bgRef}
scale={[10.5 / 2.5, 52.8 / 2.5, 0]}
position={[1.1, -13, 0.1]}
renderOrder={200}
>
<spriteMaterial
attach="material"
map={aboutBgTex}
depthTest={false}
/>
</sprite>
</>
)}
</>
);
};

View file

@ -0,0 +1,28 @@
import React, { memo } from "react";
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";
const NotFound = memo(() => {
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
return (
<group visible={false}>
<sprite scale={[1, 0.25, 0]} renderOrder={106} position={[-1, -0.05, 0]}>
<spriteMaterial
attach="material"
map={notFoundLofTex}
depthTest={false}
/>
</sprite>
<sprite scale={[4.1, 0.6, 0]} renderOrder={105} position={[0, -0.15, 0]}>
<spriteMaterial attach="material" map={notFoundTex} depthTest={false} />
</sprite>
</group>
);
});
export default NotFound;

View file

@ -3,13 +3,16 @@ import headerContainer from "../../../static/sprite/prompt_question_container.pn
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import StaticOrangeLetter from "../../TextRenderer/StaticOrangeLetter";
import { useStore } from "../../../store";
const PermissionDenied = memo(() => {
const headerContainerTex = useLoader(THREE.TextureLoader, headerContainer);
const permissionDenied = useStore((state) => state.permissionDenied);
return (
<>
<sprite scale={[4.1, 0.3, 0]} renderOrder={200} position={[0, 0.2, 0]}>
<group position={[0, 0.5, 0]} visible={permissionDenied}>
<sprite scale={[5, 0.36, 0]} renderOrder={200} position={[1, 0.2, 0]}>
<spriteMaterial
map={headerContainerTex}
attach="material"
@ -18,16 +21,12 @@ const PermissionDenied = memo(() => {
depthTest={false}
/>
</sprite>
<group scale={[0.08, 0.7, 0]} position={[-1, 0.19, 0]}>
<group scale={[0.08, 0.7, 0]} position={[0, 0.19, 0]}>
{"Permission denied".split("").map((letter, idx) => (
<StaticOrangeLetter
letter={letter}
letterIdx={idx}
key={idx}
/>
<StaticOrangeLetter letter={letter} letterIdx={idx} key={idx} />
))}
</group>
</>
</group>
);
});

View file

@ -0,0 +1,24 @@
import React, { memo } from "react";
import About from "./About";
import Prompt from "../../Prompt";
import PermissionDenied from "./PermissionDenied";
import Status from "../../Status";
import NotFound from "./NotFound";
const Popups = memo(() => {
return (
<>
<group position={[-0.85, -0.7, 0]} scale={[0.85, 0.85, 0]}>
<group position={[1, 0.6, 0]} scale={[1.2, 1.2, 0]}>
<Prompt />
</group>
<About />
<PermissionDenied />
<Status />
</group>
<NotFound />
</>
);
});
export default Popups;

View file

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

View file

@ -1,7 +1,7 @@
import React, { memo, useEffect, useState } from "react";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import { SiteData } from "../Site";
import { SiteData } from "./Site";
import InactiveLevelNode from "./InactiveLevelNode";
import usePrevious from "../../../hooks/usePrevious";
import { generateInactiveNodes } from "../../../utils/node-utils";

View file

@ -1,15 +1,15 @@
import React, { Suspense, useEffect, useMemo } from "react";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../store";
import ActiveLevelNodes from "./Site/ActiveLevelNodes";
import Rings from "./Site/Rings";
import NodeAnimations from "./Site/NodeAnimations";
import InactiveLevelNodes from "./Site/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 Loading from "../Loading";
import { useStore } from "../../../store";
import ActiveLevelNodes from "./ActiveLevelNodes";
import Rings from "./Rings";
import NodeAnimations from "./NodeAnimations";
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 Loading from "../../Loading";
export type NodeData = {
id: string;

View file

@ -1,5 +1,5 @@
import React, { memo, useEffect, useMemo, useState } from "react";
import Star from "./Starfield/Star";
import Star from "./Star";
type StarfieldProps = {
shouldIntro: boolean;

View file

@ -13,7 +13,7 @@ import ripNodeSpriteSheet from "../static/sprite/rip_node.png";
import prayerSpriteSheet from "../static/sprite/prayer.png";
import knockSpriteSheet from "../static/sprite/knock.png";
import knockAndFallSpriteSheet from "../static/sprite/knock_and_fall.png";
import touchAndScareSpriteSheet from "../static/sprite/touch_and_scare.png";
import touchAndScareSpriteSheet from "../static/sprite/touch_node_and_get_scared.png";
import touchSleeveSpriteSheet from "../static/sprite/touch_sleeve.png";
import thinkingSpriteSheet from "../static/sprite/thinking.png";
import stretchSpriteSheet from "../static/sprite/stretch.png";

View file

@ -1,4 +1,4 @@
import React from "react";
import React, { memo } from "react";
import answerContainer from "../static/sprite/prompt_answer_container.png";
import questionContainer from "../static/sprite/prompt_question_container.png";
import yes from "../static/sprite/prompt_yes.png";
@ -8,7 +8,7 @@ import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";
const Prompt = () => {
const Prompt = memo(() => {
const questionContainerTex = useLoader(
THREE.TextureLoader,
questionContainer
@ -20,8 +20,10 @@ const Prompt = () => {
const activeComponent = useStore((state) => state.activePromptComponent);
const promptVisible = useStore((state) => state.promptVisible);
return (
<>
<group visible={promptVisible}>
<sprite scale={[4.1, 0.3, 0]} renderOrder={200} position={[0, 0.2, 0]}>
<spriteMaterial
map={questionContainerTex}
@ -79,8 +81,8 @@ const Prompt = () => {
depthTest={false}
/>
</sprite>
</>
</group>
);
};
});
export default Prompt;

View file

@ -1,4 +1,4 @@
import { NodeData } from "../components/MainScene/Site";
import { NodeData } from "../components/MainScene/Site/Site";
import * as audio from "../static/sfx";
import {
nodeExplodeAnimation,
@ -7,6 +7,7 @@ import {
nodeRipAnimation,
nodeThrowAnimation,
} from "../utils/node-animations";
import { playAudio } from "../store";
export const siteMoveHorizontal = (calculatedState: {
lainMoveAnimation: string;
@ -263,3 +264,159 @@ export const changePauseComponent = (calculatedState: {
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
});
export const showPermissionDenied = {
state: [
{ mutation: { permissionDenied: true }, delay: 0 },
{ mutation: { permissionDenied: false }, delay: 1200 },
],
audio: [{ sfx: [audio.sound0], delay: 0 }],
};
export const displayPrompt = {
state: [{ mutation: { promptVisible: true }, delay: 0 }],
audio: [{ sfx: [audio.sound0], delay: 0 }],
};
export const showAbout = {
state: [{ mutation: { showingAbout: true }, delay: 0 }],
audio: [{ sfx: [audio.sound0], delay: 0 }],
};
export const exitPause = (calculatedState: { siteRot: number[] }) => ({
state: [
{
mutation: {
siteRot: calculatedState.siteRot,
pauseExitAnimation: true,
activePauseComponent: "change",
inputCooldown: true,
},
delay: 0,
},
{
mutation: {
mainSubscene: "site",
inputCooldown: false,
lainMoveState: "standing",
},
delay: 1200,
},
],
audio: [{ sfx: [audio.sound0], delay: 0 }],
});
export const exitAbout = {
state: [{ mutation: { showingAbout: false }, delay: 0 }],
};
export const changePromptComponent = (calculatedState: {
activePromptComponent: "yes" | "no";
}) => ({
state: [
{
mutation: {
activePromptComponent: calculatedState.activePromptComponent,
},
delay: 0,
},
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
});
export const exitPrompt = {
state: [
{
mutation: { activePromptComponent: "no", promptVisible: false },
delay: 0,
},
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
};
// todo actually save
export const saveGame = () => ({
state: [
{
mutation: { saveSuccessful: true },
delay: 0,
},
{
mutation: { saveSuccessful: undefined },
delay: 1200,
},
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
});
// todo actually load
export const loadGame = () => ({
state: [
{
mutation: { loadSuccessful: true },
delay: 0,
},
{
mutation: { loadSuccessful: undefined },
delay: 1200,
},
],
audio: [{ sfx: [audio.sound28], delay: 0 }],
});
export const changeSite = (calculatedState: {
newActiveSite: "a" | "b";
newActiveNode: NodeData;
newActiveLevel: string;
newSiteRot: number[];
newSiteSaveState: {
a: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
b: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
};
}) => ({
state: [
{
mutation: {
currentScene: "change_disc",
lainMoveState: "standing",
promptVisible: false,
activePromptComponent: "no",
mainSubscene: "site",
// load state
activeSite: calculatedState.newActiveSite,
activeNode: calculatedState.newActiveNode,
siteRot: calculatedState.newSiteRot,
activeLevel: calculatedState.newActiveLevel,
// save state
siteSaveState: calculatedState.newSiteSaveState,
},
delay: 0,
},
],
});
export const changeLeftMediaComponent = (calculatedState: {
activeComponent: "play" | "exit";
}) => ({
state: [
{ mutation: { activeMediaComponent: calculatedState.activeComponent } },
],
audio: [{ sfx: [audio.sound1], delay: 0 }],
});
export const changeMediaSide = (calculatedState: {
activeMediaComponent: "fstWord" | "sndWord" | "thirdWord" | "exit" | "play";
lastActiveMediaComponents: {
left: "play" | "exit";
right: "fstWord" | "sndWord" | "thirdWord";
};
currentMediaSide: "right" | "left";
}) => ({});

View file

@ -2,7 +2,7 @@ import { playAudio, useStore } from "../../store";
import sleep from "../../utils/sleep";
type Mutation = {
mutation: any;
mutation: Object;
delay: number;
};
@ -19,7 +19,6 @@ type Event = {
// the async/await here might be misleading for some, it functions as a setTimeout that fires
// multiple async calls without stopping the execution, which is what we want.
const handleEvent = (event: Event) => {
const now = performance.now();
const setState = useStore.setState;
@ -42,7 +41,7 @@ const handleEvent = (event: Event) => {
});
}
console.log(performance.now() - now);
// console.log(performance.now() - now);
};
export default handleEvent;

View file

@ -1,321 +0,0 @@
import { playAudio, useStore } from "../../store";
import sleep from "../../utils/sleep";
import * as audio from "../../static/sfx";
import { NodeData } from "../../components/MainScene/Site";
import {
nodeKnock,
nodeKnockAndFall,
nodeRip,
nodeThrow,
nodeTouchAndScare,
} from "../../utils/node-animations";
type MainSceneMutations = {
level?: string;
node?: NodeData;
};
const handleMainSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const changeSite = useStore.getState().changeSite;
switch (eventState.event) {
case "site_up":
case "site_down":
(async () => {
setState({
lainMoveState: eventState.event,
activeLevel: eventState.level,
inputCooldown: true,
});
playAudio(audio.sound13);
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
await sleep(1400);
playAudio(audio.sound8);
await sleep(1200);
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "site_left":
case "site_right":
(async () => {
setState({
lainMoveState: eventState.event,
siteRot: [0, eventState.siteRotY, 0],
inputCooldown: true,
});
await sleep(1100);
playAudio(audio.sound6);
playAudio(audio.sound34);
await sleep(2800);
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "change_node":
setState({ activeNode: eventState.node });
playAudio(audio.sound1);
break;
case "throw_node_media":
case "throw_node_sskn":
case "throw_node_gate":
case "throw_node_tak":
case "throw_node_polytan":
(async () => {
setState({
lainMoveState: "throw_node",
oldLevel: eventState.level,
oldSiteRot: [eventState.siteRotY, 0],
inputCooldown: true,
});
nodeThrow(eventState.siteRotY);
playAudio(audio.sound0);
await sleep(1600);
playAudio(audio.sound12);
await sleep(1200);
playAudio(audio.sound13);
playAudio(audio.sound14);
await sleep(650);
setState({
currentScene: eventState.event.split("_")[2],
intro: false,
lainMoveState: "standing",
});
})();
break;
case "rip_node_media":
case "rip_node_gate":
case "rip_node_sskn":
case "rip_node_tak":
case "rip_node_polytan":
(async () => {
setState({
lainMoveState: "rip_node",
oldLevel: eventState.level,
oldSiteRot: [eventState.siteRotY, 0],
inputCooldown: true,
});
nodeRip(eventState.siteRotY);
playAudio(audio.sound0);
await sleep(1600);
playAudio(audio.sound12);
await sleep(2400);
playAudio(audio.sound15);
playAudio(audio.sound13);
await sleep(2000);
setState({
currentScene: eventState.event.split("_")[2],
intro: false,
lainMoveState: "standing",
});
})();
break;
case "touch_and_scare":
(async () => {
setState({
lainMoveState: "touch_and_scare",
inputCooldown: true,
});
nodeTouchAndScare(eventState.siteRotY);
await sleep(2400);
playAudio(audio.sound17);
await sleep(750);
playAudio(audio.sound33);
await sleep(650);
setState({
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "knock":
(async () => {
setState({ lainMoveState: "knock", inputCooldown: true });
nodeKnock(eventState.siteRotY);
await sleep(1200);
playAudio(audio.sound18);
await sleep(1700);
setState({ lainMoveState: "standing", inputCooldown: false });
})();
break;
case "knock_and_fall":
(async () => {
setState({ lainMoveState: "knock_and_fall", inputCooldown: true });
nodeKnockAndFall(eventState.siteRotY);
await sleep(1200);
playAudio(audio.sound18);
await sleep(1100);
playAudio(audio.sound19);
await sleep(850);
playAudio(audio.sound33);
await sleep(3350);
setState({ lainMoveState: "standing", inputCooldown: false });
})();
break;
case "enter_level_selection":
setState({
selectedLevel: eventState.level,
mainSubscene: "level_selection",
});
playAudio(audio.sound1);
break;
case "level_selection_up":
case "level_selection_down":
setState({ selectedLevel: eventState.selectedLevelIdx });
break;
case "level_selection_back":
setState({ mainSubscene: "site" });
playAudio(audio.sound1);
break;
case "select_level_up":
case "select_level_down":
(async () => {
setState({
lainMoveState: eventState.event,
activeLevel: eventState.level,
mainSubscene: "site",
inputCooldown: true,
});
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
await sleep(1400);
playAudio(audio.sound8);
await sleep(1200);
setState({
activeNode: eventState.node,
lainMoveState: "standing",
inputCooldown: false,
});
})();
break;
case "exit_not_found":
setState({ mainSubscene: "site" });
break;
case "pause_game":
(async () => {
setState({
lainMoveState: "pause_game",
pauseExitAnimation: false,
mainSubscene: "pause",
inputCooldown: true,
});
playAudio(audio.sound7);
await sleep(3600);
useStore.getState().setSiteRotX(Math.PI / 2);
playAudio(audio.sound23);
})();
break;
case "pause_up":
case "pause_down":
setState({ activePauseComponent: eventState.activePauseComponent });
playAudio(audio.sound1);
break;
case "pause_exit_select":
setState({
pauseExitAnimation: true,
activePauseComponent: "change",
siteRot: eventState.siteRot,
inputCooldown: true,
});
playAudio(audio.sound0);
setTimeout(
() =>
setState({
mainSubscene: "site",
inputCooldown: false,
lainMoveState: "standing",
}),
1200
);
break;
case "pause_about_select":
setState({ showingAbout: true });
playAudio(audio.sound0);
break;
case "exit_about":
setState({ showingAbout: false });
break;
case "display_prompt":
setState({ promptVisible: true });
playAudio(audio.sound0);
break;
case "exit_prompt":
setState({ promptVisible: false, activePromptComponent: "no" });
playAudio(audio.sound28);
break;
case "prompt_left":
setState({ activePromptComponent: "yes" });
playAudio(audio.sound1);
break;
case "prompt_right":
setState({ activePromptComponent: "no" });
playAudio(audio.sound1);
break;
case "show_permission_denied":
setState({ permissionDenied: true });
playAudio(audio.sound0);
setTimeout(() => setState({ permissionDenied: false }), 1200);
break;
case "pause_save_select":
setState({ saveSuccessful: true });
playAudio(audio.sound28);
//todo actually save
setTimeout(() => setState({ saveSuccessful: undefined }), 1200);
break;
case "pause_load_select":
// todo check if data exists
setState({ loadSuccessful: true });
playAudio(audio.sound28);
//todo actually load
setTimeout(() => setState({ loadSuccessful: undefined }), 1200);
break;
case "pause_change_select":
const siteToLoad: "a" | "b" = eventState.site;
changeSite(siteToLoad);
}
};
export default handleMainSceneEvent;

View file

@ -37,14 +37,6 @@ const handleMediaSceneEvent = (eventState: any) => {
});
playAudio(audio.sound1);
break;
case "media_leftside_down":
setState({ activeMediaComponent: "exit" });
playAudio(audio.sound1);
break;
case "media_leftside_up":
setState({ activeMediaComponent: "play" });
playAudio(audio.sound1);
break;
case "media_leftside_right":
updateLeftSide(
eventState.newActiveComponent,

View file

@ -4,7 +4,6 @@ const handleSsknSceneEvent = (eventState: any) => {
const setState = useStore.setState;
const setNodeViewed = useStore.getState().setNodeViewed;
const incrementSsknLvl = useStore.getState().incrementSsknLvl;
switch (eventState.event) {
case "sskn_cancel_up":
@ -25,7 +24,7 @@ const handleSsknSceneEvent = (eventState: any) => {
is_viewed: 1,
is_visible: 0,
});
incrementSsknLvl();
// incrementSsknLvl();
setTimeout(() => setState({ currentScene: "main" }), 6000);

View file

@ -1,4 +1,6 @@
const handleEndSceneKeyPress = (endSceneContext: any) => {
import { EndSceneContext } from "../../store";
const handleEndSceneKeyPress = (endSceneContext: EndSceneContext) => {
const { keyPress, selectionVisible, activeEndComponent } = endSceneContext;
if (selectionVisible) {

View file

@ -5,6 +5,30 @@ import {
unknownNodeTemplate,
} from "../../utils/node-utils";
import { MainSceneContext } from "../../store";
import {
changeNode,
changePauseComponent,
changePromptComponent,
changeSelectedLevel,
changeSite,
displayPrompt,
enterLevelSelection,
exitAbout,
exitLevelSelection,
exitPause,
exitPrompt,
explodeNode,
knockNode,
knockNodeAndFall,
loadGame,
pauseGame,
saveGame,
selectLevel,
showAbout,
showPermissionDenied,
siteMoveHorizontal,
siteMoveVertical,
} from "../eventTemplates";
const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
const {
@ -22,23 +46,47 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
promptVisible,
activePromptComponent,
gateLvl,
siteSaveState,
} = mainSceneContext;
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: "exit_prompt" };
return exitPrompt;
case "yes":
return {
event: `pause_${activePauseComponent}_select`,
site: activeSite === "a" ? "b" : "a",
};
switch (activePauseComponent) {
case "change":
const siteToLoad = activeSite === "a" ? "b" : "a";
const stateToLoad = siteSaveState[siteToLoad];
const newSiteSaveState = {
...siteSaveState,
[activeSite]: {
activeNode: activeNode,
siteRot: [0, siteRotY, 0],
activeLevel: level.toString().padStart(2, "0"),
},
};
console.log(newSiteSaveState);
return changeSite({
newActiveSite: siteToLoad,
newActiveNode: stateToLoad.activeNode,
newSiteRot: stateToLoad.siteRot,
newActiveLevel: stateToLoad.activeLevel,
newSiteSaveState: newSiteSaveState,
});
case "save":
return saveGame();
case "load":
return loadGame();
}
}
}
} else {
@ -47,11 +95,10 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
switch (keyPress) {
case "LEFT":
case "RIGHT": {
const keyPressToLower = keyPress.toLowerCase();
const direction = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
keyPressToLower,
direction,
activeNode.matrixIndices!,
level,
activeSite,
@ -61,37 +108,38 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
if (!nodeData) return;
const lainMoveAnimation = `move_${direction}`;
const newSiteRot = [
0,
direction === "left"
? siteRotY + Math.PI / 4
: siteRotY - Math.PI / 4,
0,
];
const newNode = {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
};
if (nodeData.didMove) {
return {
event: keyPressToLower === "left" ? `site_left` : "site_right",
siteRotY:
keyPressToLower === "left"
? siteRotY + Math.PI / 4
: siteRotY - Math.PI / 4,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
};
return siteMoveHorizontal({
lainMoveAnimation: lainMoveAnimation,
siteRot: newSiteRot,
activeNode: newNode,
});
} else {
return {
event: "change_node",
nodeMatrixIndices: nodeData.matrixIndices,
node: {
...getNodeById(nodeData.node, activeSite),
matrixIndices: nodeData.matrixIndices,
},
};
return changeNode({ activeNode: newNode });
}
}
case "UP":
case "DOWN": {
const keyPressToLower = keyPress.toLowerCase();
const direction = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
keyPressToLower,
direction,
activeNode.matrixIndices!,
level,
activeSite,
@ -101,28 +149,24 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
if (!nodeData) return;
if (nodeData.didMove) {
return {
event: keyPressToLower === "up" ? "site_up" : "site_down",
level: (keyPressToLower === "up" ? level + 1 : level - 1)
.toString()
.padStart(2, "0"),
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
};
} else {
return {
event: "change_node",
node: {
...getNodeById(nodeData.node, activeSite),
matrixIndices: nodeData.matrixIndices,
},
};
}
const lainMoveAnimation = `jump_${direction}`;
const newLevel = (direction === "up" ? level + 1 : level - 1)
.toString()
.padStart(2, "0");
const newNode = {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
};
if (nodeData.didMove)
return siteMoveVertical({
lainMoveAnimation: lainMoveAnimation,
activeLevel: newLevel,
activeNode: newNode,
});
else return changeNode({ activeNode: newNode });
}
case "CIRCLE":
const eventAnimation =
@ -137,21 +181,8 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
return;
if (activeNode.upgrade_requirement > ssknLvl) {
const rejectAnimations = [
"touch_and_scare",
"knock_and_fall",
"knock",
];
const pickedAnim =
rejectAnimations[
Math.floor(Math.random() * rejectAnimations.length)
];
return {
event: pickedAnim,
siteRotY: siteRotY,
};
const rejectEvents = [explodeNode, knockNode, knockNodeAndFall];
return rejectEvents[Math.floor(Math.random() * 3)];
}
switch (nodeType) {
@ -162,101 +193,56 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
case 5:
return {
event: `${eventAnimation}_media`,
scene: "media",
siteRotY: siteRotY,
level: level.toString().padStart(2, "0"),
mutations: { scene: "media" },
};
case 6:
if (activeNode.node_name.substr(0, 3) === "TaK") {
return {
event: `${eventAnimation}_tak`,
scene: "tak",
siteRotY: siteRotY,
node: activeNode,
mutations: { scene: "tak" },
};
} else {
return {
event: `${eventAnimation}_media`,
scene: "media",
siteRotY: siteRotY,
level: level.toString().padStart(2, "0"),
mutations: { scene: "media" },
};
}
case 8:
return {
event: `${eventAnimation}_gate`,
scene: "gate",
siteRotY: siteRotY,
node: activeNode,
mutations: { scene: "gate" },
};
case 7:
return {
event: `${eventAnimation}_sskn`,
scene: "sskn",
siteRotY: siteRotY,
mutations: { scene: "sskn" },
};
case 9:
const bodyPart = (() => {
switch (parseInt(activeNode.node_name.slice(-1))) {
case 6:
return "head";
case 5:
return "rightArm";
case 4:
return "leftArm";
case 3:
return "rightLeg";
case 2:
return "leftLeg";
case 1:
return "body";
}
})();
return {
event: `${eventAnimation}_polytan`,
scene: "polytan",
siteRotY: siteRotY,
node: activeNode,
bodyPart: bodyPart,
mutations: { scene: "polytan" },
};
}
break;
case "L2":
return { event: "enter_level_selection", level: level };
return enterLevelSelection({ selectedLevel: level });
case "TRIANGLE":
return { event: "pause_game" };
case "SPACE":
return { event: "play_with_hair", siteRotY: siteRotY };
return pauseGame({ siteRot: [Math.PI / 2, siteRotY, 0] });
}
break;
case "level_selection":
switch (keyPress) {
case "UP":
if (activeSite === "a") {
if (selectedLevel + 1 <= 22)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
} else if (activeSite === "b") {
if (selectedLevel + 1 <= 13)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
}
const upperLimit = activeSite === "a" ? 22 : 13;
if (selectedLevel + 1 <= upperLimit)
return changeSelectedLevel({ selectedLevel: selectedLevel + 1 });
break;
case "DOWN":
if (selectedLevel - 1 >= 1)
return {
event: `level_selection_down`,
selectedLevelIdx: selectedLevel - 1,
};
return changeSelectedLevel({ selectedLevel: selectedLevel - 1 });
break;
case "X":
return {
event: "level_selection_back",
};
return exitLevelSelection;
case "CIRCLE":
if (level === selectedLevel) return;
@ -275,96 +261,59 @@ const handleMainSceneKeyPress = (mainSceneContext: MainSceneContext) => {
);
if (nodeData) {
const event =
selectedLevel < level ? "select_level_down" : "select_level_up";
return {
event: event,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
level: selectedLevel.toString().padStart(2, "0"),
const newLevel = selectedLevel.toString().padStart(2, "0");
const newNode = {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, activeSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
};
const lainMoveState =
selectedLevel < level ? "jump_down" : "jump_up";
return selectLevel({
lainMoveState: lainMoveState,
activeLevel: newLevel,
activeNode: newNode,
});
}
}
break;
case "pause":
if (showingAbout)
return {
event: "exit_about",
};
else {
switch (keyPress) {
case "UP": {
const newComponent = (() => {
switch (activePauseComponent) {
case "exit":
return "save";
case "save":
return "change";
case "change":
return "about";
case "about":
return "load";
}
})();
if (showingAbout) return exitAbout;
switch (keyPress) {
case "UP":
case "DOWN":
const direction = keyPress.toLowerCase();
const components = ["load", "about", "change", "save", "exit"];
if (newComponent)
return {
event: "pause_up",
activePauseComponent: newComponent,
};
break;
const newComponent =
components[
components.indexOf(activePauseComponent) +
(direction === "up" ? -1 : 1)
];
if (newComponent)
return changePauseComponent({
activePauseComponent: newComponent,
});
break;
case "CIRCLE":
switch (activePauseComponent) {
case "about":
return showAbout;
case "exit":
return exitPause({ siteRot: [0, siteRotY, 0] });
case "save":
case "load":
return displayPrompt;
case "change":
if (activePauseComponent === "change" && gateLvl > 4)
return showPermissionDenied;
else return displayPrompt;
}
case "DOWN": {
const newComponent = (() => {
switch (activePauseComponent) {
case "load":
return "about";
case "about":
return "change";
case "change":
return "save";
case "save":
return "exit";
}
})();
if (newComponent)
return {
event: "pause_down",
activePauseComponent: newComponent,
};
break;
}
case "CIRCLE":
if (activePauseComponent === "change") {
if (gateLvl > 4) {
return { event: "show_permission_denied" };
} else {
return {
event: "display_prompt",
};
}
} else if (
activePauseComponent === "save" ||
activePauseComponent === "load"
) {
return {
event: "display_prompt",
};
} else {
return {
event: `pause_${activePauseComponent}_select`,
siteRot: [0, siteRotY, 0],
};
}
}
}
break;
case "not_found":
return { event: "exit_not_found" };
}
}
};

View file

@ -1,5 +1,6 @@
import { findNodeFromWord } from "../../utils/media-utils";
import { MediaSceneContext } from "../../store";
import { changeLeftMediaComponent, changeMediaSide } from "../eventTemplates";
const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
const {
@ -17,16 +18,21 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
case "left":
switch (keyPress) {
case "UP":
case "DOWN":
return {
event: `media_leftside_${keyPress.toLowerCase()}`,
};
case "RIGHT":
return {
event: "media_leftside_right",
lastActiveComponent: activeMediaComponent,
newActiveComponent: lastActiveMediaComponents.right,
};
case "DOWN": {
const direction = keyPress.toLowerCase();
const newComponent = direction === "up" ? "play" : "exit";
return changeLeftMediaComponent({ activeComponent: newComponent });
}
case "RIGHT": {
return changeMediaSide({
activeMediaComponent: lastActiveMediaComponents.right,
lastActiveMediaComponents: {
...lastActiveMediaComponents,
left: activeMediaComponent as "play" | "exit",
},
currentMediaSide: "right",
});
}
case "CIRCLE":
switch (activeMediaComponent) {
case "play":
@ -84,11 +90,17 @@ const handleMediaSceneKeyPress = (mediaSceneContext: MediaSceneContext) => {
}
case "LEFT":
return {
event: "media_rightside_left",
lastActiveComponent: activeMediaComponent,
newActiveComponent: lastActiveMediaComponents.left,
};
return changeMediaSide({
activeMediaComponent: lastActiveMediaComponents.left,
lastActiveMediaComponents: {
...lastActiveMediaComponents,
right: activeMediaComponent as
| "fstWord"
| "sndWord"
| "thirdWord",
},
currentMediaSide: "left",
});
case "CIRCLE":
const data = findNodeFromWord(

View file

@ -1,20 +1,19 @@
import { OrbitControls } from "@react-three/drei";
import React, { Suspense, useEffect, useRef, useState } from "react";
import { playAudio, useStore } from "../store";
import Pause from "../components/MainScene/PauseSubscene/Pause";
import Pause from "../components/MainScene/Pause/Pause";
import LevelSelection from "../components/MainScene/LevelSelection";
import HUD from "../components/MainScene/HUD";
import MainYellowTextAnimator from "../components/TextRenderer/MainYellowTextAnimator";
import YellowOrb from "../components/MainScene/YellowOrb";
import MiddleRing from "../components/MainScene/MiddleRing";
import GrayPlanes from "../components/MainScene/GrayPlanes";
import Starfield from "../components/MainScene/Starfield";
import Site from "../components/MainScene/Site";
import MiddleRing from "../components/MainScene/MiddleRing/MiddleRing";
import GrayPlanes from "../components/MainScene/GrayPlanes/GrayPlanes";
import Starfield from "../components/MainScene/Starfield/Starfield";
import Site from "../components/MainScene/Site/Site";
import Lain from "../components/MainScene/Lain";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import NotFound from "../components/MainScene/NotFound";
import PausePopUps from "../components/MainScene/PauseSubscene/PausePopUps";
import Popups from "../components/MainScene/Popups/Popups";
import * as audio from "../static/sfx";
import Loading from "../components/Loading";
import usePrevious from "../hooks/usePrevious";
@ -94,9 +93,8 @@ const MainScene = () => {
<perspectiveCamera position-z={3}>
<Suspense fallback={<Loading />}>
<LevelSelection />
<PausePopUps />
<Popups />
<Pause />
<NotFound visible={subscene === "not_found"} />
<group visible={!paused}>
<group visible={!wordSelected && (intro ? introFinished : true)}>
<group visible={subscene !== "not_found"}>

View file

@ -2,7 +2,7 @@ import create from "zustand";
import { combine } from "zustand/middleware";
import * as THREE from "three";
import game_progress from "./resources/initial_progress.json";
import { NodeData } from "./components/MainScene/Site";
import { NodeData } from "./components/MainScene/Site/Site";
import { getNodeById } from "./utils/node-utils";
import site_a from "./resources/site_a.json";
@ -126,7 +126,7 @@ export const useStore = create(
combine(
{
// scene data
currentScene: "boot",
currentScene: "media",
// game progress
gameProgress: game_progress,
@ -258,14 +258,7 @@ export const useStore = create(
// scene data setters
setScene: (to: string) => set(() => ({ currentScene: to })),
// main subscene setter
setMainSubscene: (to: string) => set(() => ({ mainSubscene: to })),
// intro setters
setIntro: (to: boolean) => set(() => ({ intro: to })),
// node setters
setNode: (to: NodeData) => set(() => ({ activeNode: to })),
setNodePos: (to: number[]) => set(() => ({ activeNodePos: to })),
setNodeRot: (to: number[]) => set(() => ({ activeNodeRot: to })),
setNodeAttributes: (
@ -280,41 +273,19 @@ export const useStore = create(
setLainMoveState: (to: string) => set(() => ({ lainMoveState: to })),
// site setters
setActiveSite: (to: "a" | "b") => set(() => ({ activeSite: to })),
setSiteRotY: (to: number) =>
set((prev) => {
const nextRot = [...prev.siteRot];
nextRot[1] = to;
return { siteRot: nextRot };
}),
setSiteRotX: (to: number) =>
set((prev) => {
const nextRot = [...prev.siteRot];
nextRot[0] = to;
return { siteRot: nextRot };
}),
setOldSiteRot: (to: number[]) =>
set(() => ({
oldSiteRot: to,
})),
// level setters
setActiveLevel: (to: string) => set(() => ({ activeLevel: to })),
setOldLevel: (to: string) => set(() => ({ oldLevel: to })),
// level selection setters
setSelectedLevel: (to: number) => set(() => ({ selectedLevel: to })),
// end scene setters
setEndSceneSelectionVisible: (to: boolean) =>
set(() => ({ endSceneSelectionVisible: to })),
// pause setters
setPauseExitAnimation: (to: boolean) =>
set(() => ({ pauseExitAnimation: to })),
setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })),
setPermissionDenied: (to: boolean) =>
set(() => ({ permissionDenied: to })),
// media scene setters
setAudioAnalyser: (to: any) => set(() => ({ audioAnalyser: to })),
@ -368,41 +339,6 @@ export const useStore = create(
},
})),
// gate scene setters
incrementGateLvl: () => set((state) => ({ gateLvl: state.gateLvl + 1 })),
// player name setters
setPlayerName: (to: string) => set(() => ({ playerName: to })),
// boot scene setters
setBootSubscene: (to: "load_data" | "authorize_user" | "main_menu") =>
set(() => ({ bootSubscene: to })),
setAuthorizeUserLetterIdx: (to: number) =>
set(() => ({ authorizeUserLetterIdx: to })),
// site state setters
setSiteSaveState: (
site: string,
to: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
}
) =>
set((state) => ({
siteSaveState: { ...state.siteSaveState, [site]: to },
})),
loadSiteSaveState: (site: "a" | "b") =>
set((state) => {
const stateToLoad = state.siteSaveState[site];
return {
activeSite: site,
activeNode: stateToLoad.activeNode,
siteRot: stateToLoad.siteRot,
activeLevel: stateToLoad.activeLevel,
};
}),
changeSite: (to: "a" | "b") =>
set((state) => {
const newState = state.siteSaveState[to];
@ -428,12 +364,6 @@ export const useStore = create(
};
}),
// status notifier setters
setSaveSuccessful: (to: boolean | undefined) =>
set(() => ({ saveSuccessful: to })),
setLoadSuccessful: (to: boolean | undefined) =>
set(() => ({ loadSuccessful: to })),
// progress setters
setNodeViewed: (
nodeName: string,
@ -447,22 +377,10 @@ export const useStore = create(
})),
setInputCooldown: (to: boolean) => set(() => ({ inputCooldown: to })),
incrementSsknLvl: () => set((state) => ({ ssknLvl: state.ssknLvl + 1 })),
})
)
);
export const getSiteState = (site: "a" | "b") => {
const siteState = useStore.getState().siteSaveState[site];
return {
activeNode: siteState.activeNode,
siteRot: siteState.siteRot,
activeLevel: siteState.activeLevel,
};
};
type PromptContext = {
activePromptComponent: "yes" | "no";
promptVisible: boolean;
@ -490,6 +408,18 @@ export interface MainSceneContext extends PromptContext {
siteRotY: number;
activeSite: "a" | "b";
selectedLevel: number;
siteSaveState: {
a: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
b: {
activeNode: NodeData;
siteRot: number[];
activeLevel: string;
};
};
}
export const getMainSceneContext = (keyPress: string): MainSceneContext => {
@ -509,6 +439,7 @@ export const getMainSceneContext = (keyPress: string): MainSceneContext => {
ssknLvl: state.ssknLvl,
showingAbout: state.showingAbout,
gateLvl: state.gateLvl,
siteSaveState: state.siteSaveState,
};
};
@ -610,19 +541,3 @@ export const createAudioAnalyser = () => {
return new THREE.AudioAnalyser(audio, 2048);
};
export const getSceneResetValues = (scene: string) => {
switch (scene) {
case "media":
return {
mediaWordPosStateIdx: 1,
mediaComponentMatrixIndices: {
sideIdx: 0,
leftSideIdx: 0,
rightSideIdx: 0,
},
};
case "sskn":
return { ssknComponentMatrixIdx: 0, ssknLoading: false };
}
};

View file

@ -1,6 +1,6 @@
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
import { SiteData } from "../components/MainScene/Site";
import { SiteData } from "../components/MainScene/Site/Site";
import { useStore } from "../store";
export const getRandomIdleMedia = () => {

View file

@ -1,7 +1,7 @@
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";
import { NodeData, SiteData } from "../components/MainScene/Site/Site";
import { isNodeVisible } from "./node-utils";
export const findNodeFromWord = (

View file

@ -14,8 +14,14 @@ const calculateCoordsBasedOnRotation = (
z: x * Math.sin(rotation) + z * Math.cos(rotation),
});
export const nodeThrow = (siteRotY: number) => {
// async calls in this file are executed inside IIAFE-s because defining them as async would
// throw a warning about an unhandled promise, and we dont care about that.
// async/awaits here are used simply to improve readability, nothing else.
export const nodeThrowAnimation = () => {
(async () => {
const siteRotY = useStore.getState().siteRot[1];
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(1.55, 0.2, siteRotY);
@ -42,7 +48,9 @@ export const nodeThrow = (siteRotY: number) => {
})();
};
export const nodeKnock = (siteRotY: number) => {
export const nodeKnockAnimation = () => {
const siteRotY = useStore.getState().siteRot[1];
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
@ -52,8 +60,10 @@ export const nodeKnock = (siteRotY: number) => {
setTimeout(() => setActiveNodeAttributes(false, "interactedWith"), 2500);
};
export const nodeKnockAndFall = (siteRotY: number) => {
export const nodeKnockAndFallAnimation = () => {
(async () => {
const siteRotY = useStore.getState().siteRot[1];
const fstCoordSet = calculateCoordsBasedOnRotation(1.1, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
@ -71,8 +81,10 @@ export const nodeKnockAndFall = (siteRotY: number) => {
})();
};
export const nodeTouchAndScare = (siteRotY: number) => {
export const nodeExplodeAnimation = () => {
(async () => {
const siteRotY = useStore.getState().siteRot[1];
const fstCoordSet = calculateCoordsBasedOnRotation(-0.6, 0.2, siteRotY);
setActiveNodeAttributes(true, "interactedWith");
@ -95,8 +107,10 @@ export const nodeTouchAndScare = (siteRotY: number) => {
})();
};
export const nodeRip = (siteRotY: number) => {
export const nodeRipAnimation = () => {
(async () => {
const siteRotY = useStore.getState().siteRot[1];
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
const thirdCoordSet = calculateCoordsBasedOnRotation(0, 0.2, siteRotY);

View file

@ -1,4 +1,4 @@
import { NodeData, SiteData } from "../components/MainScene/Site";
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";