feat: connect prologue choices to first battle

This commit is contained in:
2026-07-27 03:21:37 +09:00
parent 40dca5321e
commit a726ba129f
10 changed files with 1437 additions and 60 deletions

View File

@@ -29,6 +29,7 @@ const expectedCampMarkerIds = [
'prologue-camp-inspect-arms',
'prologue-camp-complete'
];
const expectedFirstCommandOrderIds = ['elite', 'mobile', 'siege'];
const server = await createServer({
logLevel: 'error',
@@ -39,6 +40,7 @@ const server = await createServer({
try {
const village = await server.ssrLoadModule('/src/game/data/prologueVillage.ts');
const militiaCamp = await server.ssrLoadModule('/src/game/data/prologueMilitiaCamp.ts');
const sortieOrders = await server.ssrLoadModule('/src/game/data/sortieOrders.ts');
const campaign = await server.ssrLoadModule('/src/game/state/campaignState.ts');
const unitAssets = await server.ssrLoadModule('/src/game/data/unitAssets.ts');
const failures = [];
@@ -178,6 +180,58 @@ try {
'militia camp must have Zou Jing as the single final command interaction',
failures
);
const firstCommandChoices = militiaCamp.prologueMilitiaCampCommandChoices;
assertArrayEquals(
firstCommandChoices.map((choice) => choice.orderId),
expectedFirstCommandOrderIds,
'first command choice order',
failures
);
assert(
new Set(firstCommandChoices.map((choice) => choice.orderId)).size ===
expectedFirstCommandOrderIds.length,
'the first command choices must cover three unique sortie orders',
failures
);
for (const choice of firstCommandChoices) {
const definition = sortieOrders.sortieOrderDefinition(choice.orderId);
assert(
definition.id === choice.orderId &&
definition.rewardGold > 0 &&
definition.rewardItems.length > 0,
`first command ${choice.orderId} must reuse a complete battle order definition`,
failures
);
assert(
choice.label === sortieOrders.sortieOrderDisplayLabel(
'first-battle-zhuo-commandery',
choice.orderId
) &&
choice.lead.length >= 8 &&
choice.battlefieldPromise.length >= 20 &&
choice.firstBattleCondition.length >= 20,
`first command ${choice.orderId} must explain its player value and battlefield promise`,
failures
);
assert(
choice.reaction.length === 3 &&
choice.reaction.some((line) => line.speaker === '관우') &&
choice.reaction.some((line) => line.speaker === '장비'),
`first command ${choice.orderId} must receive distinct Guan Yu and Zhang Fei reactions`,
failures
);
verifyDialogueLines(
choice.reaction,
`militia camp/first-command/${choice.orderId}`,
unitAssets,
failures
);
}
assert(
campNpcs.find((npc) => npc.id === 'zou-jing')?.dialogue.length === 1,
'Zou Jing command setup should be compressed to one line so the new decision adds no extra input',
failures
);
assert(
campNpcs.some((npc) => !npc.objectiveId && !npc.departure),
'militia camp should include at least one optional volunteer conversation',
@@ -234,7 +288,7 @@ try {
console.log(
`Verified ${npcs.length} village NPCs, ${campNpcs.length} militia camp NPCs, ` +
`${openingPages.length + brotherhoodPages.length + departurePages.length} prologue story pages, ` +
'sequential meetings, camp preparation, and save markers.'
`${firstCommandChoices.length} first-command choices, sequential meetings, camp preparation, and save markers.`
);
} finally {
await server.close();