Rework story engine flow and reorganize project docs
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-06 23:19:00 +08:00
parent d678929064
commit ddcb5d5c8c
241 changed files with 19805 additions and 2478 deletions

View File

@@ -0,0 +1,92 @@
import { describe, expect, it } from 'vitest';
import { AnimationState, type GameState } from '../../types';
import { advanceChapterState, resolveCurrentChapterState } from './chapterDirector';
function createState(signalCount: number): GameState {
return {
worldType: null,
customWorldProfile: null,
playerCharacter: null,
runtimeStats: {
playTimeMs: 0,
lastPlayTickAt: null,
hostileNpcsDefeated: 0,
questsAccepted: 0,
itemsUsed: 0,
scenesTraveled: 0,
},
currentScene: 'Story',
storyHistory: [],
storyEngineMemory: {
discoveredFactIds: [],
inferredFactIds: [],
activeThreadIds: ['thread-1'],
resolvedScarIds: [],
recentCarrierIds: [],
recentSignalIds: Array.from({ length: signalCount }, (_, index) => `signal-${index + 1}`),
recentCompanionReactions: [],
currentChapter: null,
currentJourneyBeatId: null,
companionArcStates: [],
worldMutations: [],
chronicle: [],
factionTensionStates: [],
currentCampEvent: null,
currentSetpieceDirective: null,
continueGameDigest: null,
},
chapterState: null,
characterChats: {},
animationState: AnimationState.IDLE,
currentEncounter: null,
npcInteractionActive: false,
currentScenePreset: null,
sceneHostileNpcs: [],
playerX: 0,
playerOffsetY: 0,
playerFacing: 'right',
playerActionMode: 'idle',
scrollWorld: false,
inBattle: false,
playerHp: 0,
playerMaxHp: 0,
playerMana: 0,
playerMaxMana: 0,
playerSkillCooldowns: {},
activeBuildBuffs: [],
activeCombatEffects: [],
playerCurrency: 0,
playerInventory: [],
playerEquipment: { weapon: null, armor: null, relic: null },
npcStates: {},
quests: [],
roster: [],
companions: [],
currentBattleNpcId: null,
currentNpcBattleMode: null,
currentNpcBattleOutcome: null,
sparReturnEncounter: null,
sparPlayerHpBefore: null,
sparPlayerMaxHpBefore: null,
sparStoryHistoryBefore: null,
};
}
describe('chapterDirector', () => {
it('resolves chapter stages from signal intensity', () => {
expect(resolveCurrentChapterState({ state: createState(1) }).stage).toBe('opening');
expect(resolveCurrentChapterState({ state: createState(4) }).stage).toBe('expansion');
expect(resolveCurrentChapterState({ state: createState(10) }).stage).toBe('climax');
});
it('keeps chapter id stable when stage and theme do not change', () => {
const previous = resolveCurrentChapterState({ state: createState(4) });
const next = advanceChapterState({
previousChapter: previous,
nextChapter: resolveCurrentChapterState({ state: createState(4) }),
});
expect(next.id).toBe(previous.id);
});
});