This commit is contained in:
127
src/services/storyEngine/worldMutationRouter.ts
Normal file
127
src/services/storyEngine/worldMutationRouter.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import type {
|
||||
ChapterState,
|
||||
GameState,
|
||||
StorySignal,
|
||||
WorldMutation,
|
||||
} from '../../types';
|
||||
|
||||
function dedupeStrings(values: Array<string | null | undefined>, limit = 6) {
|
||||
return [...new Set(values.map((value) => value?.trim() ?? '').filter(Boolean))]
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
export function resolveWorldMutations(params: {
|
||||
state: GameState;
|
||||
signals: StorySignal[];
|
||||
chapterState: ChapterState | null | undefined;
|
||||
}) {
|
||||
const currentSceneId = params.state.currentScenePreset?.id;
|
||||
const activeThreadIds = params.state.storyEngineMemory?.activeThreadIds ?? [];
|
||||
const mutations: WorldMutation[] = [];
|
||||
|
||||
if (currentSceneId && params.chapterState) {
|
||||
mutations.push({
|
||||
id: `mutation:scene:${currentSceneId}:${params.chapterState.stage}`,
|
||||
mutationType: 'scene_text',
|
||||
targetId: currentSceneId,
|
||||
reason: `${params.chapterState.title}正在改写这片地界的表面气氛。`,
|
||||
relatedThreadIds: params.chapterState.primaryThreadIds,
|
||||
});
|
||||
}
|
||||
|
||||
if (currentSceneId && params.signals.some((signal) => signal.signalType === 'win_battle')) {
|
||||
mutations.push({
|
||||
id: `mutation:pressure:${currentSceneId}:battle`,
|
||||
mutationType: 'enemy_pressure',
|
||||
targetId: currentSceneId,
|
||||
reason: '这一带的敌意正在因交锋结果重新聚拢。',
|
||||
relatedThreadIds: dedupeStrings(activeThreadIds, 4),
|
||||
});
|
||||
}
|
||||
|
||||
if (params.signals.some((signal) => signal.signalType === 'obtain_carrier')) {
|
||||
mutations.push({
|
||||
id: `mutation:attitude:${currentSceneId ?? 'scene'}:carrier`,
|
||||
mutationType: 'npc_attitude',
|
||||
targetId: currentSceneId ?? 'scene',
|
||||
reason: '关键载体已经落到你手里,相关角色的口风会开始变化。',
|
||||
relatedThreadIds: dedupeStrings(activeThreadIds, 4),
|
||||
});
|
||||
}
|
||||
|
||||
if (params.chapterState?.stage === 'climax' && currentSceneId) {
|
||||
mutations.push({
|
||||
id: `mutation:route:${currentSceneId}:climax`,
|
||||
mutationType: 'route_unlock',
|
||||
targetId: currentSceneId,
|
||||
reason: '章节高潮逼近,新的通路或对峙点开始显影。',
|
||||
relatedThreadIds: params.chapterState.primaryThreadIds,
|
||||
});
|
||||
}
|
||||
|
||||
return mutations;
|
||||
}
|
||||
|
||||
export function applyWorldMutationsToGameState(params: {
|
||||
state: GameState;
|
||||
mutations: WorldMutation[];
|
||||
}) {
|
||||
const knownMutations = [
|
||||
...(params.state.storyEngineMemory?.worldMutations ?? []),
|
||||
...params.mutations,
|
||||
];
|
||||
if (knownMutations.length <= 0) {
|
||||
return params.state;
|
||||
}
|
||||
|
||||
const currentSceneId = params.state.currentScenePreset?.id ?? null;
|
||||
const relevantMutations = currentSceneId
|
||||
? knownMutations.filter((mutation) => mutation.targetId === currentSceneId)
|
||||
: knownMutations;
|
||||
const latestSceneMutation = relevantMutations
|
||||
.filter((mutation) => mutation.mutationType === 'scene_text')
|
||||
.at(-1);
|
||||
const pressureMutationCount = relevantMutations.filter(
|
||||
(mutation) => mutation.mutationType === 'enemy_pressure',
|
||||
).length;
|
||||
const attitudeMutation = relevantMutations
|
||||
.filter((mutation) => mutation.mutationType === 'npc_attitude')
|
||||
.at(-1);
|
||||
const currentPressureLevel =
|
||||
pressureMutationCount >= 3
|
||||
? 'extreme'
|
||||
: pressureMutationCount === 2
|
||||
? 'high'
|
||||
: pressureMutationCount === 1
|
||||
? 'medium'
|
||||
: params.state.currentScenePreset?.currentPressureLevel ?? 'low';
|
||||
|
||||
return {
|
||||
...params.state,
|
||||
currentScenePreset: params.state.currentScenePreset
|
||||
? {
|
||||
...params.state.currentScenePreset,
|
||||
mutationStateText:
|
||||
[latestSceneMutation?.reason, attitudeMutation?.reason]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
?? params.state.currentScenePreset.mutationStateText
|
||||
?? null,
|
||||
currentPressureLevel,
|
||||
description: [
|
||||
params.state.currentScenePreset.description,
|
||||
latestSceneMutation?.reason,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' '),
|
||||
npcs: params.state.currentScenePreset.npcs?.map((npc) => ({
|
||||
...npc,
|
||||
description:
|
||||
attitudeMutation && !npc.hostile
|
||||
? `${npc.description} ${attitudeMutation.reason}`
|
||||
: npc.description,
|
||||
})),
|
||||
}
|
||||
: params.state.currentScenePreset,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user