159 lines
4.5 KiB
TypeScript
159 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { AnimationState, type GameState } from '../../types';
|
|
import { collectStorySignals, resolveSignalsToThreadUpdates } from './threadSignalRouter';
|
|
|
|
function createState(): 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: [],
|
|
recentCompanionReactions: [],
|
|
},
|
|
characterChats: {},
|
|
animationState: AnimationState.IDLE,
|
|
currentEncounter: null,
|
|
npcInteractionActive: false,
|
|
currentScenePreset: {
|
|
id: 'scene-1',
|
|
name: '断桥旧哨',
|
|
description: '旧哨火和断桥一起守着边城北口。',
|
|
imageSrc: '',
|
|
treasureHints: [],
|
|
narrativeResidues: [],
|
|
},
|
|
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: [
|
|
{
|
|
id: 'quest-1',
|
|
issuerNpcId: 'npc-1',
|
|
issuerNpcName: '梁砺',
|
|
sceneId: 'scene-1',
|
|
threadId: 'thread-1',
|
|
contractId: 'thread-contract:thread-1',
|
|
title: '调查断桥旧案',
|
|
description: '先去看清桥口到底发生了什么。',
|
|
summary: '调查断桥旧案',
|
|
objective: {
|
|
kind: 'inspect_treasure',
|
|
targetSceneId: 'scene-1',
|
|
requiredCount: 1,
|
|
},
|
|
progress: 0,
|
|
status: 'active',
|
|
reward: {
|
|
affinityBonus: 0,
|
|
currency: 0,
|
|
items: [],
|
|
},
|
|
rewardText: '',
|
|
steps: [],
|
|
activeStepId: null,
|
|
visibleStage: 0,
|
|
hiddenFlags: [],
|
|
discoveredFactIds: [],
|
|
relatedCarrierIds: [],
|
|
},
|
|
],
|
|
roster: [],
|
|
companions: [],
|
|
currentBattleNpcId: null,
|
|
currentNpcBattleMode: null,
|
|
currentNpcBattleOutcome: null,
|
|
sparReturnEncounter: null,
|
|
sparPlayerHpBefore: null,
|
|
sparPlayerMaxHpBefore: null,
|
|
sparStoryHistoryBefore: null,
|
|
};
|
|
}
|
|
|
|
describe('threadSignalRouter', () => {
|
|
it('collects signals and advances memory/quest stage', () => {
|
|
const prevState = createState();
|
|
const nextState = {
|
|
...createState(),
|
|
playerInventory: [
|
|
{
|
|
id: 'carrier-1',
|
|
category: '专属物品',
|
|
name: '封痕信物',
|
|
quantity: 1,
|
|
rarity: 'rare',
|
|
tags: ['relic'],
|
|
runtimeMetadata: {
|
|
origin: 'ai_compiled',
|
|
generationChannel: 'quest_reward',
|
|
seedKey: 'seed',
|
|
sourceReason: '旧案把它重新推到了你眼前。',
|
|
storyFingerprint: {
|
|
visibleClue: '桥口旧铜味一直留在它的边角。',
|
|
witnessMark: '它曾被人攥着在封桥夜里来回传递。',
|
|
unresolvedQuestion: '它为什么一直没有被交回去?',
|
|
currentAppearanceReason: '封桥旧案再次被提起。',
|
|
relatedThreadIds: ['thread-1'],
|
|
relatedScarIds: ['scar-1'],
|
|
reactionHooks: ['名单'],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
} satisfies GameState;
|
|
const signals = collectStorySignals({
|
|
prevState,
|
|
nextState,
|
|
actionText: '接下调查断桥旧案的委托',
|
|
lastFunctionId: 'npc_quest_accept',
|
|
rewardItems: nextState.playerInventory,
|
|
});
|
|
const resolved = resolveSignalsToThreadUpdates({
|
|
state: nextState,
|
|
signals,
|
|
contracts: [],
|
|
});
|
|
|
|
expect(signals.some((signal) => signal.signalType === 'accept_contract')).toBe(true);
|
|
expect(signals.some((signal) => signal.signalType === 'obtain_carrier')).toBe(true);
|
|
expect(resolved.storyEngineMemory?.recentSignalIds?.length).toBeGreaterThan(0);
|
|
expect(resolved.quests[0]?.visibleStage).toBeGreaterThan(0);
|
|
expect(resolved.quests[0]?.relatedCarrierIds).toContain('carrier-1');
|
|
});
|
|
});
|