Validate battle tactical guide data

This commit is contained in:
2026-07-05 19:24:12 +09:00
parent 3f3a8e2d04
commit ccccedc671

View File

@@ -20,6 +20,15 @@ try {
const itemKeys = new Set(Object.keys(itemCatalog));
const itemNames = new Set(Object.values(itemCatalog).map((item) => item.name));
const formationRoles = new Set(sortieFormationRoles);
const tacticalGuideEventKeys = new Set([
'leader-wavering',
'ally-danger',
'village-approach',
'village-secured',
'vanguard-broken',
'cavalry-approach',
'enemy-posture'
]);
const knownRewardUnitIds = new Set([
...scenarioEntries.flatMap(([, scenario]) => scenario.units.map((unit) => unit.id)),
...(campaignRecruitUnits ?? []).map((unit) => unit.id)
@@ -38,6 +47,7 @@ try {
validateMap(errors, scenario, terrainKeys, context);
validateUnits(errors, scenario, classKeys, itemKeys, equipmentSlots, context);
validateObjectives(errors, scenario, context);
validateTacticalGuide(errors, scenario, tacticalGuideEventKeys, context);
validateSortie(errors, scenario, classKeys, formationRoles, terrainRules, context);
validateRewards(errors, scenario, scenarioIds, itemNames, knownRewardUnitIds, context);
});
@@ -55,8 +65,9 @@ try {
(total, [, scenario]) => total + scenario.itemRewards.length + campaignRewardLabelCount(scenario.campaignReward),
0
);
const tacticalGuideCount = scenarioEntries.reduce((total, [, scenario]) => total + (scenario.tacticalGuide ? 1 : 0), 0);
console.log(
`Verified ${scenarioEntries.length} battle scenarios, ${unitCount} unit placements, maps, objectives, sortie data, equipment, and ${rewardCount} reward labels.`
`Verified ${scenarioEntries.length} battle scenarios, ${unitCount} unit placements, maps, objectives, sortie data, ${tacticalGuideCount} tactical guides, equipment, and ${rewardCount} reward labels.`
);
}
} finally {
@@ -190,6 +201,52 @@ function validateObjectives(errors, scenario, context) {
});
}
function validateTacticalGuide(errors, scenario, eventKeys, context) {
const guide = scenario.tacticalGuide;
if (!guide) {
return;
}
assertNonEmptyString(errors, guide.summary, `${context}: tacticalGuide summary`);
assertNonEmptyString(errors, guide.route, `${context}: tacticalGuide route`);
assertNonEmptyString(errors, guide.focus, `${context}: tacticalGuide focus`);
if (!Array.isArray(guide.roles) || guide.roles.length === 0) {
errors.push(`${context}: tacticalGuide roles must include at least one role`);
} else {
guide.roles.forEach((role, index) => {
assertNonEmptyString(errors, role, `${context}: tacticalGuide roles[${index}]`);
});
}
if (guide.events === undefined) {
return;
}
if (!guide.events || typeof guide.events !== 'object' || Array.isArray(guide.events)) {
errors.push(`${context}: tacticalGuide events must be an object`);
return;
}
Object.entries(guide.events).forEach(([eventKey, event]) => {
if (!eventKeys.has(eventKey)) {
errors.push(`${context}: tacticalGuide event "${eventKey}" is not supported`);
}
if (!event || typeof event !== 'object' || Array.isArray(event)) {
errors.push(`${context}: tacticalGuide event "${eventKey}" must be an object`);
return;
}
assertNonEmptyString(errors, event.title, `${context}: tacticalGuide event "${eventKey}" title`);
if (!Array.isArray(event.lines) || event.lines.length === 0) {
errors.push(`${context}: tacticalGuide event "${eventKey}" must include at least one line`);
return;
}
event.lines.forEach((line, index) => {
assertNonEmptyString(errors, line, `${context}: tacticalGuide event "${eventKey}" lines[${index}]`);
});
});
}
function validateCharacterProgress(errors, unit, context) {
if (!Number.isInteger(unit.level) || unit.level < 1) {
errors.push(`${context}: invalid level ${unit.level}`);