1
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user