This commit is contained in:
2026-04-10 15:37:02 +08:00
parent 161cd32277
commit f19e482c8f
233 changed files with 43987 additions and 5127 deletions

View File

@@ -1,97 +1,73 @@
import { useCallback } from 'react';
import { addInventoryItems } from '../data/npcInteractions';
import {
buildTreasureEncounterStoryMoment,
buildTreasureResultText,
resolveTreasureReward,
} from '../data/treasureInteractions';
import { appendStoryEngineCarrierMemory } from '../services/storyEngine/echoMemory';
import { Character, Encounter, GameState, StoryMoment, StoryOption } from '../types';
import type {CommitGeneratedState} from './generatedState';
type ProgressTreasureQuest = (state: GameState, sceneId: string | null) => GameState;
export function isTreasureEncounter(encounter: GameState['currentEncounter']): encounter is Encounter {
return Boolean(encounter?.kind === 'treasure');
}
export function buildTreasureStory(
state: GameState,
_character: Character,
encounter: Encounter,
overrideText?: string,
): StoryMoment {
return buildTreasureEncounterStoryMoment({
state,
encounter,
overrideText,
});
}
import { resolveServerRuntimeChoice } from './story/runtimeStoryCoordinator';
import { Character, GameState, StoryMoment, StoryOption } from '../types';
export function useTreasureFlow({
gameState,
commitGeneratedState,
progressTreasureQuest,
runtime,
}: {
gameState: GameState;
commitGeneratedState: CommitGeneratedState;
progressTreasureQuest: ProgressTreasureQuest;
runtime: {
currentStory: StoryMoment | null;
setGameState: (state: GameState) => void;
setCurrentStory: (story: StoryMoment) => void;
setAiError: (message: string | null) => void;
setIsLoading: (loading: boolean) => void;
buildFallbackStoryForState: (
state: GameState,
character: Character,
fallbackText?: string,
) => StoryMoment;
};
}) {
const handleTreasureInteraction = useCallback((option: StoryOption) => {
if (!gameState.playerCharacter || option.interaction?.kind !== 'treasure' || gameState.currentEncounter?.kind !== 'treasure') {
return false;
}
const handleTreasureInteraction = useCallback(
async (option: StoryOption) => {
if (
!gameState.playerCharacter ||
option.interaction?.kind !== 'treasure' ||
gameState.currentEncounter?.kind !== 'treasure'
) {
return false;
}
const encounter = gameState.currentEncounter;
const action = option.interaction.action;
const reward = action === 'leave'
? null
: resolveTreasureReward(gameState, encounter, action);
const progressedState = action === 'leave'
? gameState
: progressTreasureQuest(gameState, gameState.currentScenePreset?.id ?? null);
runtime.setAiError(null);
runtime.setIsLoading(true);
const nextState: GameState = appendStoryEngineCarrierMemory({
...progressedState,
currentEncounter: null,
npcInteractionActive: false,
sceneHostileNpcs: [],
playerX: 0,
playerFacing: 'right' as const,
animationState: progressedState.animationState,
scrollWorld: false,
inBattle: false,
playerHp: reward
? Math.min(progressedState.playerMaxHp, progressedState.playerHp + reward.hp)
: progressedState.playerHp,
playerMana: reward
? Math.min(progressedState.playerMaxMana, progressedState.playerMana + reward.mana)
: progressedState.playerMana,
playerCurrency: reward
? progressedState.playerCurrency + reward.currency
: progressedState.playerCurrency,
playerInventory: reward
? addInventoryItems(progressedState.playerInventory, reward.items)
: progressedState.playerInventory,
currentBattleNpcId: null,
currentNpcBattleMode: null,
currentNpcBattleOutcome: null,
sparReturnEncounter: null,
sparPlayerHpBefore: null,
sparPlayerMaxHpBefore: null,
sparStoryHistoryBefore: null,
}, reward?.items ?? []);
try {
const { hydratedSnapshot, nextStory } =
await resolveServerRuntimeChoice({
gameState,
currentStory: runtime.currentStory,
option,
});
void commitGeneratedState(
nextState,
gameState.playerCharacter,
option.actionText,
buildTreasureResultText(encounter, action, reward ?? undefined),
option.functionId,
);
return true;
}, [commitGeneratedState, gameState, progressTreasureQuest]);
runtime.setGameState(hydratedSnapshot.gameState);
runtime.setCurrentStory(nextStory);
return true;
} catch (error) {
console.error(
'Failed to resolve treasure runtime action on the server:',
error,
);
runtime.setAiError(
error instanceof Error ? error.message : '宝藏动作执行失败',
);
if (!runtime.currentStory) {
runtime.setCurrentStory(
runtime.buildFallbackStoryForState(
gameState,
gameState.playerCharacter,
),
);
}
return false;
} finally {
runtime.setIsLoading(false);
}
},
[gameState, runtime],
);
return {
handleTreasureInteraction,