Add Xuzhou rescue sortie flow

This commit is contained in:
2026-06-23 00:45:22 +09:00
parent 84a5606a73
commit 87b200d772
11 changed files with 929 additions and 43 deletions

View File

@@ -749,16 +749,119 @@ try {
await page.waitForTimeout(160);
const sixthCampSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (!sixthCampSortieState?.sortieVisible) {
throw new Error(`Expected sixth camp story bridge overlay: ${JSON.stringify(sixthCampSortieState)}`);
throw new Error(`Expected sixth camp sortie preparation overlay: ${JSON.stringify(sixthCampSortieState)}`);
}
if (!sixthCampSortieState.selectedSortieUnitIds?.includes('liu-bei') || sixthCampSortieState.selectedSortieUnitIds.length < 3) {
throw new Error(`Expected sortie prep to default to the core brother roster: ${JSON.stringify(sixthCampSortieState)}`);
}
await page.mouse.click(254, 450);
await page.waitForTimeout(220);
const sixthCampAfterSortieToggle = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!sixthCampAfterSortieToggle?.sortieVisible ||
sixthCampAfterSortieToggle.selectedSortieUnitIds?.includes('guan-yu') ||
!sixthCampAfterSortieToggle.selectedSortieUnitIds?.includes('liu-bei') ||
!sixthCampAfterSortieToggle.selectedSortieUnitIds?.includes('zhang-fei')
) {
throw new Error(`Expected sortie selection toggle to bench Guan Yu while keeping Liu Bei/Zhang Fei: ${JSON.stringify(sixthCampAfterSortieToggle)}`);
}
await page.mouse.click(938, 596);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
});
await page.screenshot({ path: 'dist/verification-xuzhou-bridge-story.png', fullPage: true });
await page.screenshot({ path: 'dist/verification-seventh-bridge-story.png', fullPage: true });
for (let i = 0; i < 4; i += 1) {
for (let i = 0; i < 30; i += 1) {
const isSeventhBattleActive = await page.evaluate(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'seventh-battle-xuzhou-rescue';
});
if (isSeventhBattleActive) {
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 === 'seventh-battle-xuzhou-rescue' && state?.battleOutcome === null && state?.phase === 'idle';
});
await page.screenshot({ path: 'dist/verification-seventh-battle.png', fullPage: true });
const seventhBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
const seventhEnemies = seventhBattleState.units.filter((unit) => unit.faction === 'enemy');
const seventhAllies = seventhBattleState.units.filter((unit) => unit.faction === 'ally');
const seventhEnemyBehaviors = new Set(seventhEnemies.map((unit) => unit.ai));
if (
seventhBattleState.camera?.mapWidth !== 24 ||
seventhBattleState.camera?.mapHeight !== 20 ||
seventhBattleState.victoryConditionLabel !== '하후돈 격파' ||
seventhEnemies.length < 12 ||
!seventhEnemyBehaviors.has('aggressive') ||
!seventhEnemyBehaviors.has('guard') ||
!seventhEnemyBehaviors.has('hold') ||
seventhAllies.some((unit) => unit.id === 'guan-yu') ||
!seventhAllies.some((unit) => unit.id === 'liu-bei') ||
!seventhAllies.some((unit) => unit.id === 'zhang-fei')
) {
throw new Error(`Expected seventh battle map, objective, mixed AI, and saved sortie selection: ${JSON.stringify(seventhBattleState)}`);
}
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 campaignSaveAfterSeventhBattle = await page.evaluate(() => {
const raw = window.localStorage.getItem('heros-web:campaign-state');
return raw ? JSON.parse(raw) : undefined;
});
if (
!campaignSaveAfterSeventhBattle ||
campaignSaveAfterSeventhBattle.step !== 'seventh-camp' ||
campaignSaveAfterSeventhBattle.latestBattleId !== 'seventh-battle-xuzhou-rescue' ||
!campaignSaveAfterSeventhBattle.battleHistory?.['seventh-battle-xuzhou-rescue'] ||
!campaignSaveAfterSeventhBattle.roster?.some((unit) => unit.id === 'guan-yu')
) {
throw new Error(`Expected campaign save to persist seventh battle victory and preserve benched roster: ${JSON.stringify(campaignSaveAfterSeventhBattle)}`);
}
const seventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
seventhCampState?.campBattleId !== 'seventh-battle-xuzhou-rescue' ||
seventhCampState.campTitle !== '서주 인수 준비 군영' ||
seventhCampState.availableDialogueIds?.length !== 3 ||
!seventhCampState.availableDialogueIds.every((id) => id.endsWith('xuzhou')) ||
!seventhCampState.campaign?.roster?.some((unit) => unit.id === 'guan-yu')
) {
throw new Error(`Expected seventh camp to expose Xu Province dialogue set and preserved roster: ${JSON.stringify(seventhCampState)}`);
}
await page.mouse.click(1120, 38);
await page.waitForTimeout(160);
const seventhCampSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (!seventhCampSortieState?.sortieVisible) {
throw new Error(`Expected seventh camp story bridge overlay: ${JSON.stringify(seventhCampSortieState)}`);
}
await page.mouse.click(938, 596);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
});
await page.screenshot({ path: 'dist/verification-xuzhou-entrust-story.png', fullPage: true });
for (let i = 0; i < 8; i += 1) {
const returnedToCamp = await page.evaluate(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('CampScene');
@@ -785,7 +888,7 @@ try {
return activeScenes.includes('CampScene');
});
console.log(`Verified title-to-sixth-battle flow, result states, and debug API at ${targetUrl}`);
console.log(`Verified title-to-seventh-battle flow, sortie selection, result states, and debug API at ${targetUrl}`);
} finally {
await browser?.close();
if (serverProcess && !serverProcess.killed) {