127 lines
3.9 KiB
TypeScript
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;
|
|
}
|