This commit is contained in:
203
src/hooks/rpg-runtime-story/useRpgRuntimeStoryFlow.ts
Normal file
203
src/hooks/rpg-runtime-story/useRpgRuntimeStoryFlow.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
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>>;
|
||||
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,
|
||||
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;
|
||||
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,
|
||||
});
|
||||
const {
|
||||
handleChoice,
|
||||
battleRewardUi,
|
||||
npcUi,
|
||||
inventoryUi,
|
||||
clearStoryInteractionUi,
|
||||
handleNpcChatInput,
|
||||
refreshNpcChatOptions,
|
||||
exitNpcChat,
|
||||
npcChatQuestOfferUi,
|
||||
} = useRpgRuntimeInteractionFlow({
|
||||
gameState,
|
||||
isLoading,
|
||||
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,
|
||||
});
|
||||
|
||||
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
|
||||
>;
|
||||
Reference in New Issue
Block a user