150 lines
4.7 KiB
TypeScript
150 lines
4.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { WorldType, type CustomWorldProfile } from '../types';
|
|
import { resolveCustomWorldCoverPresentation } from './customWorldCover';
|
|
|
|
function createBaseProfile(): CustomWorldProfile {
|
|
return {
|
|
id: 'custom-world-cover-test',
|
|
settingText: '潮雾群岛',
|
|
name: '潮雾群岛',
|
|
subtitle: '封面规则测试',
|
|
summary: '用于验证默认封面优先级。',
|
|
tone: '潮湿、压抑',
|
|
playerGoal: '查明旧航道真相。',
|
|
templateWorldType: WorldType.WUXIA,
|
|
compatibilityTemplateWorldType: WorldType.WUXIA,
|
|
majorFactions: [],
|
|
coreConflicts: [],
|
|
attributeSchema: {
|
|
id: 'schema:test',
|
|
worldId: 'CUSTOM',
|
|
schemaVersion: 1,
|
|
generatedFrom: {
|
|
worldType: WorldType.CUSTOM,
|
|
worldName: '潮雾群岛',
|
|
settingSummary: '封面规则测试',
|
|
tone: '潮湿、压抑',
|
|
conflictCore: '旧航道真相',
|
|
},
|
|
slots: [],
|
|
},
|
|
playableNpcs: [
|
|
{
|
|
id: 'playable-1',
|
|
name: '林潮',
|
|
title: '守潮人',
|
|
role: '可扮演角色',
|
|
description: '负责守住第一道进港口。',
|
|
backstory: '他在港口旧案里失去过同伴。',
|
|
personality: '谨慎克制。',
|
|
motivation: '想查清货船去向。',
|
|
combatStyle: '借地形换位。',
|
|
initialAffinity: 20,
|
|
relationshipHooks: ['旧案'],
|
|
tags: ['港口'],
|
|
backstoryReveal: {
|
|
publicSummary: '他对港口格外熟悉。',
|
|
chapters: [],
|
|
},
|
|
skills: [],
|
|
initialItems: [],
|
|
imageSrc: '/images/roles/linchao.webp',
|
|
},
|
|
],
|
|
storyNpcs: [],
|
|
items: [],
|
|
camp: {
|
|
id: 'camp-1',
|
|
name: '守夜营地',
|
|
description: '潮线后的临时据点。',
|
|
imageSrc: '/images/camp/camp.webp',
|
|
sceneNpcIds: [],
|
|
connections: [],
|
|
},
|
|
landmarks: [
|
|
{
|
|
id: 'landmark-1',
|
|
name: '潮汐码头',
|
|
description: '涨潮时会吞掉半截栈桥。',
|
|
imageSrc: '/images/landmark/docks.webp',
|
|
sceneNpcIds: [],
|
|
connections: [],
|
|
},
|
|
],
|
|
sceneChapterBlueprints: [
|
|
{
|
|
id: 'scene-chapter-1',
|
|
sceneId: 'landmark-1',
|
|
title: '潮汐码头',
|
|
summary: '第一章开局场景。',
|
|
sceneTaskDescription: '追查潮汐码头失踪案的第一条线索。',
|
|
linkedThreadIds: [],
|
|
linkedLandmarkIds: ['landmark-1'],
|
|
acts: [
|
|
{
|
|
id: 'act-1',
|
|
sceneId: 'landmark-1',
|
|
title: '雾里靠岸',
|
|
summary: '玩家第一次进入港口。',
|
|
stageCoverage: ['opening'],
|
|
backgroundImageSrc: '/images/scene/act-1.webp',
|
|
backgroundAssetId: 'asset-scene-act-1',
|
|
encounterNpcIds: [],
|
|
primaryNpcId: 'playable-1',
|
|
oppositeNpcId: 'playable-1',
|
|
eventDescription: '玩家第一次进入港口,发现涨潮后的异常痕迹。',
|
|
linkedThreadIds: [],
|
|
advanceRule: 'after_primary_contact',
|
|
actGoal: '拿到第一句真话。',
|
|
transitionHook: '下一幕将进入封锁区。',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
describe('resolveCustomWorldCoverPresentation', () => {
|
|
it('优先使用开局场景第一幕图片作为默认封面底图', () => {
|
|
const profile = createBaseProfile();
|
|
|
|
const result = resolveCustomWorldCoverPresentation(profile);
|
|
|
|
expect(result.imageSrc).toBe('/images/scene/act-1.webp');
|
|
expect(result.renderMode).toBe('scene_with_roles');
|
|
expect(result.characterImageSrcs).toEqual(['/images/roles/linchao.webp']);
|
|
});
|
|
|
|
it('当第一幕图片缺失时按营地图与地标图顺序回退', () => {
|
|
const profile = createBaseProfile();
|
|
const firstSceneChapter = profile.sceneChapterBlueprints?.[0];
|
|
const firstSceneAct = firstSceneChapter?.acts[0];
|
|
if (!firstSceneChapter || !firstSceneAct) {
|
|
throw new Error('expected base profile to provide an opening scene chapter');
|
|
}
|
|
profile.sceneChapterBlueprints = [
|
|
{
|
|
...firstSceneChapter,
|
|
acts: [
|
|
{
|
|
...firstSceneAct,
|
|
backgroundImageSrc: null,
|
|
backgroundAssetId: null,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const fallbackToCamp = resolveCustomWorldCoverPresentation(profile);
|
|
expect(fallbackToCamp.imageSrc).toBe('/images/camp/camp.webp');
|
|
|
|
profile.camp = {
|
|
...profile.camp!,
|
|
imageSrc: '',
|
|
};
|
|
const fallbackToLandmark = resolveCustomWorldCoverPresentation(profile);
|
|
expect(fallbackToLandmark.imageSrc).toBe('/images/landmark/docks.webp');
|
|
});
|
|
});
|