This commit is contained in:
132
src/hooks/combat/resolvedChoice.ts
Normal file
132
src/hooks/combat/resolvedChoice.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
getForwardScenePreset,
|
||||
getScenePresetById,
|
||||
getScenePresetsByWorld,
|
||||
getTravelScenePreset,
|
||||
} from '../../data/scenePresets';
|
||||
import { getFunctionEffect } from '../../data/stateFunctions';
|
||||
import type {
|
||||
Character,
|
||||
GameState,
|
||||
StoryOption,
|
||||
WorldType,
|
||||
} from '../../types';
|
||||
import { classifyCombatOption } from '../combatStoryUtils';
|
||||
import { buildIdleAfterSequence } from '../idleAdventureFlow';
|
||||
import {
|
||||
applyRecoveryEffectToState,
|
||||
type BattlePlan,
|
||||
} from './battlePlan';
|
||||
import { buildEscapeAfterSequence } from './escapeFlow';
|
||||
|
||||
type OptionKind = 'battle' | 'escape' | 'idle';
|
||||
|
||||
export type ResolvedChoiceState = {
|
||||
optionKind: OptionKind;
|
||||
battlePlan: BattlePlan | null;
|
||||
afterSequence: GameState;
|
||||
};
|
||||
|
||||
function getShiftedScenePreset(
|
||||
worldType: WorldType | null,
|
||||
currentScenePreset: GameState['currentScenePreset'],
|
||||
sceneShift: number | undefined,
|
||||
): GameState['currentScenePreset'] {
|
||||
if (!worldType || sceneShift === undefined || sceneShift === 0) return currentScenePreset;
|
||||
if (!currentScenePreset) return getScenePresetsByWorld(worldType)[0] ?? null;
|
||||
|
||||
if (sceneShift > 0) {
|
||||
let nextScene = currentScenePreset;
|
||||
for (let index = 0; index < sceneShift; index += 1) {
|
||||
nextScene = getForwardScenePreset(worldType, nextScene.id) ?? nextScene;
|
||||
}
|
||||
return nextScene;
|
||||
}
|
||||
|
||||
const scenes = getScenePresetsByWorld(worldType);
|
||||
if (scenes.length === 0) return currentScenePreset;
|
||||
const currentIndex = scenes.findIndex(scene => scene.id === currentScenePreset.id);
|
||||
const safeIndex = currentIndex >= 0 ? currentIndex : 0;
|
||||
const nextIndex = ((safeIndex + sceneShift) % scenes.length + scenes.length) % scenes.length;
|
||||
return scenes[nextIndex] ?? null;
|
||||
}
|
||||
|
||||
function getSceneTargetForFunction(
|
||||
worldType: WorldType | null,
|
||||
currentScenePreset: GameState['currentScenePreset'],
|
||||
option: StoryOption,
|
||||
): GameState['currentScenePreset'] {
|
||||
if (!worldType) return currentScenePreset;
|
||||
|
||||
if (option.functionId === 'idle_travel_next_scene') {
|
||||
const targetSceneId =
|
||||
typeof option.runtimePayload?.targetSceneId === 'string'
|
||||
? option.runtimePayload.targetSceneId
|
||||
: null;
|
||||
if (targetSceneId) {
|
||||
return getScenePresetById(worldType, targetSceneId) ?? currentScenePreset;
|
||||
}
|
||||
|
||||
return getTravelScenePreset(worldType, currentScenePreset?.id) ?? currentScenePreset;
|
||||
}
|
||||
|
||||
return getShiftedScenePreset(
|
||||
worldType,
|
||||
currentScenePreset,
|
||||
getFunctionEffect(option.functionId).sceneShift,
|
||||
);
|
||||
}
|
||||
|
||||
export function buildResolvedChoiceState(params: {
|
||||
state: GameState;
|
||||
option: StoryOption;
|
||||
character: Character;
|
||||
buildBattlePlan: (state: GameState, option: StoryOption, character: Character) => BattlePlan;
|
||||
}) {
|
||||
const {
|
||||
state,
|
||||
option,
|
||||
character,
|
||||
buildBattlePlan,
|
||||
} = params;
|
||||
const nextScenePreset = getSceneTargetForFunction(
|
||||
state.worldType,
|
||||
state.currentScenePreset,
|
||||
option,
|
||||
);
|
||||
const optionKind = classifyCombatOption(option);
|
||||
|
||||
if (optionKind === 'battle') {
|
||||
const battlePlan = buildBattlePlan(state, option, character);
|
||||
const battleResult: GameState = {
|
||||
...battlePlan.finalState,
|
||||
currentScenePreset: nextScenePreset ?? battlePlan.finalState.currentScenePreset,
|
||||
};
|
||||
|
||||
return {
|
||||
optionKind,
|
||||
battlePlan,
|
||||
afterSequence: battleResult,
|
||||
} satisfies ResolvedChoiceState;
|
||||
}
|
||||
|
||||
if (optionKind === 'escape') {
|
||||
return {
|
||||
optionKind,
|
||||
battlePlan: null,
|
||||
afterSequence: buildEscapeAfterSequence(state, option),
|
||||
} satisfies ResolvedChoiceState;
|
||||
}
|
||||
|
||||
return {
|
||||
optionKind,
|
||||
battlePlan: null,
|
||||
afterSequence: buildIdleAfterSequence({
|
||||
state,
|
||||
option,
|
||||
character,
|
||||
nextScenePreset,
|
||||
applyRecoveryEffectToState,
|
||||
}),
|
||||
} satisfies ResolvedChoiceState;
|
||||
}
|
||||
Reference in New Issue
Block a user