From 8f303e455a408449bb0a3cf9e9a03fb7d33f6264 Mon Sep 17 00:00:00 2001 From: ad044 Date: Sun, 7 Feb 2021 19:12:19 +0400 Subject: [PATCH] added prompt, and word selection node not found handling --- src/components/BootScene/BootLoadData.tsx | 173 +++--- src/components/KeyPressHandler.tsx | 4 + src/components/MainScene/HUD.tsx | 1 + src/components/MainScene/NotFound.tsx | 48 ++ .../MainScene/PauseSubscene/About.tsx | 41 ++ .../MainScene/PauseSubscene/Pause.tsx | 12 +- src/components/Prompt.tsx | 110 ++++ src/components/TextRenderer/BigLetter.tsx | 1 + .../TextRenderer/YellowTextRenderer.tsx | 3 +- .../handleMainKeyPress.ts | 505 ++++++++++-------- .../handleMediaKeyPress.ts | 7 +- src/core/setters/main/mainSubsceneManager.ts | 6 + src/core/setters/main/pause/pauseManager.ts | 9 + src/core/setters/media/mediaManager.ts | 1 - src/core/setters/promptManager.ts | 32 ++ src/core/setters/sceneManager.ts | 1 + src/scenes/MainScene.tsx | 8 +- src/store.ts | 23 + src/utils/media-utils.ts | 12 +- 19 files changed, 658 insertions(+), 339 deletions(-) create mode 100644 src/components/MainScene/NotFound.tsx create mode 100644 src/components/MainScene/PauseSubscene/About.tsx create mode 100644 src/components/Prompt.tsx create mode 100644 src/core/setters/promptManager.ts diff --git a/src/components/BootScene/BootLoadData.tsx b/src/components/BootScene/BootLoadData.tsx index e92e5e9..fdf458e 100644 --- a/src/components/BootScene/BootLoadData.tsx +++ b/src/components/BootScene/BootLoadData.tsx @@ -14,92 +14,93 @@ type BootLoadDataProps = { }; const BootLoadData = (props: BootLoadDataProps) => { - const loadDataUnderlineTex = useLoader( - THREE.TextureLoader, - loadDataUnderline - ); - const loadDataQuestionContainerTex = useLoader( - THREE.TextureLoader, - loadDataQuestionContainer - ); - const loadDataAnswerContainerTex = useLoader( - THREE.TextureLoader, - loadDataAnswerContainer - ); - const areYouSureTex = useLoader(THREE.TextureLoader, areYouSure); - const yesTex = useLoader(THREE.TextureLoader, yes); - const noTex = useLoader(THREE.TextureLoader, no); - - return ( - <> - {props.visible ? ( - <> - - - - - - - - - - - - - - - - - - - - - - - - - ) : ( - <> - )} - - ); + // const loadDataUnderlineTex = useLoader( + // THREE.TextureLoader, + // loadDataUnderline + // ); + // const loadDataQuestionContainerTex = useLoader( + // THREE.TextureLoader, + // loadDataQuestionContainer + // ); + // const loadDataAnswerContainerTex = useLoader( + // THREE.TextureLoader, + // loadDataAnswerContainer + // ); + // const areYouSureTex = useLoader(THREE.TextureLoader, areYouSure); + // const yesTex = useLoader(THREE.TextureLoader, yes); + // const noTex = useLoader(THREE.TextureLoader, no); + // + // return ( + // <> + // {props.visible ? ( + // <> + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // ) : ( + // <> + // )} + // + // ); + return <>; }; export default BootLoadData; diff --git a/src/components/KeyPressHandler.tsx b/src/components/KeyPressHandler.tsx index 5daab03..0c72267 100644 --- a/src/components/KeyPressHandler.tsx +++ b/src/components/KeyPressHandler.tsx @@ -22,6 +22,7 @@ import handleMainSceneEvent from "../core/scene-keypress-handlers/handleMainKeyP import gameLoader from "../core/setters/gameLoader"; import gameSaver from "../core/setters/gameSaver"; import progressManager from "../core/setters/progressManager"; +import promptManager from "../core/setters/promptManager"; const KeyPressHandler = () => { const mediaSceneSetters = useMemo( @@ -32,6 +33,7 @@ const KeyPressHandler = () => { levelManager, siteManager, progressManager, + mainSubsceneManager, ], [] ); @@ -52,6 +54,7 @@ const KeyPressHandler = () => { gameLoader, gameSaver, progressManager, + promptManager, ], [] ); @@ -92,6 +95,7 @@ const KeyPressHandler = () => { }; case "gate": case "polytan": + case "about": return { action: () => useStore.setState({ currentScene: "main" }), }; diff --git a/src/components/MainScene/HUD.tsx b/src/components/MainScene/HUD.tsx index 97f242a..59b21e7 100644 --- a/src/components/MainScene/HUD.tsx +++ b/src/components/MainScene/HUD.tsx @@ -130,6 +130,7 @@ const HUD = memo(() => { if ( !(scene === "main" && prevData?.scene === "main") || (subscene === "site" && prevData?.subscene === "pause") || + (subscene === "site" && prevData?.subscene === "not_found") || subscene === "pause" ) { // set to final pos instantly diff --git a/src/components/MainScene/NotFound.tsx b/src/components/MainScene/NotFound.tsx new file mode 100644 index 0000000..762290b --- /dev/null +++ b/src/components/MainScene/NotFound.tsx @@ -0,0 +1,48 @@ +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 && ( + <> + + + + + + + + + )} + + ); +}; + +export default NotFound; diff --git a/src/components/MainScene/PauseSubscene/About.tsx b/src/components/MainScene/PauseSubscene/About.tsx new file mode 100644 index 0000000..bf36931 --- /dev/null +++ b/src/components/MainScene/PauseSubscene/About.tsx @@ -0,0 +1,41 @@ +import React, { useRef } from "react"; +import aboutBg from "../../../static/sprite/about_background.png"; +import { useFrame, useLoader } from "react-three-fiber"; +import * as THREE from "three"; +import { useStore } from "../../../store"; + +const About = () => { + const setShowingAbout = useStore((state) => state.setShowingAbout); + const aboutBgTex = useLoader(THREE.TextureLoader, aboutBg); + + const bgRef = useRef(); + // todo im not sure where the other bg file is located, + // the one here is just the text, in the original game there's another one + + useFrame(() => { + if (bgRef.current) { + bgRef.current.position.y += 0.03; + if (Math.round(bgRef.current.position.y) === 14) { + setShowingAbout(false); + } + } + }); + + return ( + <> + + + + + + + + ); +}; + +export default About; diff --git a/src/components/MainScene/PauseSubscene/Pause.tsx b/src/components/MainScene/PauseSubscene/Pause.tsx index 4991f08..319b9df 100644 --- a/src/components/MainScene/PauseSubscene/Pause.tsx +++ b/src/components/MainScene/PauseSubscene/Pause.tsx @@ -4,9 +4,12 @@ import PauseSquare from "./PauseSquare"; import StaticBigLetter from "../../TextRenderer/StaticBigLetter"; import { useStore } from "../../../store"; import { useLoader } from "react-three-fiber"; +import About from "./About"; +import Prompt from "../../Prompt"; const Pause = () => { const exit = useStore((state) => state.pauseExitAnimation); + const showingAbout = useStore((state) => state.showingAbout); const [showActiveComponent, setShowActiveComponent] = useState(false); const [animation, setAnimation] = useState(false); const [intro, setIntro] = useState(true); @@ -274,7 +277,6 @@ const Pause = () => { active={activeComponent === "load"} /> ))} - {"About".split("").map((letter, idx) => ( 0 ? "yellow" : "orange"} @@ -286,7 +288,6 @@ const Pause = () => { key={idx} /> ))} - {"Change".split("").map((letter, idx) => ( 0 ? "yellow" : "orange"} @@ -298,7 +299,6 @@ const Pause = () => { key={idx} /> ))} - {"Save".split("").map((letter, idx) => ( 0 ? "yellow" : "orange"} @@ -310,7 +310,6 @@ const Pause = () => { key={idx} /> ))} - {"Exit".split("").map((letter, idx) => ( 0 ? "yellow" : "orange"} @@ -322,7 +321,6 @@ const Pause = () => { active={activeComponent === "exit"} /> ))} - { /> + {showingAbout && } + + + )} diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx new file mode 100644 index 0000000..86f3ed5 --- /dev/null +++ b/src/components/Prompt.tsx @@ -0,0 +1,110 @@ +import React, { useCallback, useEffect } 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"; +import no from "../static/sprite/prompt_no.png"; +import question from "../static/sprite/prompt_question.png"; +import { useLoader } from "react-three-fiber"; +import * as THREE from "three"; +import { useStore } from "../store"; + +const Prompt = () => { + const promptVisible = useStore((state) => state.promptVisible); + + const questionContainerTex = useLoader( + THREE.TextureLoader, + questionContainer + ); + const answerContainerTex = useLoader(THREE.TextureLoader, answerContainer); + const questionTex = useLoader(THREE.TextureLoader, question); + const yesTex = useLoader(THREE.TextureLoader, yes); + const noTex = useLoader(THREE.TextureLoader, no); + + const activeComponent = useStore( + useCallback( + (state) => state.promptComponentMatrix[state.promptComponentMatrixIdx], + [] + ) + ); + + useEffect(() => { + console.log(promptVisible); + }, [promptVisible]); + return ( + <> + {promptVisible && ( + <> + + + + + + + + + + + + + + + + + + + + + )} + + ); +}; + +export default Prompt; diff --git a/src/components/TextRenderer/BigLetter.tsx b/src/components/TextRenderer/BigLetter.tsx index 7552843..470b2c2 100644 --- a/src/components/TextRenderer/BigLetter.tsx +++ b/src/components/TextRenderer/BigLetter.tsx @@ -100,6 +100,7 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => { useEffect(() => { if ( subscene === "pause" || + (subscene === "site" && prevData?.subscene === "not_found") || (subscene === "site" && prevData?.subscene === "pause") ) return; diff --git a/src/components/TextRenderer/YellowTextRenderer.tsx b/src/components/TextRenderer/YellowTextRenderer.tsx index b71c0db..030adf1 100644 --- a/src/components/TextRenderer/YellowTextRenderer.tsx +++ b/src/components/TextRenderer/YellowTextRenderer.tsx @@ -3,7 +3,7 @@ import { useStore } from "../../store"; import { a, useTrail } from "@react-spring/three"; import BigLetter from "./BigLetter"; import usePrevious from "../../hooks/usePrevious"; -import {getNodeHud} from "../../utils/node-utils"; +import { getNodeHud } from "../../utils/node-utils"; const YellowTextRenderer = (props: { visible?: boolean }) => { const activeNode = useStore((state) => state.activeNode); @@ -22,6 +22,7 @@ const YellowTextRenderer = (props: { visible?: boolean }) => { useEffect(() => { const hud = getNodeHud(activeNode.matrixIndices!); + if (subscene === "level_selection") { setTimeout(() => { set({ posX: -0.02, posY: 0.005 }); diff --git a/src/core/scene-keypress-handlers/handleMainKeyPress.ts b/src/core/scene-keypress-handlers/handleMainKeyPress.ts index a5846db..a9fab40 100644 --- a/src/core/scene-keypress-handlers/handleMainKeyPress.ts +++ b/src/core/scene-keypress-handlers/handleMainKeyPress.ts @@ -18,273 +18,308 @@ const handleMainSceneEvent = (mainSceneContext: any) => { level, keyPress, ssknLvl, + showingAbout, + promptVisible, + activePromptComponent, } = mainSceneContext; - switch (subscene) { - case "site": - switch (keyPress) { - case "LEFT": - case "RIGHT": { - const keyPressToLower = keyPress.toLowerCase(); - - const nodeData = findNode( - activeNode.id, - keyPressToLower, - activeNode.matrixIndices!, - level, - currentSite, - gameProgress, - true - ); - - if (!nodeData) return; - - if (nodeData.didMove) { + if (promptVisible) { + switch (keyPress) { + case "LEFT": + return { event: "prompt_left" }; + case "RIGHT": + return { event: "prompt_right" }; + case "CIRCLE": + switch (activePromptComponent) { + case "no": + return { event: "exit_prompt" }; + case "yes": 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, currentSite) - : unknownNodeTemplate), - matrixIndices: nodeData.matrixIndices, - }, + event: `pause_${activePauseComponent}_select`, + site: currentSite, }; - } else { - return { - event: "change_node", - nodeMatrixIndices: nodeData.matrixIndices, - node: { - ...getNodeById(nodeData.node, currentSite), - matrixIndices: nodeData.matrixIndices, - }, - }; - } } - case "UP": - case "DOWN": { - const keyPressToLower = keyPress.toLowerCase(); - const nodeData = findNode( - activeNode.id, - keyPressToLower, - activeNode.matrixIndices!, - level, - currentSite, - gameProgress, - true - ); + } + } else { + switch (subscene) { + case "site": + switch (keyPress) { + case "LEFT": + case "RIGHT": { + const keyPressToLower = keyPress.toLowerCase(); - if (!nodeData) return; + const nodeData = findNode( + activeNode.id, + keyPressToLower, + activeNode.matrixIndices!, + level, + currentSite, + gameProgress, + true + ); - 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, currentSite) - : unknownNodeTemplate), - matrixIndices: nodeData.matrixIndices, - }, - }; - } else { - return { - event: "change_node", - node: { - ...getNodeById(nodeData.node, currentSite), - matrixIndices: nodeData.matrixIndices, - }, - }; + if (!nodeData) return; + + 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, currentSite) + : unknownNodeTemplate), + matrixIndices: nodeData.matrixIndices, + }, + }; + } else { + return { + event: "change_node", + nodeMatrixIndices: nodeData.matrixIndices, + node: { + ...getNodeById(nodeData.node, currentSite), + matrixIndices: nodeData.matrixIndices, + }, + }; + } } - } - case "CIRCLE": - const eventAnimation = - Math.random() < 0.4 ? "rip_node" : "throw_node"; + case "UP": + case "DOWN": { + const keyPressToLower = keyPress.toLowerCase(); + const nodeData = findNode( + activeNode.id, + keyPressToLower, + activeNode.matrixIndices!, + level, + currentSite, + gameProgress, + true + ); - const nodeType = activeNode.type; + if (!nodeData) return; - if (activeNode.id === "" || !isNodeVisible(activeNode, gameProgress)) - 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, currentSite) + : unknownNodeTemplate), + matrixIndices: nodeData.matrixIndices, + }, + }; + } else { + return { + event: "change_node", + node: { + ...getNodeById(nodeData.node, currentSite), + matrixIndices: nodeData.matrixIndices, + }, + }; + } + } + case "CIRCLE": + const eventAnimation = + Math.random() < 0.4 ? "rip_node" : "throw_node"; - if (activeNode.upgrade_requirement > ssknLvl) { - const rejectAnimations = [ - "touch_and_scare", - "knock_and_fall", - "knock", - ]; + const nodeType = activeNode.type; - const pickedAnim = - rejectAnimations[ - Math.floor(Math.random() * rejectAnimations.length) + if ( + activeNode.id === "" || + !isNodeVisible(activeNode, gameProgress) + ) + return; + + if (activeNode.upgrade_requirement > ssknLvl) { + const rejectAnimations = [ + "touch_and_scare", + "knock_and_fall", + "knock", ]; - return { - event: pickedAnim, - siteRotY: siteRotY, - }; - } + const pickedAnim = + rejectAnimations[ + Math.floor(Math.random() * rejectAnimations.length) + ]; - switch (nodeType) { - case 0: - case 2: - case 4: - case 3: - case 5: return { - event: `${eventAnimation}_media`, - scene: "media", + event: pickedAnim, siteRotY: siteRotY, - level: level.toString().padStart(2, "0"), }; - case 6: - if (activeNode.node_name.substr(0, 3) === "TaK") { - return { - event: `${eventAnimation}_tak`, - scene: "tak", - siteRotY: siteRotY, - node: activeNode, - }; - } else { + } + + switch (nodeType) { + case 0: + case 2: + case 4: + case 3: + case 5: return { event: `${eventAnimation}_media`, scene: "media", siteRotY: siteRotY, level: level.toString().padStart(2, "0"), }; - } - case 8: - return { - event: `${eventAnimation}_gate`, - scene: "gate", - siteRotY: siteRotY, - node: activeNode, - }; - case 7: - return { - event: `${eventAnimation}_sskn`, - scene: "sskn", - siteRotY: siteRotY, - }; - 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"; + case 6: + if (activeNode.node_name.substr(0, 3) === "TaK") { + return { + event: `${eventAnimation}_tak`, + scene: "tak", + siteRotY: siteRotY, + node: activeNode, + }; + } else { + return { + event: `${eventAnimation}_media`, + scene: "media", + siteRotY: siteRotY, + level: level.toString().padStart(2, "0"), + }; } - })(); + case 8: + return { + event: `${eventAnimation}_gate`, + scene: "gate", + siteRotY: siteRotY, + node: activeNode, + }; + case 7: + return { + event: `${eventAnimation}_sskn`, + scene: "sskn", + siteRotY: siteRotY, + }; + 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, + }; + } + break; + case "L2": + return { event: "toggle_level_selection", level: level }; + case "TRIANGLE": + return { event: "pause_game" }; + case "SPACE": + return { event: "play_with_hair", siteRotY: siteRotY }; + } + break; + case "level_selection": + switch (keyPress) { + case "UP": + if (currentSite === "a") { + if (selectedLevel + 1 <= 22) + return { + event: `level_selection_up`, + selectedLevelIdx: selectedLevel + 1, + }; + } else if (currentSite === "b") { + if (selectedLevel + 1 <= 13) + return { + event: `level_selection_up`, + selectedLevelIdx: selectedLevel + 1, + }; + } + break; + case "DOWN": + if (selectedLevel - 1 >= 1) return { - event: `${eventAnimation}_polytan`, - scene: "polytan", - siteRotY: siteRotY, - node: activeNode, - bodyPart: bodyPart, + event: `level_selection_down`, + selectedLevelIdx: selectedLevel - 1, }; - } - break; - case "L2": - return { event: "toggle_level_selection", level: level }; - case "TRIANGLE": - return { event: "pause_game" }; - case "SPACE": - return { event: "play_with_hair", siteRotY: siteRotY }; - } - break; - case "level_selection": - switch (keyPress) { - case "UP": - if (currentSite === "a") { - if (selectedLevel + 1 <= 22) - return { - event: `level_selection_up`, - selectedLevelIdx: selectedLevel + 1, - }; - } else if (currentSite === "b") { - if (selectedLevel + 1 <= 13) - return { - event: `level_selection_up`, - selectedLevelIdx: selectedLevel + 1, - }; - } - break; - case "DOWN": - if (selectedLevel - 1 >= 1) + break; + case "X": return { - event: `level_selection_down`, - selectedLevelIdx: selectedLevel - 1, + event: "level_selection_back", }; - break; - case "X": + + case "CIRCLE": + if (level === selectedLevel) return; + + const direction = selectedLevel > level ? "up" : "down"; + + const rowIdx = direction === "up" ? 2 : 0; + const nodeData = findNode( + activeNode.id, + direction, + { ...activeNode.matrixIndices!, rowIdx: rowIdx }, + selectedLevel, + currentSite, + gameProgress, + false + ); + + if (nodeData) { + const event = + selectedLevel < level ? "select_level_down" : "select_level_up"; + return { + event: event, + node: { + ...(nodeData.node !== "unknown" + ? getNodeById(nodeData.node, currentSite) + : unknownNodeTemplate), + matrixIndices: nodeData.matrixIndices, + }, + level: selectedLevel.toString().padStart(2, "0"), + }; + } + } + break; + case "pause": + if (showingAbout) return { - event: "level_selection_back", + event: "exit_about", }; - - case "CIRCLE": - if (level === selectedLevel) return; - - const direction = selectedLevel > level ? "up" : "down"; - - const rowIdx = direction === "up" ? 2 : 0; - const nodeData = findNode( - activeNode.id, - direction, - { ...activeNode.matrixIndices!, rowIdx: rowIdx }, - selectedLevel, - currentSite, - gameProgress, - false - ); - - if (nodeData) { - const event = - selectedLevel < level ? "select_level_down" : "select_level_up"; - return { - event: event, - node: { - ...(nodeData.node !== "unknown" - ? getNodeById(nodeData.node, currentSite) - : unknownNodeTemplate), - matrixIndices: nodeData.matrixIndices, - }, - level: selectedLevel.toString().padStart(2, "0"), - }; + else { + switch (keyPress) { + case "UP": + if (pauseMatrixIdx - 1 < 0) break; + return { + event: "pause_up", + pauseMatrixIdx: pauseMatrixIdx - 1, + }; + case "DOWN": + if (pauseMatrixIdx + 1 > 4) break; + return { + event: "pause_down", + pauseMatrixIdx: pauseMatrixIdx + 1, + }; + case "CIRCLE": + if (activePauseComponent === "change") { + return { + event: "display_prompt", + }; + } } - } - break; - case "pause": - switch (keyPress) { - case "UP": - if (pauseMatrixIdx - 1 < 0) break; - return { - event: "pause_up", - pauseMatrixIdx: pauseMatrixIdx - 1, - }; - case "DOWN": - if (pauseMatrixIdx + 1 > 4) break; - return { - event: "pause_down", - pauseMatrixIdx: pauseMatrixIdx + 1, - }; - case "CIRCLE": - return { - event: `pause_${activePauseComponent}_select`, - site: currentSite, - }; - } + } + break; + case "not_found": + return { event: "exit_not_found" }; + } } }; diff --git a/src/core/scene-keypress-handlers/handleMediaKeyPress.ts b/src/core/scene-keypress-handlers/handleMediaKeyPress.ts index 34a8147..aa4d53f 100644 --- a/src/core/scene-keypress-handlers/handleMediaKeyPress.ts +++ b/src/core/scene-keypress-handlers/handleMediaKeyPress.ts @@ -8,6 +8,7 @@ const handleMediaKeyPress = (mediaSceneContext: any) => { rightSideComponentIdx, activeNode, activeSite, + gameProgress, } = mediaSceneContext; const calculateNewRightSide = ( @@ -72,14 +73,14 @@ const handleMediaKeyPress = (mediaSceneContext: any) => { const data = findNodeFromWord( activeMediaComponent, activeNode, - activeSite + activeSite, + gameProgress ); if (data) { return { event: `media_${activeMediaComponent}_select`, ...data }; } else { - // todo in case node isnt unlocked yet - return; + return { event: `word_node_not_found` }; } default: if (activeMediaComponent === "play") { diff --git a/src/core/setters/main/mainSubsceneManager.ts b/src/core/setters/main/mainSubsceneManager.ts index 5e97a26..b77b7c8 100644 --- a/src/core/setters/main/mainSubsceneManager.ts +++ b/src/core/setters/main/mainSubsceneManager.ts @@ -5,9 +5,15 @@ const mainSubsceneManager = (eventState: any) => { const dispatchAction = (eventState: { event: string }) => { switch (eventState.event) { + case "word_node_not_found": + return { + action: () => setMainSubscene("not_found"), + delay: 0, + }; case "level_selection_back": case "select_level_up": case "select_level_down": + case "exit_not_found": return { action: () => setMainSubscene("site"), delay: 0, diff --git a/src/core/setters/main/pause/pauseManager.ts b/src/core/setters/main/pause/pauseManager.ts index 6e1eb42..fe5b59a 100644 --- a/src/core/setters/main/pause/pauseManager.ts +++ b/src/core/setters/main/pause/pauseManager.ts @@ -5,6 +5,7 @@ type PauseManagerProps = { event: string; pauseMatrixIdx: number }; const pauseManager = (eventState: any) => { const setComponentMatrixIdx = useStore.getState().setPauseComponentMatrixIdx; const setExitAnimation = useStore.getState().setPauseExitAnimation; + const setShowingAbout = useStore.getState().setShowingAbout; const dispatchAction = (eventState: PauseManagerProps) => { switch (eventState.event) { @@ -17,6 +18,14 @@ const pauseManager = (eventState: any) => { return { action: () => setExitAnimation(true), }; + case "pause_about_select": + return { + action: () => setShowingAbout(true), + }; + case "exit_about": + return { + action: () => setShowingAbout(false), + }; case "pause_game": return { action: () => setExitAnimation(false) }; } diff --git a/src/core/setters/media/mediaManager.ts b/src/core/setters/media/mediaManager.ts index b7d612c..a23ef72 100644 --- a/src/core/setters/media/mediaManager.ts +++ b/src/core/setters/media/mediaManager.ts @@ -1,5 +1,4 @@ import { useStore } from "../../../store"; -import { useCallback } from "react"; import * as THREE from "three"; const mediaManager = (eventState: any) => { diff --git a/src/core/setters/promptManager.ts b/src/core/setters/promptManager.ts new file mode 100644 index 0000000..323df44 --- /dev/null +++ b/src/core/setters/promptManager.ts @@ -0,0 +1,32 @@ +import { useStore } from "../../store"; + +const promptManager = (eventState: any) => { + const setComponentMatrixIdx = useStore.getState().setPromptComponentMatrixIdx; + const setPromptVisible = useStore.getState().setPromptVisible; + + const dispatchAction = (eventState: { event: string; scene: string }) => { + switch (eventState.event) { + case "display_prompt": { + return { action: () => setPromptVisible(true) }; + } + case "prompt_right": + return { + action: () => setComponentMatrixIdx(1), + }; + case "prompt_left": + return { action: () => setComponentMatrixIdx(0) }; + case "pause_change_select": + return { action: () => setPromptVisible(false) }; + case "exit_prompt": + return { action: () => setPromptVisible(false) }; + } + }; + + const { action } = { ...dispatchAction(eventState) }; + + if (action) { + action(); + } +}; + +export default promptManager; diff --git a/src/core/setters/sceneManager.ts b/src/core/setters/sceneManager.ts index f249270..3a0c557 100644 --- a/src/core/setters/sceneManager.ts +++ b/src/core/setters/sceneManager.ts @@ -52,6 +52,7 @@ const sceneManager = (eventState: any) => { case "media_fstWord_select": case "media_sndWord_select": case "media_thirdWord_select": + case "word_node_not_found": return { action: () => useStore.setState({ currentScene: "main", intro: false }), diff --git a/src/scenes/MainScene.tsx b/src/scenes/MainScene.tsx index 19804d7..4b7e89c 100644 --- a/src/scenes/MainScene.tsx +++ b/src/scenes/MainScene.tsx @@ -13,6 +13,7 @@ import Site from "../components/MainScene/Site"; import Lain from "../components/MainScene/Lain"; import * as THREE from "three"; import { useFrame } from "react-three-fiber"; +import NotFound from "../components/MainScene/NotFound"; const MainScene = () => { const intro = useStore((state) => state.intro); @@ -94,10 +95,13 @@ const MainScene = () => { + - - + + + + diff --git a/src/store.ts b/src/store.ts index a68e100..5196456 100644 --- a/src/store.ts +++ b/src/store.ts @@ -44,6 +44,7 @@ type State = { pauseComponentMatrix: ["load", "about", "change", "save", "exit"]; pauseComponentMatrixIdx: number; pauseExitAnimation: boolean; + showingAbout: boolean; // media/media scene audioAnalyser: undefined | THREE.AudioAnalyser; @@ -98,6 +99,11 @@ type State = { // end scene endMediaPlayedCount: number; + // prompt + promptVisible: boolean; + promptComponentMatrix: ["yes", "no"]; + promptComponentMatrixIdx: 1 | 0; + // save state siteSaveState: { a: { @@ -188,6 +194,7 @@ export const useStore = create( pauseComponentMatrix: ["load", "about", "change", "save", "exit"], pauseComponentMatrixIdx: 2, pauseExitAnimation: false, + showingAbout: false, // media / media scene audioAnalyser: undefined, @@ -249,6 +256,11 @@ export const useStore = create( // end scene endMediaPlayedCount: 0, + // prompt + promptVisible: false, + promptComponentMatrix: ["yes", "no"], + promptComponentMatrixIdx: 1, + // save states for loading the game/changing sites siteSaveState: { a: { @@ -325,6 +337,7 @@ export const useStore = create( set(() => ({ pauseComponentMatrixIdx: to })), setPauseExitAnimation: (to: boolean) => set(() => ({ pauseExitAnimation: to })), + setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })), // media/media scene setters toggleMediaSide: () => @@ -404,6 +417,11 @@ export const useStore = create( })), resetEndMediaPlayedCount: () => set(() => ({ endMediaPlayedCount: 0 })), + // prompt setters + setPromptVisible: (to: boolean) => set(() => ({ promptVisible: to })), + setPromptComponentMatrixIdx: (to: 1 | 0) => + set(() => ({ promptComponentMatrixIdx: to })), + // site state setters setSiteSaveState: ( site: string, @@ -467,6 +485,10 @@ export const getMainSceneContext = () => { activeNode: state.activeNode, level: parseInt(state.activeLevel), ssknLvl: state.ssknLvl, + showingAbout: state.showingAbout, + promptVisible: state.promptVisible, + activePromptComponent: + state.promptComponentMatrix[state.promptComponentMatrixIdx], }; }; @@ -493,5 +515,6 @@ export const getMediaSceneContext = () => { wordPosStateIdx: state.mediaWordPosStateIdx, activeNode: state.activeNode, activeSite: state.activeSite, + gameProgress: state.gameProgress, }; }; diff --git a/src/utils/media-utils.ts b/src/utils/media-utils.ts index 3298282..8a7f5be 100644 --- a/src/utils/media-utils.ts +++ b/src/utils/media-utils.ts @@ -1,15 +1,14 @@ 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 { - NodeDataType, - SiteType, -} from "../components/MainScene/Site"; +import { NodeDataType, SiteType } from "../components/MainScene/Site"; +import { isNodeVisible } from "./node-utils"; export const findNodeFromWord = ( wordLabel: string, activeNode: NodeDataType, - site: "a" | "b" + site: "a" | "b", + gameProgress: any ) => { const labelToIdx = (() => { switch (wordLabel) { @@ -41,7 +40,8 @@ export const findNodeFromWord = ( ) + 1 ] ?? nodesWithSameWords[0]; - //todo check if visible + if (!isNodeVisible(chosenNode, gameProgress)) return; + const pos = chosenNode.id.substr(2); const matrixIndices = Object.entries(node_matrices).flatMap((matrixData) =>