Files
Genarrative/src/services/attributeSchemaGenerator.ts
2026-04-28 20:25:37 +08:00

127 lines
3.9 KiB
TypeScript

import {validateWorldAttributeSchema} from '../data/attributeValidation';
import {getTemplateWorldAttributeSchema} from '../data/worldAttributeSchemas';
import type {
AttributeSchemaGenerationInput,
WorldAttributeSchema,
WorldAttributeSlot,
} from '../types';
import {WorldType} from '../types';
import {detectCustomWorldThemeMode} from './customWorldTheme';
function buildSchema(
input: AttributeSchemaGenerationInput,
slots: WorldAttributeSlot[],
): WorldAttributeSchema {
return {
id: `schema:${input.worldType.toLowerCase()}:${input.worldName}`,
worldId: input.worldType === WorldType.CUSTOM ? `custom:${input.worldName}` : input.worldType,
schemaVersion: 1,
generatedFrom: {
worldType: input.worldType,
worldName: input.worldName,
settingSummary: input.summary,
tone: input.tone,
conflictCore: input.coreConflicts[0] ?? input.playerGoal,
},
slots,
};
}
function buildCustomThemeSlots(input: AttributeSchemaGenerationInput) {
const themeMode = detectCustomWorldThemeMode({
settingText: input.settingText,
summary: input.summary,
tone: input.tone,
playerGoal: input.playerGoal,
templateWorldType: /||||/u.test(input.settingText) ? WorldType.XIANXIA : WorldType.WUXIA,
});
if (themeMode === 'mythic') {
return {
slots: [
{ slotId: 'axis_a', name: '体魄' },
{ slotId: 'axis_b', name: '身法' },
{ slotId: 'axis_c', name: '识见' },
{ slotId: 'axis_d', name: '胆魄' },
{ slotId: 'axis_e', name: '牵引' },
{ slotId: 'axis_f', name: '定力' },
] satisfies WorldAttributeSlot[],
};
}
if (themeMode === 'machina') {
return {
slots: [
{ slotId: 'axis_a', name: '机锋' },
{ slotId: 'axis_b', name: '步准' },
{ slotId: 'axis_c', name: '算识' },
{ slotId: 'axis_d', name: '潮压' },
{ slotId: 'axis_e', name: '协频' },
{ slotId: 'axis_f', name: '续载' },
] satisfies WorldAttributeSlot[],
};
}
if (themeMode === 'tide') {
return {
slots: [
{ slotId: 'axis_a', name: '潮骨' },
{ slotId: 'axis_b', name: '浪步' },
{ slotId: 'axis_c', name: '舟识' },
{ slotId: 'axis_d', name: '潮魄' },
{ slotId: 'axis_e', name: '契汐' },
{ slotId: 'axis_f', name: '回澜' },
] satisfies WorldAttributeSlot[],
};
}
if (themeMode === 'rift') {
return {
slots: [
{ slotId: 'axis_a', name: '界躯' },
{ slotId: 'axis_b', name: '裂步' },
{ slotId: 'axis_c', name: '界识' },
{ slotId: 'axis_d', name: '界压' },
{ slotId: 'axis_e', name: '缚契' },
{ slotId: 'axis_f', name: '回脉' },
] satisfies WorldAttributeSlot[],
};
}
return {
slots: getTemplateWorldAttributeSchema(WorldType.WUXIA).slots,
};
}
export function generateWorldAttributeSchema(input: AttributeSchemaGenerationInput) {
if (input.worldType === WorldType.WUXIA) {
return getTemplateWorldAttributeSchema(WorldType.WUXIA);
}
if (input.worldType === WorldType.XIANXIA) {
return getTemplateWorldAttributeSchema(WorldType.XIANXIA);
}
const generated = buildCustomThemeSlots(input);
const schema = buildSchema(input, generated.slots);
const issues = validateWorldAttributeSchema(schema);
if (issues.length > 0) {
const fallbackWorldType = /||||/u.test(input.settingText) ? WorldType.XIANXIA : WorldType.WUXIA;
return {
...getTemplateWorldAttributeSchema(fallbackWorldType),
id: `schema:custom-fallback:${input.worldName}`,
worldId: `custom:${input.worldName}`,
generatedFrom: {
worldType: WorldType.CUSTOM,
worldName: input.worldName,
settingSummary: input.summary,
tone: input.tone,
conflictCore: input.coreConflicts[0] ?? input.playerGoal,
},
};
}
return schema;
}