Files
Genarrative/src/data/scenePresets.test.ts

196 lines
6.7 KiB
TypeScript

import { afterEach, describe, expect, it } from 'vitest';
import { buildExpandedCustomWorldProfile } from '../services/customWorldBuilder';
import { WorldType } from '../types';
import { setRuntimeCustomWorldProfile } from './customWorldRuntime';
import { buildEncounterFromSceneNpc, getScenePresetsByWorld } from './scenePresets';
function createPlayableNpc(index: number) {
return {
name: `可扮演角色${index + 1}`,
title: `可扮演头衔${index + 1}`,
role: `可扮演身份${index + 1}`,
description: `可扮演角色描述${index + 1}`,
backstory: `可扮演角色背景${index + 1}`,
personality: `可扮演角色性格${index + 1}`,
motivation: `可扮演角色动机${index + 1}`,
combatStyle: `可扮演角色战斗风格${index + 1}`,
initialAffinity: 18,
relationshipHooks: [`切入口${index + 1}`],
tags: [`标签${index + 1}`],
backstoryReveal: {
publicSummary: `公开背景${index + 1}`,
chapters: [
{
id: `surface-${index + 1}`,
title: '表层来意',
affinityRequired: 10,
teaser: `提示${index + 1}-1`,
content: `内容${index + 1}-1`,
contextSnippet: `摘要${index + 1}-1`,
},
{
id: `scar-${index + 1}`,
title: '旧事裂痕',
affinityRequired: 30,
teaser: `提示${index + 1}-2`,
content: `内容${index + 1}-2`,
contextSnippet: `摘要${index + 1}-2`,
},
{
id: `hidden-${index + 1}`,
title: '隐藏执念',
affinityRequired: 55,
teaser: `提示${index + 1}-3`,
content: `内容${index + 1}-3`,
contextSnippet: `摘要${index + 1}-3`,
},
{
id: `final-${index + 1}`,
title: '最终底牌',
affinityRequired: 80,
teaser: `提示${index + 1}-4`,
content: `内容${index + 1}-4`,
contextSnippet: `摘要${index + 1}-4`,
},
],
},
skills: [
{ name: `技能${index + 1}-1`, summary: '技能摘要1', style: '起手压制' },
{ name: `技能${index + 1}-2`, summary: '技能摘要2', style: '机动周旋' },
{ name: `技能${index + 1}-3`, summary: '技能摘要3', style: '爆发终结' },
],
initialItems: [
{
name: `物品${index + 1}-1`,
category: '武器',
quantity: 1,
rarity: 'rare',
description: '物品描述1',
tags: ['物品标签1'],
},
{
name: `物品${index + 1}-2`,
category: '消耗品',
quantity: 2,
rarity: 'uncommon',
description: '物品描述2',
tags: ['物品标签2'],
},
{
name: `物品${index + 1}-3`,
category: '专属物品',
quantity: 1,
rarity: 'rare',
description: '物品描述3',
tags: ['物品标签3'],
},
],
};
}
describe('scenePresets custom world npc mapping', () => {
afterEach(() => {
setRuntimeCustomWorldProfile(null);
});
it('preserves custom world npc dossier fields into scene npcs and encounters', () => {
const profile = buildExpandedCustomWorldProfile(
{
name: '雾潮世界',
subtitle: '潮雾未散',
summary: '一座围绕码头、断桥和旧潮路展开的自定义世界。',
tone: '克制、潮湿、危险',
playerGoal: '查清雾潮里失踪的人和桥下的旧案。',
templateWorldType: 'WUXIA',
playableNpcs: Array.from({ length: 5 }, (_, index) =>
createPlayableNpc(index),
),
storyNpcs: [
{
...createPlayableNpc(10),
name: '沈雾',
title: '潮路领航人',
role: '码头向导',
description: '熟悉潮路和暗栈的旧向导。',
backstory: '少年时曾在断桥坠潮夜里失去整队同伴。',
personality: '谨慎冷静,先观察再表态。',
motivation: '想把雾潮深处那条失踪航线重新找出来。',
combatStyle: '短刀试探后再借地形逼近。',
relationshipHooks: ['潮路', '断桥旧案'],
tags: ['码头', '旧潮路'],
imageSrc: '/custom/npcs/shenwu.png',
},
{
...createPlayableNpc(11),
name: '陆沉',
title: '断桥守更',
role: '守桥人',
description: '夜里守着断桥口的旧灯火。',
},
{
...createPlayableNpc(12),
name: '顾潮',
title: '潮册记录员',
role: '记录员',
description: '在潮账房里整理各路失踪名单。',
},
],
landmarks: [
{
name: '雾潮码头',
description: '旧船桩和潮雾把视线切成断续的几段。',
sceneNpcNames: ['沈雾', '陆沉', '顾潮'],
connections: [
{
targetLandmarkName: '断桥旧道',
relativePosition: 'north',
summary: '顺着潮路向北可抵断桥。',
},
],
},
{
name: '断桥旧道',
description: '半塌的桥面上还挂着旧索和残旗。',
sceneNpcNames: ['沈雾', '陆沉', '顾潮'],
connections: [
{
targetLandmarkName: '雾潮码头',
relativePosition: 'south',
summary: '沿旧潮路南返能回码头。',
},
],
},
],
},
'玩家想要一个围绕雾潮码头与断桥旧案展开的世界。',
);
setRuntimeCustomWorldProfile(profile);
const scene = getScenePresetsByWorld(WorldType.CUSTOM).find(
(entry) => entry.name === '雾潮码头',
);
const npc = scene?.npcs?.find((entry) => entry.name === '沈雾');
expect(scene).toBeTruthy();
expect(npc).toBeTruthy();
expect(npc?.characterId).toBe(npc?.id);
expect(npc?.title).toBe('潮路领航人');
expect(npc?.backstory).toContain('断桥坠潮夜');
expect(npc?.personality).toContain('谨慎冷静');
expect(npc?.motivation).toContain('失踪航线');
expect(npc?.skills).toHaveLength(3);
expect(npc?.initialItems).toHaveLength(3);
expect(npc?.avatar).toBe('/custom/npcs/shenwu.png');
const encounter = buildEncounterFromSceneNpc(npc!);
expect(encounter.title).toBe('潮路领航人');
expect(encounter.backstoryReveal?.publicSummary).toBe('公开背景11');
expect(encounter.skills?.[0]?.name).toBe('技能11-1');
expect(encounter.initialItems?.[0]?.name).toBe('物品11-1');
expect(encounter.imageSrc).toBe('/custom/npcs/shenwu.png');
});
});