124 lines
4.1 KiB
TypeScript
124 lines
4.1 KiB
TypeScript
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);
|
|
});
|
|
});
|