121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
import {
|
|
type CustomWorldCampScene,
|
|
type CustomWorldProfile,
|
|
} from '../types';
|
|
import { detectCustomWorldThemeMode } from './customWorldTheme';
|
|
|
|
type CampProfileSeed = Pick<
|
|
CustomWorldProfile,
|
|
'name' | 'summary' | 'tone' | 'playerGoal' | 'settingText' | 'templateWorldType'
|
|
> & {
|
|
camp?: Pick<
|
|
CustomWorldCampScene,
|
|
| 'id'
|
|
| 'name'
|
|
| 'description'
|
|
| 'visualDescription'
|
|
| 'imageSrc'
|
|
| 'sceneNpcIds'
|
|
| 'connections'
|
|
| 'narrativeResidues'
|
|
> | null;
|
|
};
|
|
|
|
function clampText(value: string, maxLength: number) {
|
|
const normalized = value.trim().replace(/\s+/g, ' ');
|
|
if (!normalized) {
|
|
return '';
|
|
}
|
|
if (normalized.length <= maxLength) {
|
|
return normalized;
|
|
}
|
|
return `${normalized.slice(0, Math.max(0, maxLength - 1)).trim()}…`;
|
|
}
|
|
|
|
function sanitizeCampSeed(name: string) {
|
|
const normalized = name.trim().replace(/\s+/g, '');
|
|
if (!normalized) {
|
|
return '';
|
|
}
|
|
|
|
const stripped = normalized.replace(
|
|
/(世界|江湖|边城|仙洲|仙境|灵境|界|录|域|境)$/u,
|
|
'',
|
|
);
|
|
const seed = stripped || normalized;
|
|
|
|
return seed.slice(0, Math.min(seed.length, 4));
|
|
}
|
|
|
|
function buildFallbackCampName(profile: CampProfileSeed) {
|
|
const seed =
|
|
sanitizeCampSeed(profile.name) ||
|
|
'归途';
|
|
const themeMode = detectCustomWorldThemeMode(profile);
|
|
|
|
const suffixByMode = {
|
|
mythic: '归舍',
|
|
martial: '归舍',
|
|
arcane: '栖居',
|
|
machina: '整备居',
|
|
tide: '潮居',
|
|
rift: '界隙居所',
|
|
} as const;
|
|
|
|
return `${seed}${suffixByMode[themeMode]}`;
|
|
}
|
|
|
|
function buildFallbackCampDescription(profile: CampProfileSeed, campName: string) {
|
|
const summaryLead = clampText(profile.summary, 24) || '前路尚未明朗';
|
|
const goalLead = clampText(profile.playerGoal, 24) || '继续整理线索';
|
|
const themeMode = detectCustomWorldThemeMode(profile);
|
|
|
|
const descriptionByMode = {
|
|
mythic: `${campName}是你在${profile.name}暂时安顿的归处,能整备行装、交换判断,并围绕“${goalLead}”继续启程。`,
|
|
martial: `${campName}是你在${profile.name}暂时落脚的归处,能整备行装、收拢同伴,并朝“${goalLead}”继续动身。`,
|
|
arcane: `${campName}是你在${profile.name}暂时栖身的居所,适合调息、整理法器,并围绕“${summaryLead}”交换判断。`,
|
|
machina: `${campName}是你在${profile.name}的临时居所,能检修装备、补齐物资,并为下一段行动重新校准节奏。`,
|
|
tide: `${campName}是你在${profile.name}靠潮歇息的住处,能安顿队伍、整理补给,并顺着“${goalLead}”继续前探。`,
|
|
rift: `${campName}是你在${profile.name}勉强守住的一处居所,既能短暂停步,也能围绕“${summaryLead}”商量下一步去向。`,
|
|
} as const;
|
|
|
|
return descriptionByMode[themeMode];
|
|
}
|
|
|
|
export function buildFallbackCustomWorldCampScene(
|
|
profile: CampProfileSeed,
|
|
): CustomWorldCampScene {
|
|
const fallbackName = buildFallbackCampName(profile);
|
|
|
|
return {
|
|
id: 'custom-scene-camp',
|
|
name: fallbackName,
|
|
description: buildFallbackCampDescription(profile, fallbackName),
|
|
sceneNpcIds: [],
|
|
connections: [],
|
|
narrativeResidues: null,
|
|
};
|
|
}
|
|
|
|
export function resolveCustomWorldCampScene(
|
|
profile: CampProfileSeed,
|
|
): CustomWorldCampScene {
|
|
const fallback = buildFallbackCustomWorldCampScene(profile);
|
|
const camp = profile.camp;
|
|
|
|
return {
|
|
id: camp?.id?.trim() || fallback.id,
|
|
name: camp?.name?.trim() || fallback.name,
|
|
description: camp?.description?.trim() || fallback.description,
|
|
visualDescription: camp?.visualDescription?.trim() || undefined,
|
|
imageSrc: camp?.imageSrc?.trim() || undefined,
|
|
sceneNpcIds: Array.isArray(camp?.sceneNpcIds)
|
|
? [...new Set(camp.sceneNpcIds.map((entry) => entry.trim()).filter(Boolean))]
|
|
: fallback.sceneNpcIds,
|
|
connections: Array.isArray(camp?.connections)
|
|
? camp.connections
|
|
: fallback.connections,
|
|
narrativeResidues: camp?.narrativeResidues ?? fallback.narrativeResidues,
|
|
};
|
|
}
|