+
{["media", "idle_media", "tak", "end"].includes(currentScene) && (
)}
diff --git a/src/components/GateScene/GateMiddleObject.tsx b/src/components/GateScene/GateMiddleObject.tsx
index 79b365a..fe197b5 100644
--- a/src/components/GateScene/GateMiddleObject.tsx
+++ b/src/components/GateScene/GateMiddleObject.tsx
@@ -1,9 +1,8 @@
import React, { useEffect, useState } from "react";
-import BlueZero from "./GateMiddleObject/BlueZero";
-import BlueOne from "./GateMiddleObject/BlueOne";
import { a, useSpring, useSprings } from "@react-spring/three";
import blue_digit_positions from "../../resources/blue_digit_positions.json";
import Mirror from "./GateMiddleObject/Mirror";
+import BlueDigit from "./GateMiddleObject/BlueDigit";
type GateMiddleObjectProps = {
intro: boolean;
@@ -16,14 +15,12 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
const [springs, set] = useSprings(44, (intIdx) => {
const idx = intIdx.toString();
return {
- type: blue_digit_positions[idx as keyof typeof blue_digit_positions].type,
posX:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_x,
posY:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_y,
- visibility: false,
config: { duration: 150 },
};
});
@@ -40,7 +37,6 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
.final_y,
delay:
blue_digit_positions[idx as keyof typeof blue_digit_positions].delay,
- visibility: true,
};
});
@@ -62,23 +58,17 @@ const GateMiddleObject = (props: GateMiddleObjectProps) => {
position-z={middleObjectGroupState.posZ}
visible={props.intro}
>
- {springs.map((item, idx) =>
- item.type.get() === 1 ? (
-
- ) : (
-
- )
- )}
+ {springs.map((item, idx) => (
+
+ ))}
0}
diff --git a/src/components/GateScene/GateMiddleObject/BlueZero.tsx b/src/components/GateScene/GateMiddleObject/BlueDigit.tsx
similarity index 57%
rename from src/components/GateScene/GateMiddleObject/BlueZero.tsx
rename to src/components/GateScene/GateMiddleObject/BlueDigit.tsx
index d2069f6..f36a075 100644
--- a/src/components/GateScene/GateMiddleObject/BlueZero.tsx
+++ b/src/components/GateScene/GateMiddleObject/BlueDigit.tsx
@@ -1,29 +1,41 @@
import React, { useEffect, useMemo, useRef } from "react";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
-import gateBlueBinarySingularZero from "../../../static/sprites/gate/blue_binary_singular_zero.png";
+import gateBlueBinarySingularOne from "../../../static/sprites/gate/blue_binary_singular_one.png";
import { a, SpringValue } from "@react-spring/three";
+import gateBlueBinarySingularZero from "../../../static/sprites/gate/blue_binary_singular_zero.png";
-type BlueZeroProps = {
+type BlueDigitProps = {
+ type: number;
posX: SpringValue;
posY: SpringValue;
- visibility: SpringValue;
};
-const BlueZero = (props: BlueZeroProps) => {
+const BlueDigit = (props: BlueDigitProps) => {
+ const gateBlueBinarySingularOneTex = useLoader(
+ THREE.TextureLoader,
+ gateBlueBinarySingularOne
+ );
const gateBlueBinarySingularZeroTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularZero
);
+ const objRef = useRef();
const matRef = useRef();
const uniforms = useMemo(
() => ({
- zeroTex: { type: "t", value: gateBlueBinarySingularZeroTex },
+ tex: {
+ type: "t",
+ value:
+ props.type === 1
+ ? gateBlueBinarySingularOneTex
+ : gateBlueBinarySingularZeroTex,
+ },
brightnessMultiplier: { value: 1.5 },
}),
- [gateBlueBinarySingularZeroTex]
+ [gateBlueBinarySingularOneTex, gateBlueBinarySingularZeroTex, props.type]
);
const vertexShader = `
@@ -35,14 +47,13 @@ const BlueZero = (props: BlueZeroProps) => {
}
`;
- const fragmentShaderZero = `
- uniform sampler2D zeroTex;
+ const fragmentShader = `
+ uniform sampler2D tex;
uniform float brightnessMultiplier;
-
varying vec2 vUv;
void main() {
- gl_FragColor = texture2D(zeroTex, vUv) * brightnessMultiplier;
+ gl_FragColor = texture2D(tex, vUv) * brightnessMultiplier;
}
`;
@@ -50,21 +61,26 @@ const BlueZero = (props: BlueZeroProps) => {
setTimeout(() => {
if (matRef.current) {
matRef.current.uniforms.brightnessMultiplier.value = 3.5;
+ matRef.current.uniformsNeedUpdate = true;
}
}, 1400);
+ setTimeout(() => {
+ if (objRef.current) objRef.current.visible = true;
+ }, 150);
}, []);
return (
-
+
{
);
};
-export default BlueZero;
+export default BlueDigit;
diff --git a/src/components/GateScene/GateMiddleObject/BlueOne.tsx b/src/components/GateScene/GateMiddleObject/BlueOne.tsx
deleted file mode 100644
index 950d071..0000000
--- a/src/components/GateScene/GateMiddleObject/BlueOne.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React, { useEffect, useMemo, useRef } from "react";
-import { useLoader } from "react-three-fiber";
-import * as THREE from "three";
-import gateBlueBinarySingularOne from "../../../static/sprites/gate/blue_binary_singular_one.png";
-import { a, SpringValue } from "@react-spring/three";
-
-type BlueOneProps = {
- posX: SpringValue;
- posY: SpringValue;
- visibility: SpringValue;
-};
-
-const BlueOne = (props: BlueOneProps) => {
- const gateBlueBinarySingularOneTex = useLoader(
- THREE.TextureLoader,
- gateBlueBinarySingularOne
- );
-
- const matRef = useRef();
-
- const uniforms = useMemo(
- () => ({
- oneTex: { type: "t", value: gateBlueBinarySingularOneTex },
- brightnessMultiplier: { value: 1.5 },
- }),
- [gateBlueBinarySingularOneTex]
- );
-
- const vertexShader = `
- varying vec2 vUv;
-
- void main() {
- vUv = uv;
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `;
-
- const fragmentShaderOne = `
- uniform sampler2D oneTex;
- uniform float brightnessMultiplier;
- varying vec2 vUv;
-
- void main() {
- gl_FragColor = texture2D(oneTex, vUv) * brightnessMultiplier;
- }
- `;
-
- useEffect(() => {
- setTimeout(() => {
- if (matRef.current)
- matRef.current.uniforms.brightnessMultiplier.value = 3.5;
- }, 1400);
- }, []);
-
- return (
-
-
-
-
- );
-};
-
-export default BlueOne;
diff --git a/src/components/IdleManager.tsx b/src/components/IdleManager.tsx
new file mode 100644
index 0000000..46f7050
--- /dev/null
+++ b/src/components/IdleManager.tsx
@@ -0,0 +1,77 @@
+import { useFrame } from "react-three-fiber";
+import { playAudio, useStore } from "../store";
+import * as audio from "../static/audio/sfx";
+import {
+ playIdleAudio,
+ playIdleVideo,
+ playLainIdleAnim,
+} from "../core/eventTemplates";
+import {
+ getRandomIdleLainAnim,
+ getRandomIdleMedia,
+} from "../helpers/idle-helpers";
+import handleEvent from "../core/handleEvent";
+
+type IdleManagerProps = {
+ lainIdleTimerRef: any;
+ idleSceneTimerRef: any;
+};
+
+const IdleManager = (props: IdleManagerProps) => {
+ const mainSubscene = useStore((state) => state.mainSubscene);
+ const scene = useStore((state) => state.currentScene);
+
+ useFrame(() => {
+ const now = Date.now();
+ if (
+ props.lainIdleTimerRef.current !== -1 &&
+ props.idleSceneTimerRef.current !== -1 &&
+ mainSubscene !== "pause" &&
+ mainSubscene !== "level_selection" &&
+ scene === "main"
+ ) {
+ if (now > props.lainIdleTimerRef.current + 10000) {
+ // after one idle animation plays, the second comes sooner than it would after a regular keypress
+ props.lainIdleTimerRef.current = now - 2500;
+
+ const [idleLainAnim, duration] = getRandomIdleLainAnim();
+
+ const event = playLainIdleAnim({
+ lainMoveState: idleLainAnim,
+ duration: duration,
+ });
+
+ if (event) handleEvent(event);
+ }
+ if (now > props.idleSceneTimerRef.current + 500000) {
+ // put it on lock until the next action, since while the idle media plays, the
+ // Date.now() value keeps increasing, which can result in another idle media playing right after one finishes
+ // one way to work around this would be to modify the value depending on the last played idle media's duration
+ // but i'm way too lazy for that
+ props.idleSceneTimerRef.current = -1;
+
+ playAudio(audio.sound32);
+
+ const data = getRandomIdleMedia();
+
+ const { type, nodeName, images, media } = data;
+ let event;
+ if (type === "audio" && images && nodeName) {
+ event = playIdleAudio({
+ idleNodeName: nodeName,
+ idleImages: images,
+ idleMedia: media,
+ });
+ } else if (type === "video") {
+ event = playIdleVideo({ idleMedia: media });
+ }
+
+ if (event) handleEvent(event);
+ }
+ }
+ });
+
+ return null;
+};
+
+export default IdleManager;
diff --git a/src/components/InputHandler.tsx b/src/components/InputHandler.tsx
index 7dfa790..63254d7 100644
--- a/src/components/InputHandler.tsx
+++ b/src/components/InputHandler.tsx
@@ -1,154 +1,138 @@
-import { useCallback, useEffect, useRef } from "react";
+import React, { useCallback, useEffect, useRef } from "react";
import {
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSsknSceneContext,
- playAudio,
useStore,
} from "../store";
-import { getKeyCodeAssociation } from "../utils/parseUserInput";
+import getKeyPress from "../utils/getKeyPress";
import handleMediaSceneInput from "../core/input-handlers/handleMediaSceneInput";
import handleSsknSceneInput from "../core/input-handlers/handleSsknSceneInput";
import handleMainSceneInput from "../core/input-handlers/handleMainSceneInput";
import handleBootSceneInput from "../core/input-handlers/handleBootSceneInput";
-import { useFrame } from "react-three-fiber";
-import { getRandomIdleLainAnim } from "../helpers/idle-helpers";
-import * as audio from "../static/audio/sfx";
import handleEndSceneInput from "../core/input-handlers/handleEndSceneInput";
import handleEvent from "../core/handleEvent";
import { GameEvent } from "../types/types";
+import { useSwipeable } from "react-swipeable";
+import IdleManager from "./IdleManager";
+import { Canvas } from "react-three-fiber";
const InputHandler = () => {
const scene = useStore((state) => state.currentScene);
- const mainSubscene = useStore((state) => state.mainSubscene);
const inputCooldown = useStore((state) => state.inputCooldown);
- const setLainMoveState = useStore((state) => state.setLainMoveState);
-
const timeSinceLastKeyPress = useRef(-1);
- const lainIdleCounter = useRef(-1);
- const idleSceneCounter = useRef(-1);
- useFrame(() => {
- const now = Date.now();
- if (
- lainIdleCounter.current > -1 &&
- idleSceneCounter.current > -1 &&
- mainSubscene !== "pause" &&
- mainSubscene !== "level_selection" &&
- scene === "main"
- ) {
- if (now > lainIdleCounter.current + 10000) {
- setLainMoveState(getRandomIdleLainAnim());
- // after one idle animation plays, the second comes sooner than it would after a regular keypress
- lainIdleCounter.current = now - 2500;
- }
- if (now > idleSceneCounter.current + 30000) {
- // put it on lock until the next action, since while the idle media plays, the
- // Date.now() value keeps increasing, which can result in another idle media playing right after one finishes
- // one way to work around this would be to modify the value depending on the last played idle media's duration
- // but i'm way too lazy for that
- idleSceneCounter.current = -1;
-
- // idleManager(getRandomIdleMedia());
- playAudio(audio.sound32);
-
- setTimeout(() => {
- // useStore.setState({ event: "play_idle_media" });
- }, 1200);
- }
- }
- });
-
- useEffect(() => {
- if (scene !== "main") idleSceneCounter.current = -1;
- }, [scene]);
+ const lainIdleTimerRef = useRef(-1);
+ const idleSceneTimerRef = useRef(-1);
const handleKeyPress = useCallback(
- (event) => {
- const { keyCode } = event;
+ (keyPress: string) => {
+ const now = Date.now();
- const keyPress = getKeyCodeAssociation(keyCode);
+ if (scene === "main") {
+ timeSinceLastKeyPress.current = now;
+ lainIdleTimerRef.current = now;
+ idleSceneTimerRef.current = now;
+ }
+
+ const sceneFns = (() => {
+ switch (scene) {
+ case "main":
+ return {
+ contextProvider: getMainSceneContext,
+ keyPressHandler: handleMainSceneInput,
+ };
+ case "media":
+ return {
+ contextProvider: getMediaSceneContext,
+ keyPressHandler: handleMediaSceneInput,
+ };
+ case "sskn":
+ return {
+ contextProvider: getSsknSceneContext,
+ keyPressHandler: handleSsknSceneInput,
+ };
+ case "boot":
+ return {
+ contextProvider: getBootSceneContext,
+ keyPressHandler: handleBootSceneInput,
+ };
+ case "end":
+ return {
+ contextProvider: getEndSceneContext,
+ keyPressHandler: handleEndSceneInput,
+ };
+ case "gate":
+ case "polytan":
+ useStore.setState({ currentScene: "main" });
+ break;
+ case "idle_media":
+ useStore.setState({
+ currentScene: "main",
+ idleStarting: false,
+ });
+ break;
+ }
+ })();
+
+ if (sceneFns) {
+ const { contextProvider, keyPressHandler } = sceneFns;
+
+ const ctx = contextProvider();
+ const event: GameEvent | undefined = keyPressHandler(
+ ctx as any,
+ keyPress
+ );
+ if (event) handleEvent(event);
+ }
+ },
+ [scene]
+ );
+
+ const handlers = useSwipeable({
+ onSwiped: (eventData) => handleKeyPress(eventData.dir.toUpperCase()),
+ onTap: () => handleKeyPress("CIRCLE"),
+ });
+
+ const handleKeyBoardEvent = useCallback(
+ (event) => {
+ const key = getKeyPress(event.key);
const now = Date.now();
if (
- keyPress &&
+ key &&
now > timeSinceLastKeyPress.current + inputCooldown &&
inputCooldown !== -1
) {
- if (scene === "main") {
- lainIdleCounter.current = now;
- idleSceneCounter.current = now;
- timeSinceLastKeyPress.current = now;
- }
-
- const sceneFns = (() => {
- switch (scene) {
- case "main":
- return {
- contextProvider: getMainSceneContext,
- keyPressHandler: handleMainSceneInput,
- };
- case "media":
- return {
- contextProvider: getMediaSceneContext,
- keyPressHandler: handleMediaSceneInput,
- };
- case "sskn":
- return {
- contextProvider: getSsknSceneContext,
- keyPressHandler: handleSsknSceneInput,
- };
- case "boot":
- return {
- contextProvider: getBootSceneContext,
- keyPressHandler: handleBootSceneInput,
- };
- case "end":
- return {
- contextProvider: getEndSceneContext,
- keyPressHandler: handleEndSceneInput,
- };
- case "gate":
- case "polytan":
- useStore.setState({ currentScene: "main" });
- break;
- case "idle_media":
- useStore.setState({
- currentScene: "main",
- idleStarting: false,
- });
- break;
- }
- })();
-
- if (sceneFns) {
- const { contextProvider, keyPressHandler } = sceneFns;
-
- const ctx = contextProvider();
- const event: GameEvent | undefined = keyPressHandler(
- ctx as any,
- keyPress
- );
- if (event) handleEvent(event);
- }
+ handleKeyPress(key);
}
},
- [inputCooldown, scene]
+ [handleKeyPress, inputCooldown]
);
useEffect(() => {
- window.addEventListener("keydown", handleKeyPress);
+ window.addEventListener("keydown", handleKeyBoardEvent);
return () => {
- window.removeEventListener("keydown", handleKeyPress);
+ window.removeEventListener("keydown", handleKeyBoardEvent);
};
- }, [handleKeyPress]);
+ }, [handleKeyBoardEvent]);
- return null;
+ return (
+ <>
+
+
+ >
+ );
};
export default InputHandler;
diff --git a/src/components/MainScene/HUD.tsx b/src/components/MainScene/HUD.tsx
index fb6f594..9486c7d 100644
--- a/src/components/MainScene/HUD.tsx
+++ b/src/components/MainScene/HUD.tsx
@@ -25,18 +25,6 @@ const HUD = memo(() => {
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ siteRotY, activeLevel, subscene, scene });
- const lerpObject = (
- obj: THREE.Object3D,
- posX: number,
- initialPosX: number
- ) => {
- obj.position.x = lerp(
- obj.position.x,
- activeRef.current ? posX : initialPosX,
- 0.12
- );
- };
-
// this part is imperative because it performs a lot better than having a toggleable spring.
useFrame(() => {
if (
@@ -46,25 +34,30 @@ const HUD = memo(() => {
greenTextRef.current
) {
const hud = currentHudRef.current;
- lerpObject(
- longHudRef.current,
- hud.long.position[0],
- hud.long.initial_position[0]
+
+ longHudRef.current.position.x = lerp(
+ longHudRef.current.position.x,
+ activeRef.current ? hud.long.position[0] : hud.long.initial_position[0],
+ 0.12
);
- lerpObject(
- boringHudRef.current,
- hud.boring.position[0],
- hud.boring.initial_position[0]
+ boringHudRef.current.position.x = lerp(
+ boringHudRef.current.position.x,
+ activeRef.current
+ ? hud.boring.position[0]
+ : hud.boring.initial_position[0],
+ 0.12
);
- lerpObject(
- bigHudRef.current,
- hud.big.position[0],
- hud.big.initial_position[0]
+ bigHudRef.current.position.x = lerp(
+ bigHudRef.current.position.x,
+ activeRef.current ? hud.big.position[0] : hud.big.initial_position[0],
+ 0.12
);
- lerpObject(
- greenTextRef.current,
- hud.medium_text.position[0],
- hud.medium_text.initial_position[0]
+ greenTextRef.current.position.x = lerp(
+ greenTextRef.current.position.x,
+ activeRef.current
+ ? hud.medium_text.position[0]
+ : hud.medium_text.initial_position[0],
+ 0.12
);
}
});
diff --git a/src/core/eventTemplates.ts b/src/core/eventTemplates.ts
index c9bacc0..472eae6 100644
--- a/src/core/eventTemplates.ts
+++ b/src/core/eventTemplates.ts
@@ -204,7 +204,7 @@ export const changeSelectedLevel = (calculatedState: {
{
mutation: {
selectedLevel: calculatedState.selectedLevel,
- inputCooldown: 300,
+ inputCooldown: 100,
},
},
],
@@ -263,7 +263,7 @@ export const changePauseComponent = (calculatedState: {
{
mutation: {
activePauseComponent: calculatedState.activePauseComponent,
- inputCooldown: 500,
+ inputCooldown: 700,
},
},
],
@@ -279,7 +279,7 @@ export const showPermissionDenied = {
};
export const displayPrompt = {
- state: [{ mutation: { promptVisible: true, inputCooldown: 500 } }],
+ state: [{ mutation: { promptVisible: true, inputCooldown: 0 } }],
audio: [{ sfx: [audio.sound0] }],
};
@@ -311,7 +311,7 @@ export const exitPause = (calculatedState: { siteRot: number[] }) => ({
});
export const exitAbout = {
- state: [{ mutation: { showingAbout: false, inputCooldown: 500 } }],
+ state: [{ mutation: { showingAbout: false, inputCooldown: 0 } }],
};
export const changePromptComponent = (calculatedState: {
@@ -321,7 +321,7 @@ export const changePromptComponent = (calculatedState: {
{
mutation: {
activePromptComponent: calculatedState.activePromptComponent,
- inputCooldown: 500,
+ inputCooldown: 100,
},
},
],
@@ -334,7 +334,7 @@ export const exitPrompt = {
mutation: {
activePromptComponent: "no",
promptVisible: false,
- inputCooldown: 500,
+ inputCooldown: 0,
},
},
],
@@ -458,7 +458,7 @@ export const changeMediaSide = (calculatedState: {
activeMediaComponent: calculatedState.activeMediaComponent,
lastActiveMediaComponents: calculatedState.lastActiveMediaComponents,
currentMediaSide: calculatedState.currentMediaSide,
- inputCooldown: 500,
+ inputCooldown: 0,
},
},
],
@@ -497,7 +497,7 @@ export const changeRightMediaComponent = (calculatedState: {
mutation: {
activeMediaComponent: calculatedState.activeComponent,
mediaWordPosStateIdx: calculatedState.wordPosStateIdx,
- inputCooldown: 500,
+ inputCooldown: 300,
},
},
],
@@ -519,7 +519,7 @@ export const wordNotFound = {
};
export const hideWordNotFound = {
- state: [{ mutation: { wordNotFound: false, inputCooldown: 300 } }],
+ state: [{ mutation: { wordNotFound: false, inputCooldown: 0 } }],
};
export const selectWord = (calculatedState: {
@@ -550,7 +550,7 @@ export const changeSsknComponent = (calculatedState: {
{
mutation: {
activeSsknComponent: calculatedState.activeSsknComponent,
- inputCooldown: 500,
+ inputCooldown: 100,
},
},
],
@@ -595,7 +595,7 @@ export const changeEndComponent = (calculatedState: {
{
mutation: {
activeEndComponent: calculatedState.activeEndComponent,
- inputCooldown: 500,
+ inputCooldown: 100,
},
},
],
@@ -615,7 +615,7 @@ export const changeMainMenuComponent = (calculatedState: {
{
mutation: {
activeMainMenuComponent: calculatedState.activeMainMenuComponent,
- inputCooldown: 500,
+ inputCooldown: 200,
},
},
],
@@ -702,3 +702,58 @@ export const updateAuthorizeUserLetterIdx = (calculatedState: {
},
],
});
+
+export const playIdleVideo = (calculatedState: { idleMedia: string }) => ({
+ state: [
+ {
+ mutation: {
+ idleStarting: true,
+ idleMedia: calculatedState.idleMedia,
+ inputCooldown: -1,
+ },
+ },
+ { mutation: { currentScene: "idle_media" }, delay: 1200 },
+ ],
+});
+
+export const playIdleAudio = (calculatedState: {
+ idleMedia: string;
+ idleImages: { "1": string; "2": string; "3": string };
+ idleNodeName: string;
+}) => ({
+ state: [
+ {
+ mutation: {
+ idleStarting: true,
+ inputCooldown: -1,
+ idleMedia: calculatedState.idleMedia,
+ idleImages: calculatedState.idleImages,
+ idleNodeName: calculatedState.idleNodeName,
+ },
+ },
+ { mutation: { currentScene: "idle_media" }, delay: 1200 },
+ ],
+});
+
+export const playLainIdleAnim = (calculatedState: {
+ lainMoveState: string;
+ duration: number;
+}) => ({
+ // todo appropriate disable-move here also
+ state: [
+ {
+ mutation: {
+ lainMoveState: calculatedState.lainMoveState,
+ canLainMove: false,
+ },
+ },
+ {
+ mutation: { lainMoveState: "standing", canLainMove: true },
+ delay: calculatedState.duration,
+ },
+ ],
+});
+
+export const resetInputCooldown = {
+ state: [{ mutation: { inputCooldown: 0 } }],
+};
diff --git a/src/core/input-handlers/handleMainSceneInput.ts b/src/core/input-handlers/handleMainSceneInput.ts
index 2c33ae8..98d35a2 100644
--- a/src/core/input-handlers/handleMainSceneInput.ts
+++ b/src/core/input-handlers/handleMainSceneInput.ts
@@ -24,6 +24,7 @@ import {
loadGame,
loadGameFail,
pauseGame,
+ resetInputCooldown,
ripNode,
saveGame,
selectLevel,
@@ -54,6 +55,7 @@ const handleMainSceneInput = (
activePromptComponent,
siteSaveState,
wordNotFound,
+ canLainMove,
} = mainSceneContext;
if (promptVisible) {
@@ -137,6 +139,7 @@ const handleMainSceneInput = (
};
if (nodeData.didMove) {
+ if (!canLainMove) return resetInputCooldown;
return siteMoveHorizontal({
lainMoveAnimation: lainMoveAnimation,
siteRot: newSiteRot,
@@ -179,15 +182,18 @@ const handleMainSceneInput = (
matrixIndices: nodeData.matrixIndices,
};
- if (nodeData.didMove)
+ if (nodeData.didMove) {
+ if (!canLainMove) return resetInputCooldown;
return siteMoveVertical({
lainMoveAnimation: lainMoveAnimation,
activeLevel: newLevel,
activeNode: newNode,
});
- else return changeNode({ activeNode: newNode });
+ } else return changeNode({ activeNode: newNode });
}
case "CIRCLE":
+ if (!canLainMove) return resetInputCooldown;
+
const eventAnimation = Math.random() < 0.4 ? throwNode : ripNode;
if (
@@ -207,6 +213,7 @@ const handleMainSceneInput = (
case "L2":
return enterLevelSelection({ selectedLevel: level });
case "TRIANGLE":
+ if (!canLainMove) return resetInputCooldown;
return pauseGame({ siteRot: [Math.PI / 2, siteRotY, 0] });
}
break;
@@ -225,6 +232,8 @@ const handleMainSceneInput = (
return exitLevelSelection;
case "CIRCLE":
+ if (!canLainMove) return resetInputCooldown;
+
if (level === selectedLevel) return;
const direction = selectedLevel > level ? "up" : "down";
diff --git a/src/helpers/idle-helpers.ts b/src/helpers/idle-helpers.ts
index 67f97cc..74aba37 100644
--- a/src/helpers/idle-helpers.ts
+++ b/src/helpers/idle-helpers.ts
@@ -72,39 +72,39 @@ export const getRandomIdleMedia = () => {
const nodeName = siteData[level][nodeToPlay].node_name;
return {
+ type: "audio",
images: images,
media: media,
nodeName: nodeName,
};
} else {
return {
+ type: "video",
media:
idleNodes.video[Math.floor(Math.random() * idleNodes.video.length)],
- nodeName: undefined,
- images: undefined,
};
}
};
-export const getRandomIdleLainAnim = () => {
- const moves = [
- "prayer",
- "touch_sleeve",
- "thinking",
- "stretch_2",
- "stretch",
- "spin",
- "scratch_head",
- "blush",
- "hands_behind_head",
- "hands_on_hips",
- "hands_on_hips_2",
- "hands_together",
- "lean_forward",
- "lean_left",
- "lean_right",
- "look_around",
- "play_with_hair",
+export const getRandomIdleLainAnim = (): [string, number] => {
+ const moves: [string, number][] = [
+ ["prayer", 3500],
+ ["touch_sleeve", 3000],
+ ["thinking", 3900],
+ ["stretch_2", 3900],
+ ["stretch", 3000],
+ ["spin", 3000],
+ ["scratch_head", 3900],
+ ["blush", 3000],
+ ["hands_behind_head", 2300],
+ ["hands_on_hips", 3000],
+ ["hands_on_hips_2", 3900],
+ ["hands_together", 2500],
+ ["lean_forward", 2700],
+ ["lean_left", 2700],
+ ["lean_right", 3500],
+ ["look_around", 3000],
+ ["play_with_hair", 2900],
];
return moves[Math.floor(Math.random() * moves.length)];
diff --git a/src/resources/initial_progress.json b/src/resources/initial_progress.json
index af2d3c2..ee6defc 100644
--- a/src/resources/initial_progress.json
+++ b/src/resources/initial_progress.json
@@ -1747,31 +1747,31 @@
"is_viewed": 0,
"is_visible": 1
},
- "Sskn01": {
+ "SSkn01": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn02": {
+ "SSkn02": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn03": {
+ "SSkn03": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn04": {
+ "SSkn04": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn04#": {
+ "SSkn04#": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn05": {
+ "SSkn05": {
"is_viewed": 0,
"is_visible": 1
},
- "Sskn06": {
+ "SSkn06": {
"is_viewed": 0,
"is_visible": 1
},
diff --git a/src/resources/site_a.json b/src/resources/site_a.json
index 2ea5c1d..1d3d969 100644
--- a/src/resources/site_a.json
+++ b/src/resources/site_a.json
@@ -1644,7 +1644,7 @@
"3": "-1"
},
"media_file": "INS01.STR",
- "node_name": "Sskn01",
+ "node_name": "SSkn01",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@@ -2748,7 +2748,7 @@
"3": "-1"
},
"media_file": "INS02.STR",
- "node_name": "Sskn02",
+ "node_name": "SSkn02",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@@ -4892,7 +4892,7 @@
"3": "-1"
},
"media_file": "INS03.STR",
- "node_name": "Sskn03",
+ "node_name": "SSkn03",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
@@ -7302,7 +7302,7 @@
"3": "-1"
},
"media_file": "INS04.STR",
- "node_name": "Sskn04",
+ "node_name": "SSkn04",
"required_final_video_viewcount": 0,
"site": "A",
"title": "mT up-date App.",
diff --git a/src/resources/site_b.json b/src/resources/site_b.json
index e30ecfb..1758350 100644
--- a/src/resources/site_b.json
+++ b/src/resources/site_b.json
@@ -8,7 +8,7 @@
"3": "-1"
},
"media_file": "INS05.STR",
- "node_name": "Sskn04#",
+ "node_name": "SSkn04#",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",
@@ -1510,7 +1510,7 @@
"3": "-1"
},
"media_file": "INS06.STR",
- "node_name": "Sskn05",
+ "node_name": "SSkn05",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",
@@ -2968,7 +2968,7 @@
"3": "-1"
},
"media_file": "INS07.STR",
- "node_name": "Sskn06",
+ "node_name": "SSkn06",
"required_final_video_viewcount": 0,
"site": "B",
"title": "mT up-date App.",
@@ -5811,4 +5811,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/scenes/ChangeDiscScene.tsx b/src/scenes/ChangeDiscScene.tsx
index 9e61000..c18828a 100644
--- a/src/scenes/ChangeDiscScene.tsx
+++ b/src/scenes/ChangeDiscScene.tsx
@@ -28,7 +28,7 @@ const ChangeDiscScene = () => {
const disc2Tex = useLoader(THREE.TextureLoader, disc2);
useEffect(() => {
- // setTimeout(() => setScene("main"), 3500);
+ setTimeout(() => setScene("main"), 3500);
}, [activeSite, setScene]);
return (
@@ -70,7 +70,10 @@ const ChangeDiscScene = () => {
-
+
>
);
diff --git a/src/scenes/IdleMediaScene.tsx b/src/scenes/IdleMediaScene.tsx
index 6761657..2b2c805 100644
--- a/src/scenes/IdleMediaScene.tsx
+++ b/src/scenes/IdleMediaScene.tsx
@@ -15,6 +15,7 @@ const IdleMediaScene = () => {
useStore.setState({
currentScene: "main",
idleStarting: false,
+ intro: false,
});
}, [mediaPercentageElapsed]);
diff --git a/src/store.ts b/src/store.ts
index 54588ee..4707318 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -46,32 +46,26 @@ type State = {
activeNodeRot: number[];
activeNodeAttributes: NodeAttributes;
- // lain
lainMoveState: string;
+ canLainMove: boolean;
- // site
activeSite: ActiveSite;
siteRot: number[];
oldSiteRot: number[];
- // level
activeLevel: string;
oldLevel: string;
- // level selection
selectedLevel: number;
- // end scene
activeEndComponent: EndComponent;
endSceneSelectionVisible: boolean;
- // pause
activePauseComponent: PauseComponent;
pauseExitAnimation: boolean;
showingAbout: boolean;
permissionDenied: boolean;
- // media/media scene
audioAnalyser: AudioAnalyser | undefined;
mediaPercentageElapsed: number;
currentMediaSide: MediaSide;
@@ -84,39 +78,30 @@ type State = {
mediaWordPosStateIdx: number;
wordSelected: boolean;
- // idle scene
idleStarting: boolean;
idleMedia: string;
idleImages: { "1": string; "2": string; "3": string } | undefined;
idleNodeName: string | undefined;
- // sskn scene
activeSsknComponent: SsknComponent;
ssknLoading: boolean;
- // polytan scene
polytanUnlockedParts: PolytanBodyParts;
- // player name
playerName: string;
- // boot scene
activeMainMenuComponent: MainMenuComponent;
authorizeUserLetterIdx: number;
bootSubscene: BootSubscene;
- // prompt
promptVisible: boolean;
activePromptComponent: PromptComponent;
- // status notifiers
loadSuccessful: boolean | undefined;
saveSuccessful: boolean | undefined;
- // word not found notification thing
wordNotFound: boolean;
- // save state
siteSaveState: SiteSaveState;
inputCooldown: number;
@@ -126,7 +111,7 @@ export const useStore = create(
combine(
{
// scene data
- currentScene: "change_disc",
+ currentScene: "main",
// game progress
gameProgress: game_progress,
@@ -153,6 +138,7 @@ export const useStore = create(
// lain
lainMoveState: "standing",
+ canLainMove: true,
// site
activeSite: "a",
@@ -324,6 +310,7 @@ export const useStore = create(
gate_level: state.gameProgress.gate_level + 1,
},
})),
+
loadUserSaveState: (userState: UserSaveState) =>
set(() => ({
siteSaveState: userState.siteSaveState,
@@ -362,6 +349,7 @@ export const getMainSceneContext = (): MainSceneContext => {
showingAbout: state.showingAbout,
siteSaveState: state.siteSaveState,
wordNotFound: state.wordNotFound,
+ canLainMove: state.canLainMove,
};
};
diff --git a/src/types/types.ts b/src/types/types.ts
index a43ef27..ad330de 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -108,6 +108,7 @@ export interface MainSceneContext extends PromptContext {
selectedLevel: number;
wordNotFound: boolean;
siteSaveState: SiteSaveState;
+ canLainMove: boolean;
}
export type SsknSceneContext = {
diff --git a/src/utils/getKeyPress.ts b/src/utils/getKeyPress.ts
new file mode 100644
index 0000000..a04e5c6
--- /dev/null
+++ b/src/utils/getKeyPress.ts
@@ -0,0 +1,16 @@
+const getKeyPress = (keyCode: string) => {
+ const keyCodeAssocs = {
+ ArrowDown: "DOWN", // down arrow
+ ArrowLeft: "LEFT", // left arrow
+ ArrowUp: "UP", // up arrow
+ ArrowRight: "RIGHT", // right arrow
+ x: "CIRCLE", // x key
+ z: "X", // z key
+ d: "TRIANGLE", // d key
+ e: "L2", // e key
+ v: "START", // v key
+ };
+ return keyCodeAssocs[keyCode as keyof typeof keyCodeAssocs];
+};
+
+export default getKeyPress;
diff --git a/src/utils/parseUserInput.ts b/src/utils/parseUserInput.ts
deleted file mode 100644
index a4bbdc7..0000000
--- a/src/utils/parseUserInput.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export const getKeyCodeAssociation = (keyCode: number) => {
- const keyCodeAssocs = {
- 40: "DOWN", // down arrow
- 37: "LEFT", // left arrow
- 38: "UP", // up arrow
- 39: "RIGHT", // right arrow
- 88: "CIRCLE", // x key
- 90: "X", // z key
- 68: "TRIANGLE", // d key
- 69: "L2", // e key
- 86: "START", // v key
- 32: "SPACE",
- };
- return keyCodeAssocs[keyCode as keyof typeof keyCodeAssocs];
-};