76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
import { useCallback } from 'react';
|
|
|
|
import { resolveRpgRuntimeChoice } from './rpg-runtime-story';
|
|
import { Character, GameState, StoryMoment, StoryOption } from '../types';
|
|
|
|
export function useTreasureFlow({
|
|
gameState,
|
|
runtime,
|
|
}: {
|
|
gameState: GameState;
|
|
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(
|
|
async (option: StoryOption) => {
|
|
if (
|
|
!gameState.playerCharacter ||
|
|
option.interaction?.kind !== 'treasure' ||
|
|
gameState.currentEncounter?.kind !== 'treasure'
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
runtime.setAiError(null);
|
|
runtime.setIsLoading(true);
|
|
|
|
try {
|
|
const { hydratedSnapshot, nextStory } =
|
|
await resolveRpgRuntimeChoice({
|
|
gameState,
|
|
currentStory: runtime.currentStory,
|
|
option,
|
|
});
|
|
|
|
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,
|
|
};
|
|
}
|