Files
Genarrative/src/hooks/rpg-runtime-story/useRpgRuntimeStoryFlow.ts
2026-05-05 14:40:41 +08:00

212 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Dispatch, SetStateAction } from 'react';
import type { Character, Encounter, GameState, StoryOption } from '../../types';
import type { EscapePlaybackSync as ResolvedChoicePlaybackSync } from '../combat/escapeFlow';
import type { ResolvedChoiceState } from '../combat/resolvedChoice';
import { createStoryInteractionCoordinatorConfig } from './storyInteractionCoordinator';
import { sanitizeStoryOptions } from './storyPresentation';
import type { StoryRuntimeSupport } from './storyRuntimeSupport';
import { useRpgRuntimeInteractionFlow } from './useRpgRuntimeInteractionFlow';
import type { RpgRuntimeStoryControllerResult } from './useRpgRuntimeStoryController';
import { useRpgRuntimeStoryState } from './useRpgRuntimeStoryState';
import { useStoryGoalOptionCoordinator } from './useStoryGoalOptionCoordinator';
type RpgRuntimeStoryFlowParams = {
gameState: GameState;
setGameState: Dispatch<SetStateAction<GameState>>;
sceneTransitionPhase?: 'idle' | 'exiting' | 'entering';
buildResolvedChoiceState: (
state: GameState,
option: StoryOption,
character: Character,
) => ResolvedChoiceState;
playResolvedChoice: (
state: GameState,
option: StoryOption,
character: Character,
resolvedChoice: ResolvedChoiceState,
sync?: ResolvedChoicePlaybackSync,
) => Promise<GameState>;
getStoryGenerationHostileNpcs: (
state: GameState,
) => GameState['sceneHostileNpcs'];
getResolvedSceneHostileNpcs: (
state: GameState,
) => GameState['sceneHostileNpcs'];
runtimeController: RpgRuntimeStoryControllerResult;
runtimeSupport: StoryRuntimeSupport;
sortOptions: (options: StoryOption[]) => StoryOption[];
buildContinueAdventureOption: () => StoryOption;
resolveNpcInteractionDecision: (
state: GameState,
option: StoryOption,
) => { kind: string };
clearCharacterChatModal: () => void;
isContinueAdventureOption: (option: StoryOption) => boolean;
isCampTravelHomeOption: (option: StoryOption) => boolean;
isRegularNpcEncounter: (
encounter: GameState['currentEncounter'],
) => encounter is Encounter;
isNpcEncounter: (
encounter: GameState['currentEncounter'],
) => encounter is Encounter;
npcPreviewTalkFunctionId: string;
fallbackCompanionName: string;
turnVisualMs: number;
};
/**
* RPG runtime story 主编排层。
* 这里把 option 展示、正式交互分发和 story/session 状态动作收束成稳定出口。
*/
export function useRpgRuntimeStoryFlow({
gameState,
setGameState,
sceneTransitionPhase = 'idle',
buildResolvedChoiceState,
playResolvedChoice,
getStoryGenerationHostileNpcs,
getResolvedSceneHostileNpcs,
runtimeController,
runtimeSupport,
sortOptions,
buildContinueAdventureOption,
resolveNpcInteractionDecision,
clearCharacterChatModal,
isContinueAdventureOption,
isCampTravelHomeOption,
isRegularNpcEncounter,
isNpcEncounter,
npcPreviewTalkFunctionId,
fallbackCompanionName,
turnVisualMs,
}: RpgRuntimeStoryFlowParams) {
const {
currentStory,
setCurrentStory,
setAiError,
setIsLoading,
isLoading,
buildStoryContextFromState,
buildFallbackStoryForState,
buildDialogueStoryMoment,
generateStoryForState,
getAvailableOptionsForState,
getTypewriterDelay,
commitGeneratedState,
commitGeneratedStateWithEncounterEntry,
appendHistory,
buildOpeningCampChatContext,
resetPreparedOpeningAdventure,
} = runtimeController;
// 中文注释interactionConfig 是“剧情交互协调器”的配置快照;
// 后续选项刷新、动作提交、fallback 叙事都会共用这套上下文。
const interactionConfig = createStoryInteractionCoordinatorConfig({
gameState,
setGameState,
setCurrentStory,
setAiError,
setIsLoading,
currentStory,
buildStoryContextFromState,
buildFallbackStoryForState,
buildDialogueStoryMoment,
generateStoryForState,
getAvailableOptionsForState,
getStoryGenerationHostileNpcs,
getTypewriterDelay,
runtimeSupport,
commitGeneratedState,
commitGeneratedStateWithEncounterEntry,
appendHistory,
buildOpeningCampChatContext,
sortOptions,
buildContinueAdventureOption,
sanitizeOptions: sanitizeStoryOptions,
resolveNpcInteractionDecision,
});
const {
displayedOptions,
canRefreshOptions,
handleRefreshOptions,
goalUi,
clearStoryGoalOptionUi,
} = useStoryGoalOptionCoordinator({
gameState,
currentStory,
});
// 中文注释:这一层把“战斗/NPC/背包/地图旅行”等具体交互入口分发到对应流程,
// 保证冒险面板只调用统一的 handleChoice / handleNpcChatInput 等接口。
const {
handleChoice,
battleRewardUi,
npcUi,
inventoryUi,
clearStoryInteractionUi,
handleNpcChatInput,
refreshNpcChatOptions,
exitNpcChat,
npcChatQuestOfferUi,
} = useRpgRuntimeInteractionFlow({
gameState,
isLoading,
sceneTransitionPhase,
interactionConfig,
runtimeSupport,
buildResolvedChoiceState,
playResolvedChoice,
buildStoryFromResponse: runtimeController.buildStoryFromResponse,
getResolvedSceneHostileNpcs,
getCampCompanionTravelScene: runtimeController.getCampCompanionTravelScene,
isContinueAdventureOption,
isCampTravelHomeOption,
isRegularNpcEncounter,
isNpcEncounter,
npcPreviewTalkFunctionId,
fallbackCompanionName,
turnVisualMs,
});
const { questUi, resetStoryState, hydrateStoryState, travelToSceneFromMap } =
useRpgRuntimeStoryState({
gameState,
isLoading,
setGameState,
setCurrentStory,
setAiError,
setIsLoading,
commitGeneratedState,
buildFallbackStoryForState,
resetPreparedOpeningAdventure,
clearStoryGoalOptionUi,
clearStoryInteractionUi,
clearCharacterChatModal,
});
// 中文注释:最终返回的是已经过目标选项协调、交互分发和 story state 收束后的稳定输出。
return {
displayedOptions,
canRefreshOptions,
handleRefreshOptions,
handleChoice,
resetStoryState,
hydrateStoryState,
travelToSceneFromMap,
battleRewardUi,
questUi,
goalUi,
npcUi,
inventoryUi,
handleNpcChatInput,
refreshNpcChatOptions,
exitNpcChat,
npcChatQuestOfferUi,
};
}
export type UseRpgRuntimeStoryFlowParams = Parameters<
typeof useRpgRuntimeStoryFlow
>[0];
export type RpgRuntimeStoryFlowResult = ReturnType<
typeof useRpgRuntimeStoryFlow
>;