98 lines
2.5 KiB
TypeScript
98 lines
2.5 KiB
TypeScript
import {describe, expect, it, vi} from 'vitest';
|
|
|
|
import type {GameState} from '../types';
|
|
import {AnimationState, WorldType} from '../types';
|
|
import {rollHostileNpcLoot} from './hostileNpcPresets';
|
|
|
|
function createGameState(): GameState {
|
|
return {
|
|
worldType: WorldType.WUXIA,
|
|
customWorldProfile: null,
|
|
playerCharacter: null,
|
|
runtimeStats: {
|
|
playTimeMs: 0,
|
|
lastPlayTickAt: null,
|
|
hostileNpcsDefeated: 0,
|
|
questsAccepted: 0,
|
|
itemsUsed: 0,
|
|
scenesTraveled: 0,
|
|
},
|
|
currentScene: 'Story',
|
|
storyHistory: [],
|
|
characterChats: {},
|
|
animationState: AnimationState.IDLE,
|
|
currentEncounter: null,
|
|
npcInteractionActive: false,
|
|
currentScenePreset: {
|
|
id: 'ruins',
|
|
name: '断碑古道',
|
|
description: '阴气与碎骨混在旧路之间。',
|
|
imageSrc: '/ruins.png',
|
|
npcs: [],
|
|
treasureHints: [],
|
|
},
|
|
sceneHostileNpcs: [],
|
|
playerX: 0,
|
|
playerOffsetY: 0,
|
|
playerFacing: 'right',
|
|
playerActionMode: 'idle',
|
|
scrollWorld: false,
|
|
inBattle: false,
|
|
playerHp: 100,
|
|
playerMaxHp: 100,
|
|
playerMana: 60,
|
|
playerMaxMana: 60,
|
|
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('hostileNpcPresets', () => {
|
|
it('combines preset loot with runtime semantic drops', async () => {
|
|
const randomSpy = vi.spyOn(Math, 'random').mockReturnValue(0);
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn().mockRejectedValue(new TypeError('network disabled in test')),
|
|
);
|
|
|
|
try {
|
|
const loot = await rollHostileNpcLoot(createGameState(), [
|
|
{
|
|
id: 'monster-03',
|
|
name: '断骨祟灵',
|
|
},
|
|
]);
|
|
|
|
expect(loot.some(item => item.id === 'monster-loot:bone-dust')).toBe(true);
|
|
expect(
|
|
loot.some(item => item.runtimeMetadata?.generationChannel === 'monster_drop'),
|
|
).toBe(true);
|
|
expect(
|
|
loot.find(item => item.id === 'monster-loot:bone-dust')?.runtimeMetadata?.storyFingerprint,
|
|
).toBeTruthy();
|
|
} finally {
|
|
vi.unstubAllGlobals();
|
|
randomSpy.mockRestore();
|
|
}
|
|
});
|
|
});
|