Files
heros_web/scripts/verify-prologue-village-data.mjs

161 lines
4.8 KiB
JavaScript

import { createServer } from 'vite';
const expectedOpeningPageIds = ['yellow-turban-chaos', 'liu-bei-resolve'];
const expectedDeparturePageIds = [
'first-sortie',
'yellow-turban-nearby',
'first-battle-plan-talk',
'battle-briefing'
];
const expectedRequiredObjectiveIds = [
'meet-zhang-fei',
'meet-guan-yu',
'check-supplies'
];
const expectedCampaignMarkerIds = [
'prologue-village-entered',
'prologue-village-meet-zhang-fei',
'prologue-village-meet-guan-yu',
'prologue-village-check-supplies',
'prologue-village-complete'
];
const server = await createServer({
logLevel: 'error',
server: { middlewareMode: true },
appType: 'custom'
});
try {
const village = await server.ssrLoadModule('/src/game/data/prologueVillage.ts');
const campaign = await server.ssrLoadModule('/src/game/state/campaignState.ts');
const unitAssets = await server.ssrLoadModule('/src/game/data/unitAssets.ts');
const failures = [];
const openingPages = village.prologueOpeningPages();
const departurePages = village.prologueDeparturePages();
assertArrayEquals(
openingPages.map((page) => page.id),
expectedOpeningPageIds,
'opening story page order',
failures
);
assertArrayEquals(
departurePages.map((page) => page.id),
expectedDeparturePageIds,
'departure story page order',
failures
);
assertArrayEquals(
[...village.prologueVillageRequiredObjectiveIds],
expectedRequiredObjectiveIds,
'required objective order',
failures
);
const objectives = village.prologueVillageObjectiveDefinitions;
assert(objectives.length === 4, `expected 4 objective rows, received ${objectives.length}`, failures);
assert(
new Set(objectives.map((objective) => objective.id)).size === objectives.length,
'objective ids must be unique',
failures
);
assert(
objectives.at(-1)?.id === 'make-oath',
'the final objective must be make-oath',
failures
);
const npcs = village.prologueVillageNpcDefinitions;
const objectiveNpcIds = npcs
.filter((npc) => npc.objectiveId)
.map((npc) => npc.objectiveId);
assertArrayEquals(
[...objectiveNpcIds].sort(),
[...expectedRequiredObjectiveIds].sort(),
'required NPC objective coverage',
failures
);
assert(
new Set(npcs.map((npc) => npc.id)).size === npcs.length,
'NPC ids must be unique',
failures
);
assert(npcs.some((npc) => !npc.objectiveId), 'at least one optional villager should be available', failures);
for (const npc of npcs) {
assert(
Number.isFinite(npc.x) && npc.x >= 70 && npc.x <= 1435 &&
Number.isFinite(npc.y) && npc.y >= 130 && npc.y <= 900,
`${npc.id}: position must remain inside the FHD village play area`,
failures
);
assert(unitAssets.hasUnitSheetAsset(npc.textureKey), `${npc.id}: missing ${npc.textureKey}`, failures);
assert(Array.isArray(npc.dialogue) && npc.dialogue.length > 0, `${npc.id}: dialogue is required`, failures);
for (const [lineIndex, line] of npc.dialogue.entries()) {
assert(
typeof line.speaker === 'string' && line.speaker.trim().length > 0,
`${npc.id}[${lineIndex}]: speaker is required`,
failures
);
assert(
typeof line.text === 'string' && line.text.trim().length >= 8 && line.text.length <= 180,
`${npc.id}[${lineIndex}]: dialogue must be 8-180 characters`,
failures
);
if (line.textureKey) {
assert(
unitAssets.hasUnitSheetAsset(line.textureKey),
`${npc.id}[${lineIndex}]: missing dialogue sprite ${line.textureKey}`,
failures
);
}
}
}
assert(
unitAssets.hasUnitSheetAsset('unit-liu-bei'),
'the controllable Liu Bei base sheet is required',
failures
);
assertArrayEquals(
Object.values(campaign.prologueVillageCampaignTutorialIds),
expectedCampaignMarkerIds,
'campaign progress marker ids',
failures
);
assert(
expectedCampaignMarkerIds.every((id) => campaign.campaignTutorialIds.includes(id)),
'every village marker must survive campaign save normalization',
failures
);
if (failures.length > 0) {
throw new Error(
`Prologue village data verification failed with ${failures.length} issue(s):\n` +
failures.map((failure) => `- ${failure}`).join('\n')
);
}
console.log(
`Verified ${npcs.length} village NPCs, ${expectedRequiredObjectiveIds.length} required interactions, ` +
`${openingPages.length} opening pages, ${departurePages.length} departure pages, and save markers.`
);
} finally {
await server.close();
}
function assert(condition, message, failures) {
if (!condition) {
failures.push(message);
}
}
function assertArrayEquals(actual, expected, label, failures) {
assert(
JSON.stringify(actual) === JSON.stringify(expected),
`${label}: expected [${expected.join(', ')}], received [${actual.join(', ')}]`,
failures
);
}