Skip to content

Commit

Permalink
feat: tutorial episode II: the great rework
Browse files Browse the repository at this point in the history
  • Loading branch information
Cygnusfear committed Oct 19, 2023
1 parent 1b20512 commit 9943e6b
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 60 deletions.
46 changes: 22 additions & 24 deletions packages/client/src/components/ui/tutorialModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
completeTutorial,
tutorialSteps,
} from "@/game/data/tutorial";
import { getState, useStore } from "@/game/store";
import { getState } from "@/game/store";
import { useState, useEffect } from "react";
import { useSpring, animated, config } from "@react-spring/web";

Expand Down Expand Up @@ -77,36 +77,34 @@ function TutorialModal({
}

const Tutorial = () => {
const {
player: { playerData },
} = useStore();
const [currentTutorial, setCurrentTutorial] = useState<
TutorialStep | undefined
>(undefined);
const [screenIndex, setScreenIndex] = useState<number>(0);

useEffect(() => {
const playerData = getState().player.playerData;
console.log(currentTutorial, playerData.activeTutorials);
if (playerData.activeTutorials.length > 0) {
if (
currentTutorial === undefined ||
(currentTutorial &&
playerData.activeTutorials[0] !== currentTutorial?.name)
) {
const tutorialStep = tutorialSteps.find(
(step) => step.name === playerData.activeTutorials[0]
);
setCurrentTutorial(tutorialStep);
setScreenIndex(0);
const setTutorial = () => {
const playerData = getState().player.playerData;
if (playerData.activeTutorials.length > 0) {
if (playerData.activeTutorials[0]) {
const tutorialStep = tutorialSteps.find(
(step) => step.name === playerData.activeTutorials[0]
);
setCurrentTutorial((prev) => {
if (prev != tutorialStep) {
setScreenIndex(0);
return tutorialStep;
}
});
}
}
}
}, [
currentTutorial,
playerData,
playerData.activeTutorials,
playerData.finishedTutorials,
]);
};

document.addEventListener("activeTutorial", setTutorial);
return () => {
document.removeEventListener("activeTutorial", setTutorial);
};
}, []);

return (
<>
Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/game/data/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,7 @@ export const savePlayer = async (playerData: PlayerData, verbose = false) => {
};

export const hasFacility = (playerData: PlayerData, facilityId: number) => {
return playerData.facilities.some((f) => f.type.entityTypeId === facilityId);
return !!playerData.facilities.find(
(f) => f.type.entityTypeId === facilityId
);
};
39 changes: 22 additions & 17 deletions packages/client/src/game/data/tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,37 @@ export const evaluateTutorials = async () => {
for (const t of player.activeTutorials) {
const activeTutorial = tutorialSteps.find((step) => step.name === t);
if (activeTutorial?.completedCondition(player)) {
activeTutorials = activeTutorials.filter(
(t) => t !== activeTutorial.name
);
activeTutorials = [];
if (!finishedTutorials.includes(activeTutorial.name)) {
finishedTutorials.push(activeTutorial.name);
}
}
}
for (const t of tutorialSteps.filter(
(t) => !finishedTutorials.includes(t.name)
)) {
const activeTutorial = tutorialSteps.find((step) => step.name === t.name);
if (
activeTutorial?.startCondition(player) &&
!activeTutorials.includes(t.name) &&
activeTutorials.length < 1
) {
activeTutorials.push(activeTutorial.name);
if (activeTutorials.length < 1) {
for (const t of tutorialSteps.filter(
(t) => !finishedTutorials.includes(t.name)
)) {
const availabletutorial = t;
if (availabletutorial.completedCondition(player)) {
finishedTutorials.push(availabletutorial.name);
continue;
} else if (
availabletutorial?.startCondition(player) &&
!activeTutorials.includes(t.name)
) {
activeTutorials.push(availabletutorial.name);
if (activeTutorials.length > 0) {
const event = new Event("activeTutorial");
document.dispatchEvent(event);
}
}
}
}
getState().player.setPlayerData({
...player,
activeTutorials,
finishedTutorials,
});
console.log(activeTutorials, finishedTutorials, player);
};

export const completeTutorial = async (tutorialName: string) => {
Expand Down Expand Up @@ -149,7 +154,7 @@ export const tutorialSteps = [
{
name: "A place to put your stuff",
text: `With the basic infrastructure in place, it's time to craft a space of warmth, comfort, and belonging. The Residence stands as a beacon of hope and rest for the citizens of your city. As you construct these abodes, you're not just building structures; you're crafting homes, stories, and memories. Place them with care, and watch as life, laughter, and dreams fill the spaces within.<br/><br/>
${EntityData.facilities.residence.description}`,
${EntityData.facilities.residence.description}<br/><br/><b>Build a residence for your citizens</b>`,
entity: EntityData.facilities.residence,
image: "house.webp",
},
Expand All @@ -164,8 +169,8 @@ export const tutorialSteps = [
EntityData.facilities.residence,
EntityData.facilities.scaffold,
],
completedCondition: () => {
return true;
completedCondition: (player: PlayerData) => {
return hasFacility(player, EntityData.facilities.residence.entityTypeId);
},
startCondition: (player: PlayerData) => {
return hasFacility(player, EntityData.facilities.residence.entityTypeId);
Expand Down
14 changes: 2 additions & 12 deletions packages/client/src/game/gameRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import GameUI from "@/components/ui/gameUI";
import Importer from "./utils/importer";
import GameLoop from "./systems/gameLoop";
import { Stats } from "@react-three/drei";
import { useEffect, useMemo, useState } from "react";
import { useMemo, useState } from "react";
import { useMUD } from "@/useMUD";
import { initializePlayer, savePlayer } from "./data/player";
import { initializePlayer } from "./data/player";
import { getState } from "./store";
import { evaluateTutorials } from "./data/tutorial";

function GameRoot() {
const [showFps, setShowFps] = useState(false);
Expand All @@ -33,15 +32,6 @@ function GameRoot() {
Object.assign(window, { showFps: toggleFPS });
}, [showFps]);

useEffect(() => {
const interval = setInterval(() => {
savePlayer(getState().player.playerData);
evaluateTutorials();
}, 5000);

return () => clearInterval(interval);
}, []);

return (
<>
<Canvas
Expand Down
10 changes: 6 additions & 4 deletions packages/client/src/game/systems/constructionSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,12 @@ const buildFacility = ({
}
addEntity(newFacility);
if (owner == getState().player.playerData?.address) {
getState().player.setPlayerData({
...getState().player.playerData!,
facilities: [...getState().player.playerData!.facilities, newFacility],
});
if (!getState().player.playerData?.facilities.includes(newFacility)) {
getState().player.setPlayerData({
...getState().player.playerData!,
facilities: [...getState().player.playerData!.facilities, newFacility],
});
}
}
propagateGravity();
};
Expand Down
20 changes: 18 additions & 2 deletions packages/client/src/game/systems/gameLoop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Has, getComponentValueStrict } from "@latticexyz/recs";
import { getState } from "../store";
import { useOnce } from "@/lib/useOnce";
import { createNewPlayerData, savePlayer } from "../data/player";
import { evaluateTutorials, tutorialSteps } from "../data/tutorial";

let loaded = false;

Expand Down Expand Up @@ -135,8 +136,8 @@ function GameLoop() {

useMemo(() => {
// Debug for hiding the loading screen on new world
const event = new Event("gameLoaded");
document.dispatchEvent(event);
// const event = new Event("gameLoaded");
// document.dispatchEvent(event);

// we're going to check which entities don't exist yet and build new ones:
// TODO: GameLoaded logic breaks when the map has zero entities [bug]
Expand Down Expand Up @@ -168,6 +169,21 @@ function GameLoop() {
}
}, [facilities]);

useEffect(() => {
const interval = setInterval(() => {
savePlayer(getState().player.playerData);
if (
loaded &&
getState().player.playerData.finishedTutorials.length <
tutorialSteps.length
) {
evaluateTutorials();
}
}, 5000);

return () => clearInterval(interval);
}, []);

return <></>;
}

Expand Down

0 comments on commit 9943e6b

Please sign in to comment.