import {describe, expect, it} from 'vitest'; import {WorldType} from '../types'; import {addInventoryItems} from './npcInteractions'; import { buildLooseRuntimeItemGenerationContext, buildQuestRuntimeItemGenerationContext, } from './runtimeItemContext'; import {buildDirectedRuntimeReward, buildRuntimeInventoryStock} from './runtimeItemDirector'; describe('runtime item director', () => { it('builds treasure rewards with runtime metadata and relation anchors', () => { const context = buildLooseRuntimeItemGenerationContext({ worldType: WorldType.WUXIA, scene: { id: 'scene-ruins', name: '断碑古道', description: '碎碑与旧誓散落在路旁。', treasureHints: ['残匣', '旧祭火'], }, encounter: { id: 'treasure-altar', kind: 'treasure', npcName: '断誓秘匣', npcDescription: '匣盖上留着未熄的旧印。', npcAvatar: '', context: '古道祭坛', }, playerCharacterId: 'hero', playerBuildTags: ['快剑', '追击'], generationChannel: 'treasure', }); const reward = buildDirectedRuntimeReward(context, { seedKey: 'test:treasure', fixedKinds: ['relic', 'consumable'], fixedPermanence: ['permanent', 'timed'], itemCount: 2, }); expect(reward.primaryItem?.runtimeMetadata?.generationChannel).toBe('treasure'); expect(reward.primaryItem?.runtimeMetadata?.relationAnchor?.type).toBe('npc'); expect(reward.primaryItem?.name).not.toBe('未命名秘物'); expect(reward.primaryItem?.runtimeMetadata?.storyFingerprint?.visibleClue).toBeTruthy(); expect(reward.primaryItem?.runtimeMetadata?.storyFingerprint?.unresolvedQuestion).toBeTruthy(); expect(reward.primaryItem?.description).toContain('适合当前局势里的临场构筑调整'); }); it('keeps identity-sensitive runtime items separate when adding inventory', () => { const baseItem = buildRuntimeInventoryStock( buildLooseRuntimeItemGenerationContext({ worldType: WorldType.WUXIA, encounter: { id: 'npc-blackmarket', kind: 'npc', npcName: '黑市牙人', npcDescription: '在阴影里兜售消息与暗器。', npcAvatar: '', context: '黑市', }, playerCharacterId: 'hero', playerBuildTags: ['快袭', '风行'], generationChannel: 'npc_trade', }), { seedKey: 'test:stock', itemCount: 1, fixedKinds: ['relic'], fixedPermanence: ['permanent'], }, )[0]; const secondItem = { ...baseItem, id: `${baseItem.id}:variant`, runtimeMetadata: baseItem.runtimeMetadata ? { ...baseItem.runtimeMetadata, seedKey: `${baseItem.runtimeMetadata.seedKey}:variant`, } : null, }; const merged = addInventoryItems([], [baseItem, secondItem]); expect(merged).toHaveLength(2); }); it('can build quest-flavored runtime rewards from quest context', () => { const context = buildQuestRuntimeItemGenerationContext({ context: { worldType: WorldType.XIANXIA, currentSceneId: 'scene-cloud', currentSceneName: '云阙旧渡', currentSceneDescription: '旧渡口残留着灵潮和巡守痕迹。', issuerNpcId: 'npc-issuer', issuerNpcName: '巡守使', issuerNpcContext: '巡守', issuerAffinity: 24, recentStoryMoments: [], playerCharacter: null, }, issuerNpcId: 'npc-issuer', issuerNpcName: '巡守使', roleText: '巡守', scene: { id: 'scene-cloud', name: '云阙旧渡', description: '旧渡口残留着灵潮和巡守痕迹。', treasureHints: ['旧印'], }, }); const reward = buildDirectedRuntimeReward(context, { seedKey: 'test:quest', fixedKinds: ['equipment', 'consumable'], fixedPermanence: ['permanent', 'timed'], itemCount: 2, }); expect(reward.primaryItem?.runtimeMetadata?.generationChannel).toBe('quest_reward'); expect(reward.supportItems.length).toBeGreaterThanOrEqual(1); }); });