diff --git a/src/__tests__/helpers/idle-helpers.test.ts b/src/__tests__/helpers/idle-helpers.test.ts
new file mode 100644
index 0000000..9c036c4
--- /dev/null
+++ b/src/__tests__/helpers/idle-helpers.test.ts
@@ -0,0 +1,38 @@
+import { isPolytanFullyUnlocked } from "../../store";
+import { useStore } from "../../store";
+
+const initialStoreState = useStore.getState();
+
+describe("Idle helpers", () => {
+ it("Checks if polytan unlock works properly", () => {
+ expect(isPolytanFullyUnlocked()).toEqual(false);
+
+ const fullyUnlocked = {
+ body: true,
+ head: true,
+ leftArm: true,
+ rightArm: true,
+ leftLeg: true,
+ rightLeg: true,
+ };
+
+ useStore.setState({ polytanUnlockedParts: fullyUnlocked });
+ expect(isPolytanFullyUnlocked()).toEqual(true);
+
+ const partiallyUnlocked = {
+ body: false,
+ head: true,
+ leftArm: false,
+ rightArm: true,
+ leftLeg: true,
+ rightLeg: true,
+ };
+
+ useStore.setState({ polytanUnlockedParts: partiallyUnlocked });
+ expect(isPolytanFullyUnlocked()).toEqual(false);
+ });
+
+ beforeEach(() => {
+ useStore.setState(initialStoreState, true);
+ });
+});
diff --git a/src/__tests__/helpers/name-selection-helpers.test.ts b/src/__tests__/helpers/name-selection-helpers.test.ts
index 323b822..91a2338 100644
--- a/src/__tests__/helpers/name-selection-helpers.test.ts
+++ b/src/__tests__/helpers/name-selection-helpers.test.ts
@@ -1,4 +1,4 @@
-import handleNameSelection from "../../helpers/name-selection-helpers";
+import { handleNameSelection } from "../../helpers/name-selection-helpers";
it("Handles the logic for japanese characters", () => {
// cant be first character check
diff --git a/src/__tests__/helpers/node-helpers.test.ts b/src/__tests__/helpers/node-helpers.test.ts
index 9641a5f..b2a091e 100644
--- a/src/__tests__/helpers/node-helpers.test.ts
+++ b/src/__tests__/helpers/node-helpers.test.ts
@@ -6,7 +6,7 @@ it("Finds the node by it's id", () => {
expect(getNodeById("0422", "a").node_name).toEqual("Tda028");
expect(getNodeById("0000", "a").node_name).toEqual("Env001");
expect(getNodeById("0616", "a").node_name).toEqual("Cou015");
- expect(getNodeById("0100", "b").node_name).toEqual("Sskn04#");
+ expect(getNodeById("0100", "b").node_name).toEqual("SSkn04#");
expect(getNodeById("0101", "b").node_name).toEqual("Dc1025");
});
diff --git a/src/__tests__/input-handlers/handleBootSceneInput.test.ts b/src/__tests__/input-handlers/handleBootSceneInput.test.ts
index de3d8e8..89f8142 100644
--- a/src/__tests__/input-handlers/handleBootSceneInput.test.ts
+++ b/src/__tests__/input-handlers/handleBootSceneInput.test.ts
@@ -36,7 +36,10 @@ it("Checks whether or not the boot scene input handler reacts appropriately for
}
{
// change letter in authorize user scene
- const spy = jest.spyOn(eventTemplates, "updateAuthorizeUserLetterIdx");
+ const spy = jest.spyOn(
+ eventTemplates,
+ "updateAuthorizeUserLetterMatrixIndices"
+ );
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
@@ -65,7 +68,7 @@ it("Checks whether or not the boot scene input handler reacts appropriately for
playerName: "チ",
};
- handleBootSceneInput(testContext, "X");
+ handleBootSceneInput(testContext, "CROSS");
expect(spy).toHaveBeenCalled();
}
@@ -77,7 +80,7 @@ it("Checks whether or not the boot scene input handler reacts appropriately for
playerName: "",
};
- expect(handleBootSceneInput(testContext, "X")).toEqual(
+ expect(handleBootSceneInput(testContext, "CROSS")).toEqual(
exitUserAuthorization
);
}
diff --git a/src/__tests__/input-handlers/handleMediaSceneInput.test.ts b/src/__tests__/input-handlers/handleMediaSceneInput.test.ts
index 903ff05..ccefcaa 100644
--- a/src/__tests__/input-handlers/handleMediaSceneInput.test.ts
+++ b/src/__tests__/input-handlers/handleMediaSceneInput.test.ts
@@ -35,11 +35,10 @@ it("Checks whether or not the media scene input handler reacts appropriately for
{
// play media
- const spy = jest.spyOn(eventTemplates, "playMedia");
- const testContext = getMediaSceneContext();
- handleMediaSceneInput(testContext, "CIRCLE");
-
- expect(spy).toHaveBeenCalled();
+ // const testContext = getMediaSceneContext();
+ // expect(handleMediaSceneInput(testContext, "CIRCLE")).toEqual(
+ // eventTemplates.playMedia
+ // );
}
{
// change right side media component
diff --git a/src/components/MainScene/HUD.tsx b/src/components/MainScene/HUD.tsx
index 54a6914..cd4c87c 100644
--- a/src/components/MainScene/HUD.tsx
+++ b/src/components/MainScene/HUD.tsx
@@ -1,4 +1,4 @@
-import React, { createRef, memo, useEffect, useRef } from "react";
+import React, { memo, useEffect, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import bigHud from "../../static/sprites/main/big_hud.png";
diff --git a/src/components/MainScene/Site/Site.tsx b/src/components/MainScene/Site/Site.tsx
index 7d92571..d7bbc28 100644
--- a/src/components/MainScene/Site/Site.tsx
+++ b/src/components/MainScene/Site/Site.tsx
@@ -43,6 +43,11 @@ const Site = (props: SiteProps) => {
config: { duration: 1200 },
}));
+ const [tiltState, setTiltState] = useSpring(() => ({
+ tilt: 0,
+ config: { duration: 200 },
+ }));
+
useEffect(
() =>
useStore.subscribe(setRotY, (state) => ({
@@ -69,6 +74,12 @@ const Site = (props: SiteProps) => {
[setPos]
);
+ useEffect(() =>
+ useStore.subscribe(setTiltState, (state) => ({
+ tilt: state.cameraTiltValue,
+ }))
+ );
+
const activeSite = useStore((state) => state.activeSite);
const gameProgress = useStore((state) => state.gameProgress);
@@ -80,13 +91,15 @@ const Site = (props: SiteProps) => {
return (
: null}>
-
-
-
-
-
+
+
+
+
+
+
+
+
-
);
diff --git a/src/components/TextRenderer/MainYellowTextAnimator.tsx b/src/components/TextRenderer/MainYellowTextAnimator.tsx
index 7fe371c..2f0313c 100644
--- a/src/components/TextRenderer/MainYellowTextAnimator.tsx
+++ b/src/components/TextRenderer/MainYellowTextAnimator.tsx
@@ -42,19 +42,19 @@ const MainYellowTextAnimator = (props: { visible?: boolean }) => {
}, [activeNode, prevData?.subscene, set, subscene, gameProgress]);
return (
-
+
{trail.map(({ posX, posY }, idx) => (
))}
-
+
);
};
diff --git a/src/core/eventTemplates.ts b/src/core/eventTemplates.ts
index 3d886e0..8174074 100644
--- a/src/core/eventTemplates.ts
+++ b/src/core/eventTemplates.ts
@@ -39,6 +39,7 @@ export const siteMoveHorizontal = (calculatedState: {
mutation: {
lainMoveState: calculatedState.lainMoveAnimation,
siteRot: calculatedState.siteRot,
+ cameraTiltValue: 0,
inputCooldown: 5500,
},
},
@@ -62,6 +63,7 @@ export const siteMoveVertical = (calculatedState: {
{
mutation: {
lainMoveState: calculatedState.lainMoveAnimation,
+ cameraTiltValue: 0,
activeLevel: calculatedState.activeLevel,
inputCooldown: 5500,
},
@@ -95,6 +97,7 @@ export const throwNode = (calculatedState: { currentScene: GameScene }) => ({
{ mutation: { lainMoveState: "throw_node", inputCooldown: -1 } },
{
mutation: {
+ cameraTiltValue: 0,
currentScene: calculatedState.currentScene,
intro: false,
lainMoveState: "standing",
@@ -116,6 +119,7 @@ export const ripNode = (calculatedState: { currentScene: GameScene }) => ({
{
mutation: {
currentScene: calculatedState.currentScene,
+ cameraTiltValue: 0,
intro: false,
lainMoveState: "standing",
},
@@ -136,6 +140,7 @@ export const explodeNode = {
mutation: {
lainMoveState: "touch_node_and_get_scared",
inputCooldown: 3800,
+ cameraTiltValue: 0,
},
},
{
@@ -153,7 +158,13 @@ export const explodeNode = {
export const knockNode = {
state: [
- { mutation: { lainMoveState: "knock", inputCooldown: 3500 } },
+ {
+ mutation: {
+ lainMoveState: "knock",
+ cameraTiltValue: 0,
+ inputCooldown: 3500,
+ },
+ },
{
mutation: { lainMoveState: "standing" },
delay: 3500,
@@ -165,7 +176,13 @@ export const knockNode = {
export const knockNodeAndFall = {
state: [
- { mutation: { lainMoveState: "knock_and_fall", inputCooldown: 6000 } },
+ {
+ mutation: {
+ lainMoveState: "knock_and_fall",
+ cameraTiltValue: 0,
+ inputCooldown: 6000,
+ },
+ },
{ mutation: { lainMoveState: "standing" }, delay: 6000 },
],
effects: [nodeKnockAndFallAnimation],
@@ -184,6 +201,7 @@ export const enterLevelSelection = (calculatedState: {
{
mutation: {
selectedLevel: calculatedState.selectedLevel,
+ cameraTiltValue: 0,
mainSubscene: "level_selection",
inputCooldown: 1500,
},
@@ -243,6 +261,7 @@ export const pauseGame = (calculatedState: { siteRot: number[] }) => ({
{
mutation: {
lainMoveState: "rip_middle_ring",
+ cameraTiltValue: 0,
mainSubscene: "pause",
inputCooldown: -1,
},
@@ -797,6 +816,33 @@ export const setProtocolLines = (calculatedState: {
],
});
+export const setCameraTilt = (calculatedState: {
+ cameraTiltValue: number;
+}) => ({
+ state: [
+ {
+ mutation: {
+ cameraTiltValue: calculatedState.cameraTiltValue,
+ inputCooldown: 100,
+ },
+ },
+ ],
+});
+
+export const resetCameraTilt = (calculatedState: {
+ lastCameraTiltValue: number;
+}) => ({
+ state: [
+ {
+ mutation: {
+ cameraTiltValue: 0,
+ lastCameraTiltValue: calculatedState.lastCameraTiltValue,
+ inputCooldown: 100,
+ },
+ },
+ ],
+});
+
export const resetInputCooldown = {
state: [{ mutation: { inputCooldown: 0 } }],
};
diff --git a/src/core/input-handlers/handleMainSceneInput.ts b/src/core/input-handlers/handleMainSceneInput.ts
index b4471d3..a13aa7a 100644
--- a/src/core/input-handlers/handleMainSceneInput.ts
+++ b/src/core/input-handlers/handleMainSceneInput.ts
@@ -25,10 +25,12 @@ import {
loadGame,
loadGameFail,
pauseGame,
+ resetCameraTilt,
resetInputCooldown,
ripNode,
saveGame,
selectLevel,
+ setCameraTilt,
setProtocolLines,
showAbout,
showPermissionDenied,
@@ -59,6 +61,8 @@ const handleMainSceneInput = (
wordNotFound,
canLainMove,
protocolLinesToggled,
+ cameraTiltValue,
+ lastCameraTiltValue,
} = mainSceneContext;
if (promptVisible) {
@@ -208,6 +212,7 @@ const handleMainSceneInput = (
case "L2":
return enterLevelSelection({ selectedLevel: level });
case "TRIANGLE":
+ case "SELECT":
if (!canLainMove) return resetInputCooldown;
return pauseGame({ siteRot: [Math.PI / 2, siteRotY, 0] });
case "L1":
@@ -250,6 +255,16 @@ const handleMainSceneInput = (
return setProtocolLines({
protocolLinesToggled: !protocolLinesToggled,
});
+ case "R2":
+ if (cameraTiltValue === 0) {
+ return setCameraTilt({
+ cameraTiltValue: -lastCameraTiltValue,
+ });
+ } else {
+ return resetCameraTilt({
+ lastCameraTiltValue: -lastCameraTiltValue,
+ });
+ }
}
break;
case "level_selection":
diff --git a/src/dom-components/Notes.tsx b/src/dom-components/Notes.tsx
index e9b3363..6422cda 100644
--- a/src/dom-components/Notes.tsx
+++ b/src/dom-components/Notes.tsx
@@ -99,10 +99,26 @@ const Notes = () => {
z |
✖ |
+
+ s |
+ ◼ |
+
d |
▲ |
+
+ r |
+ R1 |
+
+
+ t |
+ R2 |
+
+
+ w |
+ L1 |
+
e |
L2 |
@@ -111,6 +127,10 @@ const Notes = () => {
v |
START |
+
+ c |
+ SELECT |
+
k |
Upscale Game Window |
diff --git a/src/helpers/idle-helpers.ts b/src/helpers/idle-helpers.ts
index df860e6..37289cd 100644
--- a/src/helpers/idle-helpers.ts
+++ b/src/helpers/idle-helpers.ts
@@ -1,6 +1,6 @@
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
-import { useStore } from "../store";
+import { isPolytanFullyUnlocked, useStore } from "../store";
import { SiteData } from "../types/types";
export const getRandomIdleMedia = () => {
@@ -78,7 +78,7 @@ export const getRandomIdleMedia = () => {
nodeName: nodeName,
};
} else {
- if (site === "b" && Math.random() < 0.3) {
+ if (site === "b" && isPolytanFullyUnlocked() && Math.random() < 0.3) {
const polytanMedia = ["PO1.STR[0]", "PO2.STR[0]"];
return {
type: "video",
diff --git a/src/resources/node_huds.json b/src/resources/node_huds.json
index dd4eadf..968c64f 100644
--- a/src/resources/node_huds.json
+++ b/src/resources/node_huds.json
@@ -18,7 +18,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [-0.35, 0.23, -8.7]
+ "big_text": [-0.3, 0.2, -8.7]
},
"fg_hud_2": {
"mirrored": 0,
@@ -39,7 +39,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [-0.35, -0.05, -8.7]
+ "big_text": [-0.3, -0.04, -8.7]
},
"fg_hud_3": {
"mirrored": 0,
@@ -60,7 +60,7 @@
[0.09, 0.18, 0]
]
},
- "big_text": [-0.35, -0.32, -8.7]
+ "big_text": [-0.3, -0.27, -8.7]
},
"fg_hud_4": {
"mirrored": 1,
@@ -81,7 +81,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [0.45, 0.265, -8.7]
+ "big_text": [0.39, 0.23, -8.7]
},
"fg_hud_5": {
"mirrored": 1,
@@ -102,7 +102,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [0.45, -0.05, -8.7]
+ "big_text": [0.39, -0.04, -8.7]
},
"fg_hud_6": {
"mirrored": 1,
@@ -123,7 +123,7 @@
[0.09, 0.18, 0]
]
},
- "big_text": [0.45, -0.32, -8.7]
+ "big_text": [0.39, -0.27, -8.7]
},
"bg_hud_1": {
"mirrored": 0,
@@ -144,7 +144,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [-0.15, 0.1, -8.7]
+ "big_text": [-0.15, 0.09, -8.7]
},
"bg_hud_2": {
"mirrored": 0,
@@ -165,7 +165,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [-0.15, -0.03, -8.7]
+ "big_text": [-0.15, -0.02, -8.7]
},
"bg_hud_3": {
"mirrored": 0,
@@ -186,7 +186,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [-0.15, -0.17, -8.7]
+ "big_text": [-0.15, -0.14, -8.7]
},
"bg_hud_4": {
"mirrored": 1,
@@ -195,7 +195,7 @@
"initial_position": [1.63, 0.04, -8.6]
},
"boring": {
- "position": [-0.28, 0.06, -8.6],
+ "position": [-0.3, 0.06, -8.6],
"initial_position": [-1.28, 0.06, -8.6]
},
"big": {
@@ -207,7 +207,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [0.2, 0.1, -8.7]
+ "big_text": [0.2, 0.09, -8.7]
},
"bg_hud_5": {
"mirrored": 1,
@@ -228,7 +228,7 @@
[-0.09, -0.18, 0]
]
},
- "big_text": [0.2, -0.03, -8.7]
+ "big_text": [0.2, -0.02, -8.7]
},
"bg_hud_6": {
"mirrored": 1,
@@ -237,7 +237,7 @@
"initial_position": [1.63, -0.19, -8.6]
},
"boring": {
- "position": [-0.29, -0.17, -8.6],
+ "position": [-0.3, -0.17, -8.6],
"initial_position": [-1.29, -0.17, -8.6]
},
"big": {
@@ -249,6 +249,6 @@
[0.09, 0.18, 0]
]
},
- "big_text": [0.2, -0.17, -8.7]
+ "big_text": [0.2, -0.14, -8.7]
}
}
diff --git a/src/scenes/MainScene.tsx b/src/scenes/MainScene.tsx
index aa29d4a..3118f33 100644
--- a/src/scenes/MainScene.tsx
+++ b/src/scenes/MainScene.tsx
@@ -139,6 +139,18 @@ const MainScene = () => {
mainSceneMusic.pause();
};
}, [intro, introFinished, showingAbout]);
+
+ const [tiltState, setTiltState] = useSpring(() => ({
+ posY: 0,
+ config: { duration: 200 },
+ }));
+
+ useEffect(() =>
+ useStore.subscribe(setTiltState, (state) => ({
+ posY: -state.cameraTiltValue,
+ }))
+ );
+
return (
}>
@@ -153,10 +165,10 @@ const MainScene = () => {
-
+
-
+
@@ -168,12 +180,12 @@ const MainScene = () => {
mainVisible={intro ? starfieldIntro : true}
/>
-
+
-
+
{
wordNotFound: state.wordNotFound,
canLainMove: state.canLainMove,
protocolLinesToggled: state.protocolLinesToggled,
+ cameraTiltValue: state.cameraTiltValue,
+ lastCameraTiltValue: state.lastCameraTiltValue,
};
};
@@ -454,15 +463,10 @@ export const createAudioAnalyser = () => {
};
export const isPolytanFullyUnlocked = () => {
- return (
- useStore.getState().polytanUnlockedParts ===
- {
- body: true,
- head: true,
- leftArm: true,
- rightArm: true,
- leftLeg: true,
- rightLeg: true,
- }
- );
+ const polytanProgress = useStore.getState().polytanUnlockedParts;
+
+ for (const key in polytanProgress)
+ if (!polytanProgress[key as keyof typeof polytanProgress]) return false;
+
+ return true;
};
diff --git a/src/types/types.ts b/src/types/types.ts
index eb2bdae..aff822d 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -115,6 +115,8 @@ export interface MainSceneContext extends PromptContext {
siteSaveState: SiteSaveState;
canLainMove: boolean;
protocolLinesToggled: boolean;
+ cameraTiltValue: number;
+ lastCameraTiltValue: number;
}
export type SsknSceneContext = {
diff --git a/src/utils/getKeyPress.ts b/src/utils/getKeyPress.ts
index c619cf7..5872288 100644
--- a/src/utils/getKeyPress.ts
+++ b/src/utils/getKeyPress.ts
@@ -1,5 +1,6 @@
const getKeyPress = (key: string) => {
- if (["X", "Z", "D", "E", "V", "T", "W", "R"].includes(key))
+ // make the keybinds work with caps lock on aswell
+ if (["X", "Z", "D", "E", "V", "T", "W", "R", "S", "C"].includes(key))
key = key.toLowerCase();
const keyCodeAssocs = {
@@ -11,10 +12,12 @@ const getKeyPress = (key: string) => {
z: "CROSS",
d: "TRIANGLE",
s: "SQUARE",
+ t: "R2",
e: "L2",
- v: "START",
w: "L1",
r: "R1",
+ v: "START",
+ c: "SELECT",
};
return keyCodeAssocs[key as keyof typeof keyCodeAssocs];
};