implemented R2, added/fixed some tests, more bugfixes

This commit is contained in:
ad044 2021-03-20 22:06:00 +04:00
parent c2d5337168
commit fcc108a445
17 changed files with 211 additions and 56 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 (
<Suspense fallback={props.introFinished ? <Loading /> : null}>
<a.group rotation-x={rotXState.x}>
<a.group rotation-y={rotYState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />
<InactiveLevelNodes visibleNodes={visibleNodes} />
<Rings activateAllRings={props.introFinished} />
<a.group rotation-x={tiltState.tilt}>
<a.group rotation-x={rotXState.x}>
<a.group rotation-y={rotYState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />
<InactiveLevelNodes visibleNodes={visibleNodes} />
<Rings activateAllRings={props.introFinished} />
</a.group>
<NodeAnimations />
</a.group>
<NodeAnimations />
</a.group>
</Suspense>
);

View file

@ -42,19 +42,19 @@ const MainYellowTextAnimator = (props: { visible?: boolean }) => {
}, [activeNode, prevData?.subscene, set, subscene, gameProgress]);
return (
<a.group position-z={10} visible={props.visible}>
<group position={[0, 0, 10]} visible={props.visible}>
{trail.map(({ posX, posY }, idx) => (
<a.group
key={idx}
position-x={posX}
position-y={posY}
position-z={-8.7}
scale={[0.04, 0.06, 0.04]}
position-z={-8.6}
scale={[0.035, 0.055, 0.035]}
>
<BigLetter letter={text[idx]} letterIdx={idx} key={idx} />
</a.group>
))}
</a.group>
</group>
);
};

View file

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

View file

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

View file

@ -99,10 +99,26 @@ const Notes = () => {
<td>z</td>
<td></td>
</tr>
<tr>
<td>s</td>
<td></td>
</tr>
<tr>
<td>d</td>
<td></td>
</tr>
<tr>
<td>r</td>
<td>R1</td>
</tr>
<tr>
<td>t</td>
<td>R2</td>
</tr>
<tr>
<td>w</td>
<td>L1</td>
</tr>
<tr>
<td>e</td>
<td>L2</td>
@ -111,6 +127,10 @@ const Notes = () => {
<td>v</td>
<td>START</td>
</tr>
<tr>
<td>c</td>
<td>SELECT</td>
</tr>
<tr>
<td>k</td>
<td>Upscale Game Window</td>

View file

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

View file

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

View file

@ -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 (
<group position-z={3}>
<Suspense fallback={<Loading />}>
@ -153,10 +165,10 @@ const MainScene = () => {
</a.group>
<group visible={!paused}>
<group visible={!wordSelected && (intro ? introFinished : true)}>
<group visible={!wordNotFound}>
<a.group visible={!wordNotFound} position-y={tiltState.posY}>
<HUD />
<MainYellowTextAnimator />
</group>
</a.group>
<MiddleRing />
<GrayPlanes />
</group>
@ -168,12 +180,12 @@ const MainScene = () => {
mainVisible={intro ? starfieldIntro : true}
/>
</group>
<group visible={!wordSelected}>
<a.group visible={!wordSelected} position-y={tiltState.posY}>
<Lain
shouldAnimate={lainIntroAnim}
introFinished={intro ? introFinished : true}
/>
</group>
</a.group>
<group
ref={introWrapperRef}
position-z={intro ? -10 : 0}

View file

@ -52,6 +52,9 @@ type State = {
lainMoveState: string;
canLainMove: boolean;
lastCameraTiltValue: number;
cameraTiltValue: number;
activeSite: ActiveSite;
siteRot: number[];
oldSiteRot: number[];
@ -145,6 +148,10 @@ export const useStore = create(
// extra node data display
protocolLinesToggled: false,
// camera tilt
lastCameraTiltValue: -0.08,
cameraTiltValue: 0,
// site
activeSite: "a",
siteRot: [0, 0, 0],
@ -368,6 +375,8 @@ export const getMainSceneContext = (): MainSceneContext => {
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;
};

View file

@ -115,6 +115,8 @@ export interface MainSceneContext extends PromptContext {
siteSaveState: SiteSaveState;
canLainMove: boolean;
protocolLinesToggled: boolean;
cameraTiltValue: number;
lastCameraTiltValue: number;
}
export type SsknSceneContext = {

View file

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