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, }; }