diff --git a/src/game.tsx b/src/game.tsx
index fbdf38c..a801098 100644
--- a/src/game.tsx
+++ b/src/game.tsx
@@ -1,24 +1,22 @@
import React, { useState, useEffect, createContext, useRef } from 'react';
-// Game context definition
const GameContext = createContext();
-// Game state provider
const GameProvider = ({ children }) => {
const [gameState, setGameState] = useState({
screen: 'title', // 'title', 'map', 'location', 'dialogue', 'cooking', 'notebook', 'festival'
currentRegion: null,
- unlockedRegions: ['coastal'], // Start with just the coastal region unlocked
+ unlockedRegions: ['coastal'], // coastal region unlocked at start
reputation: {
coastal: 0,
southwest: 0,
midwest: 0
},
- recipes: [], // Unlocked recipes
- dialogueProgress: {}, // Track NPC conversations
- currentNpc: null, // Current NPC in dialogue
- currentDialogueId: null, // Current dialogue id
- currentRecipe: null, // Current recipe being cooked
+ recipes: [], // unlocked recipes
+ dialogueProgress: {}, // NPC conversations
+ currentNpc: null, // current NPC in dialogue
+ currentDialogueId: null, // current dialogue id
+ currentRecipe: null, // current recipe being cooked
});
const updateGameState = (newState) => {
@@ -32,16 +30,16 @@ const GameProvider = ({ children }) => {
);
};
-// Regional data structure with descriptions, visuals, and unique characteristics
+// regional data structure
const regionData = {
coastal: {
name: "Coastal Town",
fullName: "Bayshore Harbor",
description: "A charming New England coastal town with a rich maritime history. The local cuisine focuses on fresh seafood prepared with simple techniques that highlight natural flavors.",
- background: "coastal-background.jpg", // Placeholder
+ background: "coastal-background.jpg",
backgroundColor: "bg-blue-100",
accent: "blue",
- unlockRequirement: null, // Starting region
+ unlockRequirement: null, // starting region
specialFeature: "Fresh seafood market with daily catches",
culturalNote: "The town's annual Seafood Festival attracts visitors from across the region, celebrating centuries of fishing traditions that have shaped the local identity."
},
@@ -49,7 +47,7 @@ const regionData = {
name: "Southwest City",
fullName: "Mesa Verde",
description: "A vibrant desert city where Mexican, Native American, and frontier traditions blend. The cuisine features bold flavors, chiles, and slow-cooking techniques.",
- background: "southwest-background.jpg", // Placeholder
+ background: "southwest-background.jpg",
backgroundColor: "bg-orange-100",
accent: "orange",
unlockRequirement: { region: "coastal", reputation: 3 },
@@ -60,7 +58,7 @@ const regionData = {
name: "Midwest Suburb",
fullName: "Heartland Hills",
description: "A friendly Midwestern community where comfort food reigns supreme. Hearty casseroles, farm-fresh ingredients, and family recipes passed through generations define the local cuisine.",
- background: "midwest-background.jpg", // Placeholder
+ background: "midwest-background.jpg",
backgroundColor: "bg-green-100",
accent: "green",
unlockRequirement: { region: "southwest", reputation: 3 },
@@ -69,7 +67,7 @@ const regionData = {
}
};
-// Recipe data with cultural context
+// recipe data
const recipeData = {
new_england_clam_chowder: {
name: "New England Clam Chowder",
@@ -154,7 +152,7 @@ const recipeData = {
}
};
-// Dialogue data structure
+// dialogue data structure
const dialogueData = {
coastal: {
chef: {
@@ -210,7 +208,7 @@ const dialogueData = {
{
id: "increase-reputation",
text: "You know, it's refreshing to meet someone who genuinely cares about food traditions. Most tourists just want a quick seafood fix. If you're serious about learning our coastal cuisine, I'd be happy to share more insights and techniques.",
- reputation: 1, // This dialogue increases reputation
+ reputation: 1,
options: [
{ text: "I'd love to learn how to make the chowder.", nextId: "teach" },
{ text: "Thank you! I'll come back later.", nextId: "end" }
@@ -219,7 +217,7 @@ const dialogueData = {
{
id: "teach",
text: "I'd be delighted to teach you our chowder recipe! Let me add it to your notebook. The key is patience - let those flavors develop slowly. When you're ready to try cooking it yourself, just let me know and we can get started right away.",
- recipe: "new_england_clam_chowder", // This dialogue unlocks a recipe
+ recipe: "new_england_clam_chowder",
options: [
{ text: "Let's start cooking now!", nextId: "start_cooking" },
{ text: "I'll check my notebook first.", nextId: "end" }
@@ -228,7 +226,7 @@ const dialogueData = {
{
id: "start_cooking",
text: "Excellent! Let's head to the kitchen and get started on that chowder. I'll guide you through each step.",
- cooking: true, // This triggers the cooking minigame
+ cooking: true,
options: [
{ text: "Let's do it!", nextId: "end" }
]
@@ -374,7 +372,6 @@ const dialogueData = {
{ text: "I'd like to learn a recipe.", nextId: "teach" }
]
},
- // More dialogue options would be added here
]
},
historian: {
@@ -391,7 +388,6 @@ const dialogueData = {
{ text: "Nice to meet you. I'll explore more later.", nextId: "end" }
]
},
- // More dialogue options would be added here
]
},
vendor: {
@@ -408,7 +404,6 @@ const dialogueData = {
{ text: "Just browsing, thanks.", nextId: "end" }
]
},
- // More dialogue options would be added here
]
}
},
@@ -427,7 +422,6 @@ const dialogueData = {
{ text: "I'd like to learn how to make one.", nextId: "teach" }
]
},
- // More dialogue options would be added here
]
},
historian: {
@@ -444,7 +438,6 @@ const dialogueData = {
{ text: "Nice to meet you. I'll chat more later.", nextId: "end" }
]
},
- // More dialogue options would be added here
]
},
vendor: {
@@ -461,13 +454,12 @@ const dialogueData = {
{ text: "Just looking around for now, thanks.", nextId: "end" }
]
},
- // More dialogue options would be added here
]
}
}
};
-// Cooking challenges for each recipe
+// cooking challenges
const cookingChallenges = {
new_england_clam_chowder: [
{ action: "chop", key: "C", description: "Chop the vegetables", duration: 4000 },
@@ -492,7 +484,7 @@ const cookingChallenges = {
]
};
-// Title Screen Component
+// title screen component
const TitleScreen = () => {
const { updateGameState } = React.useContext(GameContext);
@@ -535,19 +527,19 @@ const TitleScreen = () => {
);
};
-// Map Screen Component
+// map screen component
const MapScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
const [selectedRegion, setSelectedRegion] = useState(null);
- // Handle region selection
+ // handle region selection
const handleRegionSelect = (regionId) => {
if (gameState.unlockedRegions.includes(regionId)) {
setSelectedRegion(regionId);
}
};
- // Handle travel to region
+ // handle travel to region
const handleTravelToRegion = () => {
if (selectedRegion) {
updateGameState({
@@ -558,7 +550,7 @@ const MapScreen = () => {
}
};
- // Get unlock status text
+ // get unlock status text
const getUnlockStatus = (regionId) => {
const region = regionData[regionId];
@@ -647,7 +639,7 @@ const MapScreen = () => {
{/* Region background image placeholder */}
- [Image of {regionData[selectedRegion].fullName}]
+ [{regionData[selectedRegion].fullName} Image]
@@ -741,16 +733,16 @@ const MapScreen = () => {
);
};
-// Location Screen Component
+// location screen component
const LocationScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
const region = regionData[gameState.currentRegion];
- // Handle NPC click
+ // handle NPC click
const handleNpcClick = (npcType) => {
const npcData = dialogueData[gameState.currentRegion][npcType];
- // Check if we have dialogueProgress for this NPC, if not start with intro
+ // check if we have dialogueProgress for this NPC, if not start with intro
const dialogueId = gameState.dialogueProgress[`${gameState.currentRegion}-${npcType}`] || 'intro';
updateGameState({
@@ -855,16 +847,16 @@ const LocationScreen = () => {
);
};
-// Dialogue Screen Component
+// dialogue screen component
const DialogueScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
- // Get current NPC and dialogue data
+ // get current NPC and dialogue data
const npcData = dialogueData[gameState.currentRegion][gameState.currentNpc];
const currentDialogue = npcData.dialogues.find(d => d.id === gameState.currentDialogueId);
const handleOptionClick = (option) => {
- // If there's no next dialogue, return to location screen
+ // no next dialogue, return to location screen
if (!option.nextId) {
updateGameState({
screen: 'location',
@@ -874,32 +866,32 @@ const DialogueScreen = () => {
return;
}
- // Find the next dialogue
+ // find the next dialogue
const nextDialogue = npcData.dialogues.find(d => d.id === option.nextId);
- // Update dialogue progress for this NPC
+ // update dialogue progress for this NPC
const newDialogueProgress = {
...gameState.dialogueProgress,
[`${gameState.currentRegion}-${gameState.currentNpc}`]: option.nextId
};
- // Check if the next dialogue awards reputation
+ // check if the next dialogue awards reputation
let newReputation = { ...gameState.reputation };
if (nextDialogue.reputation) {
newReputation[gameState.currentRegion] += nextDialogue.reputation;
- // Cap reputation at 5
+ // cap reputation at 5
if (newReputation[gameState.currentRegion] > 5) {
newReputation[gameState.currentRegion] = 5;
}
}
- // Check if the next dialogue unlocks a recipe
+ // check if the next dialogue unlocks recipe
let newRecipes = [...gameState.recipes];
if (nextDialogue.recipe && !newRecipes.includes(nextDialogue.recipe)) {
newRecipes.push(nextDialogue.recipe);
}
- // Update game state
+ // update game state
updateGameState({
currentDialogueId: option.nextId,
dialogueProgress: newDialogueProgress,
@@ -907,7 +899,7 @@ const DialogueScreen = () => {
recipes: newRecipes
});
- // If dialogue triggers cooking, go to cooking screen
+ // if dialogue triggers cooking, go to cooking screen
if (nextDialogue.cooking) {
setTimeout(() => {
updateGameState({
@@ -915,7 +907,7 @@ const DialogueScreen = () => {
currentNpc: null,
currentDialogueId: null
});
- }, 1500); // Give player time to read dialogue before transition
+ }, 1500); // give player time to read dialogue before transition
}
};
@@ -972,15 +964,15 @@ const NotebookScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
const [selectedRecipe, setSelectedRecipe] = useState(null);
- // Get all unlocked recipes
+ // get all unlocked recipes
const unlockedRecipes = gameState.recipes.map(recipeId => recipeData[recipeId]);
- // Handle recipe selection
+ // handle recipe selection
const handleRecipeClick = (recipeId) => {
setSelectedRecipe(recipeId);
};
- // Handle cooking button
+ // handle cooking button
const handleCook = () => {
updateGameState({
screen: 'cooking',
@@ -1093,14 +1085,13 @@ const NotebookScreen = () => {
);
};
-// Cooking Screen Component
+// cooking screen component
const CookingScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
- // If no specific recipe is selected, default to the first unlocked recipe
const currentRecipe = gameState.currentRecipe || (gameState.recipes.length > 0 ? gameState.recipes[0] : 'new_england_clam_chowder');
- // States for the cooking minigame
+ // states for the cooking minigame
const [gamePhase, setGamePhase] = useState('intro'); // 'intro', 'playing', 'result'
const [currentStep, setCurrentStep] = useState(0);
const [score, setScore] = useState(0);
@@ -1109,14 +1100,14 @@ const CookingScreen = () => {
const [timeLeft, setTimeLeft] = useState(0);
const [result, setResult] = useState(null); // 'perfect', 'good', 'needsWork'
- // Timer ref
+ // timer ref
const timerRef = useRef(null);
- // Recipe data
+ // recipe data
const recipe = recipeData[currentRecipe];
const challenges = cookingChallenges[currentRecipe];
- // Start the game
+ // start the game
const startGame = () => {
setGamePhase('playing');
setCurrentStep(0);
@@ -1124,10 +1115,10 @@ const CookingScreen = () => {
nextStep(0);
};
- // Next cooking step
+ // next cooking step
const nextStep = (stepIndex) => {
if (stepIndex >= challenges.length) {
- // Game complete, calculate result
+ // game complete, calculate result
const finalScore = score;
let finalResult;
@@ -1142,24 +1133,24 @@ const CookingScreen = () => {
setResult(finalResult);
setGamePhase('result');
- // Increase reputation based on result
+ // increase reputation based on result
const reputationGain = finalResult === 'perfect' ? 2 : (finalResult === 'good' ? 1 : 0);
const newReputation = { ...gameState.reputation };
newReputation[gameState.currentRegion] += reputationGain;
- // Cap reputation at 5
+ // cap reputation at 5
if (newReputation[gameState.currentRegion] > 5) {
newReputation[gameState.currentRegion] = 5;
}
updateGameState({ reputation: newReputation });
- // Check if this unlocks the next region
+ // check if this unlocks the next region
if (newReputation[gameState.currentRegion] >= 3 &&
gameState.currentRegion === 'coastal' &&
!gameState.unlockedRegions.includes('southwest')) {
- // Unlock southwest region
+ // southwest region
const newUnlockedRegions = [...gameState.unlockedRegions, 'southwest'];
updateGameState({ unlockedRegions: newUnlockedRegions });
@@ -1167,7 +1158,7 @@ const CookingScreen = () => {
gameState.currentRegion === 'southwest' &&
!gameState.unlockedRegions.includes('midwest')) {
- // Unlock midwest region
+ // midwest region
const newUnlockedRegions = [...gameState.unlockedRegions, 'midwest'];
updateGameState({ unlockedRegions: newUnlockedRegions });
}
@@ -1175,21 +1166,21 @@ const CookingScreen = () => {
return;
}
- // Set up the next step
+ // set up the next step
setCurrentStep(stepIndex);
setShowKey(false);
setKeyPressed(false);
- // Start the timer for this step
+ // start the timer for this step
const duration = challenges[stepIndex].duration;
setTimeLeft(duration);
- // Show the key after a random delay
+ // show the key after a random delay
const keyDelay = Math.floor(Math.random() * (duration * 0.6)) + (duration * 0.2);
setTimeout(() => {
setShowKey(true);
- // Hide the key after a short time if not pressed
+ // hide the key after a short time if not pressed
setTimeout(() => {
if (!keyPressed) {
setShowKey(false);
@@ -1197,41 +1188,40 @@ const CookingScreen = () => {
}, 1200);
}, keyDelay);
- // Set a timer for the entire step duration
+ // set a timer for the entire step duration
timerRef.current = setTimeout(() => {
- // Move to next step regardless of success
+ // move to next step regardless of success -- // TODO: broken?
nextStep(stepIndex + 1);
}, duration);
};
- // Handle key press
+ // handle key press
const handleKeyPress = (keyCode) => {
- // Only process if we're showing a key and in playing phase
+
if (showKey && gamePhase === 'playing' && !keyPressed) {
const expectedKey = challenges[currentStep].key;
- // Check if the correct key was pressed
+ // check if the correct key was pressed
if (keyCode.toUpperCase() === expectedKey) {
- // Correct key! Add to score
+
+ // correct
setScore(score + 1);
setKeyPressed(true);
setShowKey(false);
- // Clear the current timer
clearTimeout(timerRef.current);
- // Move to next step after a short delay
setTimeout(() => {
nextStep(currentStep + 1);
}, 800);
} else {
- // Wrong key, just hide the prompt
+ // wrong
setShowKey(false);
}
}
};
- // Set up keyboard listener
+ // set up keyboard listener
useEffect(() => {
const keyListener = (event) => {
handleKeyPress(event.key);
@@ -1245,7 +1235,7 @@ const CookingScreen = () => {
};
}, [currentStep, showKey, gamePhase, keyPressed]);
- // Timer effect
+ // timer effect
useEffect(() => {
if (gamePhase === 'playing' && timeLeft > 0) {
const interval = setInterval(() => {
@@ -1256,7 +1246,7 @@ const CookingScreen = () => {
}
}, [gamePhase, timeLeft]);
- // Render the appropriate game phase
+ // render the appropriate game phase
const renderGameContent = () => {
switch(gamePhase) {
case 'intro':
@@ -1329,7 +1319,7 @@ const CookingScreen = () => {
const reputationGain = result === 'perfect' ? 2 : (result === 'good' ? 1 : 0);
const regionName = gameState.currentRegion.charAt(0).toUpperCase() + gameState.currentRegion.slice(1);
- // Check if we unlocked a new region
+ // unlocked a new region?
const unlockedNewRegion =
(gameState.currentRegion === 'coastal' && gameState.reputation.coastal >= 3 && !gameState.unlockedRegions.includes('southwest')) ||
(gameState.currentRegion === 'southwest' && gameState.reputation.southwest >= 3 && !gameState.unlockedRegions.includes('midwest'));
@@ -1343,7 +1333,7 @@ const CookingScreen = () => {
{/* Result image placeholder */}
- [Image of {result} {recipe.name}]
+ [{result} {recipe.name} Image]
@@ -1423,15 +1413,15 @@ const CookingScreen = () => {
);
};
-// Game completion check
+// game completion check
const checkGameCompletion = (gameState) => {
- // Check if all regions have at least 4 reputation
+ // check if all regions have at least 4 reputation
const allRegionsHighRep =
gameState.unlockedRegions.includes('coastal') && gameState.reputation.coastal >= 4 &&
gameState.unlockedRegions.includes('southwest') && gameState.reputation.southwest >= 4 &&
gameState.unlockedRegions.includes('midwest') && gameState.reputation.midwest >= 4;
- // Check if at least one recipe from each region is known
+ // check if at least one recipe from each region is known
const hasCoastalRecipe = gameState.recipes.some(recipe => recipeData[recipe].region === 'coastal');
const hasSouthwestRecipe = gameState.recipes.some(recipe => recipeData[recipe].region === 'southwest');
const hasMidwestRecipe = gameState.recipes.some(recipe => recipeData[recipe].region === 'midwest');
@@ -1441,12 +1431,12 @@ const checkGameCompletion = (gameState) => {
return allRegionsHighRep && allRegionRecipes;
};
-// Final Festival Component
+// final festival component
const FinalFestivalScreen = () => {
const { gameState, updateGameState } = React.useContext(GameContext);
const [festivalPhase, setFestivalPhase] = useState('intro');
- // Total reputation across all regions
+ // total reputation across all regions
const totalReputation =
gameState.reputation.coastal +
gameState.reputation.southwest +
@@ -1455,7 +1445,7 @@ const FinalFestivalScreen = () => {
const maxReputation = 15; // 5 per region
const reputationPercentage = Math.round((totalReputation / maxReputation) * 100);
- // Festival outcome levels
+ // festival outcome levels
const getFestivalOutcome = () => {
if (reputationPercentage >= 90) return "Outstanding";
if (reputationPercentage >= 75) return "Excellent";
@@ -1463,9 +1453,9 @@ const FinalFestivalScreen = () => {
return "Modest";
};
- // Handle return to title
+ // handle return to title
const handleReturnToTitle = () => {
- // Reset game state for a new game
+ // reset game state for a new game
updateGameState({
screen: 'title',
currentRegion: null,
@@ -1482,7 +1472,7 @@ const FinalFestivalScreen = () => {
});
};
- // Render the appropriate festival phase
+ // render the appropriate festival phase
const renderFestivalContent = () => {
switch(festivalPhase) {
case 'intro':
@@ -1653,19 +1643,19 @@ const FinalFestivalScreen = () => {
);
};
-// Enhanced Map Screen that checks for game completion
+// enhanced Map Screen that checks for game completion
const EnhancedMapScreen = (props) => {
const { gameState, updateGameState } = React.useContext(GameContext);
- // Check for game completion when entering the map screen
+ // check for game completion when entering the map screen
useEffect(() => {
if (checkGameCompletion(gameState)) {
- // If conditions are met, show the final festival
+ // if conditions are met, show the final festival
updateGameState({ screen: 'festival' });
}
}, []);
- // Render the original MapScreen
+ // render the original MapScreen
return ;
};
@@ -1673,7 +1663,7 @@ const EnhancedMapScreen = (props) => {
const FoodTruckFrontier = () => {
const { gameState } = React.useContext(GameContext);
- // Render the appropriate screen based on game state
+ // render the appropriate screen based on game state
const renderScreen = () => {
switch (gameState.screen) {
case 'title':
@@ -1702,7 +1692,7 @@ const FoodTruckFrontier = () => {
);
};
-// Export the wrapped game with context
+// export wrapped game + context
export default function Game() {
return (