179
src/App.tsx
Normal file
179
src/App.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { GameShellRuntime } from './components/game-shell/GameShellRuntime.tsx';
|
||||
import { activateRosterCompanion, benchActiveCompanion } from './data/companionRoster';
|
||||
import { syncGameStatePlayTime } from './data/runtimeStats';
|
||||
import { useBackgroundMusic } from './hooks/useBackgroundMusic';
|
||||
import { useCombatFlow } from './hooks/useCombatFlow';
|
||||
import { useGameFlow } from './hooks/useGameFlow';
|
||||
import { useGamePersistence } from './hooks/useGamePersistence';
|
||||
import { useGameSettings } from './hooks/useGameSettings';
|
||||
import { useNpcInteractionFlow } from './hooks/useNpcInteractionFlow';
|
||||
import { useStoryGeneration } from './hooks/useStoryGeneration';
|
||||
|
||||
export default function App() {
|
||||
const {
|
||||
gameState,
|
||||
setGameState,
|
||||
bottomTab,
|
||||
setBottomTab,
|
||||
isMapOpen,
|
||||
setIsMapOpen,
|
||||
resetGame,
|
||||
handleWorldSelect: selectWorld,
|
||||
handleBackToWorldSelect: backToWorldSelect,
|
||||
handleCharacterSelect: selectCharacter,
|
||||
} = useGameFlow();
|
||||
|
||||
const combatFlow = useCombatFlow({
|
||||
setGameState,
|
||||
});
|
||||
|
||||
const storyFlow = useStoryGeneration({
|
||||
gameState,
|
||||
setGameState,
|
||||
buildResolvedChoiceState: combatFlow.buildResolvedChoiceState,
|
||||
playResolvedChoice: combatFlow.playResolvedChoice,
|
||||
});
|
||||
|
||||
const { companionRenderStates } = useNpcInteractionFlow(gameState);
|
||||
const settings = useGameSettings();
|
||||
|
||||
const persistence = useGamePersistence({
|
||||
gameState,
|
||||
bottomTab,
|
||||
currentStory: storyFlow.currentStory,
|
||||
isLoading: storyFlow.isLoading,
|
||||
setGameState,
|
||||
setBottomTab,
|
||||
hydrateStoryState: storyFlow.hydrateStoryState,
|
||||
resetStoryState: storyFlow.resetStoryState,
|
||||
});
|
||||
|
||||
useBackgroundMusic({
|
||||
active: Boolean(gameState.playerCharacter && gameState.currentScene === 'Story'),
|
||||
volume: settings.musicVolume,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!gameState.playerCharacter || gameState.currentScene !== 'Story') {
|
||||
return;
|
||||
}
|
||||
|
||||
const intervalId = window.setInterval(() => {
|
||||
setGameState(currentState => {
|
||||
if (!currentState.playerCharacter || currentState.currentScene !== 'Story') {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
return syncGameStatePlayTime(currentState);
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
return () => window.clearInterval(intervalId);
|
||||
}, [gameState.currentScene, gameState.playerCharacter, setGameState]);
|
||||
|
||||
const handleWorldSelect = (
|
||||
worldType: Parameters<typeof selectWorld>[0],
|
||||
customWorldProfile?: Parameters<typeof selectWorld>[1],
|
||||
) => {
|
||||
storyFlow.resetStoryState();
|
||||
selectWorld(worldType, customWorldProfile);
|
||||
};
|
||||
|
||||
const handleCharacterSelect = (
|
||||
character: Parameters<typeof selectCharacter>[0],
|
||||
) => {
|
||||
storyFlow.resetStoryState();
|
||||
selectCharacter(character);
|
||||
};
|
||||
|
||||
const handleBackToWorldSelect = () => {
|
||||
storyFlow.resetStoryState();
|
||||
backToWorldSelect();
|
||||
};
|
||||
|
||||
const handleContinueGame = () => {
|
||||
persistence.continueSavedGame();
|
||||
};
|
||||
|
||||
const handleStartNewGame = () => {
|
||||
persistence.clearSavedGame();
|
||||
storyFlow.resetStoryState();
|
||||
resetGame();
|
||||
};
|
||||
|
||||
const handleSaveAndExit = () => {
|
||||
const syncedGameState = syncGameStatePlayTime(gameState);
|
||||
persistence.saveCurrentGame({
|
||||
gameState: syncedGameState,
|
||||
bottomTab,
|
||||
currentStory: storyFlow.currentStory,
|
||||
});
|
||||
storyFlow.resetStoryState();
|
||||
resetGame();
|
||||
};
|
||||
|
||||
const handleBenchCompanion = (npcId: string) => {
|
||||
setGameState(currentState => benchActiveCompanion(currentState, npcId));
|
||||
};
|
||||
|
||||
const handleActivateRosterCompanion = (npcId: string, swapNpcId?: string | null) => {
|
||||
setGameState(currentState => activateRosterCompanion(currentState, npcId, swapNpcId));
|
||||
};
|
||||
|
||||
const gameShellSession = {
|
||||
gameState,
|
||||
currentStory: storyFlow.currentStory,
|
||||
isLoading: storyFlow.isLoading,
|
||||
aiError: storyFlow.aiError,
|
||||
bottomTab,
|
||||
setBottomTab,
|
||||
isMapOpen,
|
||||
setIsMapOpen,
|
||||
};
|
||||
|
||||
const gameShellStory = {
|
||||
displayedOptions: storyFlow.displayedOptions,
|
||||
canRefreshOptions: storyFlow.canRefreshOptions,
|
||||
handleRefreshOptions: storyFlow.handleRefreshOptions,
|
||||
handleChoice: storyFlow.handleChoice,
|
||||
handleMapTravelToScene: storyFlow.travelToSceneFromMap,
|
||||
npcUi: storyFlow.npcUi,
|
||||
characterChatUi: storyFlow.characterChatUi,
|
||||
inventoryUi: storyFlow.inventoryUi,
|
||||
battleRewardUi: storyFlow.battleRewardUi,
|
||||
questUi: storyFlow.questUi,
|
||||
};
|
||||
|
||||
const gameShellEntry = {
|
||||
hasSavedGame: persistence.hasSavedGame,
|
||||
handleContinueGame,
|
||||
handleStartNewGame,
|
||||
handleSaveAndExit,
|
||||
handleWorldSelect,
|
||||
handleBackToWorldSelect,
|
||||
handleCharacterSelect,
|
||||
};
|
||||
|
||||
const gameShellCompanions = {
|
||||
companionRenderStates,
|
||||
onBenchCompanion: handleBenchCompanion,
|
||||
onActivateRosterCompanion: handleActivateRosterCompanion,
|
||||
};
|
||||
|
||||
const gameShellAudio = {
|
||||
musicVolume: settings.musicVolume,
|
||||
onMusicVolumeChange: settings.setMusicVolume,
|
||||
};
|
||||
|
||||
return (
|
||||
<GameShellRuntime
|
||||
session={gameShellSession}
|
||||
story={gameShellStory}
|
||||
entry={gameShellEntry}
|
||||
companions={gameShellCompanions}
|
||||
audio={gameShellAudio}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user