This commit is contained in:
120
src/services/customWorldCamp.ts
Normal file
120
src/services/customWorldCamp.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user