Files
Genarrative/src/App.tsx

181 lines
5.1 KiB
TypeScript

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,
handleCustomWorldSelect: selectCustomWorld,
handleBackToWorldSelect: backToWorldSelect,
handleCharacterSelect: selectCharacter,
} = useGameFlow();
const combatFlow = useCombatFlow({
setGameState,
});
const storyFlow = useStoryGeneration({
gameState,
setGameState,
buildResolvedChoiceState: combatFlow.buildResolvedChoiceState,
playResolvedChoice: combatFlow.playResolvedChoice,
});
const { companionRenderStates, buildCompanionRenderStates } = 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 handleCustomWorldSelect = (
customWorldProfile: Parameters<typeof selectCustomWorld>[0],
) => {
storyFlow.resetStoryState();
selectCustomWorld(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,
goalUi: storyFlow.goalUi,
};
const gameShellEntry = {
hasSavedGame: persistence.hasSavedGame,
handleContinueGame,
handleStartNewGame,
handleSaveAndExit,
handleCustomWorldSelect,
handleBackToWorldSelect,
handleCharacterSelect,
};
const gameShellCompanions = {
companionRenderStates,
buildCompanionRenderStates,
onBenchCompanion: handleBenchCompanion,
onActivateRosterCompanion: handleActivateRosterCompanion,
};
const gameShellAudio = {
musicVolume: settings.musicVolume,
onMusicVolumeChange: settings.setMusicVolume,
};
return (
<GameShellRuntime
session={gameShellSession}
story={gameShellStory}
entry={gameShellEntry}
companions={gameShellCompanions}
audio={gameShellAudio}
/>
);
}