132 lines
3.2 KiB
TypeScript
132 lines
3.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { AnimationState, type GameState } from '../../types';
|
|
import {
|
|
applyCompanionReactionToStance,
|
|
buildCompanionReactionBatch,
|
|
} from './companionReactionDirector';
|
|
|
|
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: 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: {
|
|
'npc-companion': {
|
|
affinity: 30,
|
|
helpUsed: false,
|
|
chattedCount: 0,
|
|
giftsGiven: 0,
|
|
inventory: [],
|
|
recruited: true,
|
|
revealedFacts: [],
|
|
knownAttributeRumors: [],
|
|
firstMeaningfulContactResolved: true,
|
|
seenBackstoryChapterIds: [],
|
|
stanceProfile: {
|
|
trust: 52,
|
|
warmth: 48,
|
|
ideologicalFit: 50,
|
|
fearOrGuard: 30,
|
|
loyalty: 40,
|
|
currentConflictTag: null,
|
|
recentApprovals: [],
|
|
recentDisapprovals: [],
|
|
},
|
|
},
|
|
},
|
|
quests: [],
|
|
roster: [],
|
|
companions: [
|
|
{
|
|
npcId: 'npc-companion',
|
|
characterId: 'archer-hero',
|
|
joinedAtAffinity: 30,
|
|
hp: 10,
|
|
maxHp: 10,
|
|
mana: 10,
|
|
maxMana: 10,
|
|
skillCooldowns: {},
|
|
},
|
|
],
|
|
currentBattleNpcId: null,
|
|
currentNpcBattleMode: null,
|
|
currentNpcBattleOutcome: null,
|
|
sparReturnEncounter: null,
|
|
sparPlayerHpBefore: null,
|
|
sparPlayerMaxHpBefore: null,
|
|
sparStoryHistoryBefore: null,
|
|
};
|
|
}
|
|
|
|
describe('companionReactionDirector', () => {
|
|
it('builds reactions and writes them back to stance', () => {
|
|
const state = createState();
|
|
const reactions = buildCompanionReactionBatch({
|
|
state,
|
|
signals: [
|
|
{
|
|
id: 'signal-1',
|
|
signalType: 'accept_contract',
|
|
threadIds: ['thread-1'],
|
|
},
|
|
],
|
|
actionText: '接下调查断桥旧案的委托',
|
|
});
|
|
const nextState = applyCompanionReactionToStance({
|
|
state,
|
|
reactions,
|
|
});
|
|
|
|
expect(reactions[0]?.reactionType).toBe('approve');
|
|
expect(nextState.npcStates['npc-companion']?.stanceProfile?.trust).toBeGreaterThan(
|
|
state.npcStates['npc-companion']?.stanceProfile?.trust ?? 0,
|
|
);
|
|
});
|
|
});
|