Add Xiapi final sortie chapter

This commit is contained in:
2026-06-23 03:43:53 +09:00
parent 450842bd28
commit 3cdbbe8d5a
12 changed files with 905 additions and 23 deletions

View File

@@ -1257,6 +1257,93 @@ try {
throw new Error(`Expected twelfth camp to expose Xiapi siege dialogue set and preserve full roster: ${JSON.stringify(twelfthCampState)}`);
}
await page.mouse.click(1120, 38);
await page.waitForTimeout(160);
const twelfthCampSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!twelfthCampSortieState?.sortieVisible ||
!twelfthCampSortieState.sortiePlan?.objectiveLine?.includes('하비 결전') ||
twelfthCampSortieState.sortiePlan?.selectedRecruitedCount < 1 ||
!twelfthCampSortieState.sortiePlan?.recruitedLine?.includes('합류 무장')
) {
throw new Error(`Expected twelfth camp sortie prep to target Xiapi final battle with recruit selection summary: ${JSON.stringify(twelfthCampSortieState)}`);
}
assertSortieTacticalRoster(twelfthCampSortieState, ['liu-bei', 'guan-yu', 'zhang-fei', 'jian-yong', 'mi-zhu']);
if (!twelfthCampSortieState.sortieRoster.some((unit) => unit.id === 'jian-yong' && unit.recruited)) {
throw new Error(`Expected recruit officers to be marked in sortie roster: ${JSON.stringify(twelfthCampSortieState.sortieRoster)}`);
}
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
});
await page.screenshot({ path: 'dist/verification-xiapi-final-story.png', fullPage: true });
for (let i = 0; i < 18; i += 1) {
const enteredThirteenthBattle = await page.evaluate(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'thirteenth-battle-xiapi-final';
});
if (enteredThirteenthBattle) {
break;
}
await page.keyboard.press('Space');
await page.waitForTimeout(320);
}
await page.waitForFunction(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'thirteenth-battle-xiapi-final' && state?.battleOutcome === null && state?.phase === 'idle';
});
await page.screenshot({ path: 'dist/verification-thirteenth-battle.png', fullPage: true });
const thirteenthBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
const thirteenthEnemies = thirteenthBattleState.units.filter((unit) => unit.faction === 'enemy');
const thirteenthAllies = thirteenthBattleState.units.filter((unit) => unit.faction === 'ally');
const thirteenthEnemyBehaviors = new Set(thirteenthEnemies.map((unit) => unit.ai));
if (
thirteenthBattleState.camera?.mapWidth !== 32 ||
thirteenthBattleState.camera?.mapHeight !== 24 ||
thirteenthBattleState.victoryConditionLabel !== '여포 격파' ||
thirteenthEnemies.length < 15 ||
!thirteenthEnemyBehaviors.has('aggressive') ||
!thirteenthEnemyBehaviors.has('guard') ||
!thirteenthEnemyBehaviors.has('hold') ||
!thirteenthEnemies.some((unit) => unit.id === 'xiapi-final-leader-lu-bu') ||
!thirteenthEnemies.some((unit) => unit.id === 'xiapi-final-strategist-chen-gong') ||
!thirteenthAllies.some((unit) => unit.id === 'liu-bei') ||
!thirteenthAllies.some((unit) => unit.id === 'guan-yu') ||
!thirteenthAllies.some((unit) => unit.id === 'zhang-fei') ||
!thirteenthAllies.some((unit) => unit.id === 'jian-yong') ||
!thirteenthAllies.some((unit) => unit.id === 'mi-zhu')
) {
throw new Error(`Expected thirteenth battle to use Xiapi final map, Lu Bu objective, mixed AI, and selected recruit sortie: ${JSON.stringify(thirteenthBattleState)}`);
}
await page.evaluate(() => window.__HEROS_DEBUG__?.forceBattleOutcome('victory'));
await page.waitForFunction(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.battleOutcome === 'victory' && state?.phase === 'resolved' && state?.resultVisible === true;
});
await page.mouse.click(738, 642);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('CampScene');
});
const thirteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
thirteenthCampState?.campBattleId !== 'thirteenth-battle-xiapi-final' ||
thirteenthCampState.campTitle !== '하비 결전 후 군영' ||
thirteenthCampState.availableDialogueIds?.length !== 3 ||
!thirteenthCampState.availableDialogueIds.every((id) => id.endsWith('lu-bu-fall')) ||
!thirteenthCampState.campaign?.roster?.some((unit) => unit.id === 'guan-yu') ||
!thirteenthCampState.campaign?.roster?.some((unit) => unit.id === 'jian-yong') ||
!thirteenthCampState.campaign?.roster?.some((unit) => unit.id === 'mi-zhu')
) {
throw new Error(`Expected thirteenth camp to expose Lu Bu fall dialogue set and preserve full roster: ${JSON.stringify(thirteenthCampState)}`);
}
await page.evaluate(() => window.__HEROS_GAME__?.scene.start('TitleScene'));
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
@@ -1268,7 +1355,7 @@ try {
return activeScenes.includes('CampScene');
});
console.log(`Verified title-to-twelfth-battle flow, recruit sortie selection, result states, and debug API at ${targetUrl}`);
console.log(`Verified title-to-thirteenth-battle flow, recruit sortie selection, result states, and debug API at ${targetUrl}`);
} finally {
await browser?.close();
if (serverProcess && !serverProcess.killed) {