Add Red Cliffs fire attack chapter

This commit is contained in:
2026-06-23 07:15:43 +09:00
parent 7f80600d0c
commit 302f0e0a76
11 changed files with 1059 additions and 24 deletions

View File

@@ -1736,7 +1736,7 @@ try {
if (
progressTabState?.activeTab !== 'progress' ||
progressTabState.campaignProgress?.completedKnown !== 17 ||
progressTabState.campaignProgress?.totalKnown !== 21 ||
progressTabState.campaignProgress?.totalKnown !== 22 ||
progressTabState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
progressTabState.campaignProgress?.latestBattleTitle !== '융중 방문로' ||
progressTabState.campaignProgress?.nextBattleTitle !== '박망파 매복전'
@@ -1888,7 +1888,7 @@ try {
if (
postBowangProgressState?.activeTab !== 'progress' ||
postBowangProgressState.campaignProgress?.completedKnown !== 18 ||
postBowangProgressState.campaignProgress?.totalKnown !== 21 ||
postBowangProgressState.campaignProgress?.totalKnown !== 22 ||
postBowangProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postBowangProgressState.campaignProgress?.latestBattleTitle !== '박망파 매복전' ||
postBowangProgressState.campaignProgress?.nextBattleTitle !== '장판파 피난로'
@@ -2026,7 +2026,7 @@ try {
if (
postChangbanProgressState?.activeTab !== 'progress' ||
postChangbanProgressState.campaignProgress?.completedKnown !== 19 ||
postChangbanProgressState.campaignProgress?.totalKnown !== 21 ||
postChangbanProgressState.campaignProgress?.totalKnown !== 22 ||
postChangbanProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postChangbanProgressState.campaignProgress?.latestBattleTitle !== '장판파 피난로' ||
postChangbanProgressState.campaignProgress?.nextBattleTitle !== '강동 사절로'
@@ -2164,7 +2164,7 @@ try {
if (
postJiangdongProgressState?.activeTab !== 'progress' ||
postJiangdongProgressState.campaignProgress?.completedKnown !== 20 ||
postJiangdongProgressState.campaignProgress?.totalKnown !== 21 ||
postJiangdongProgressState.campaignProgress?.totalKnown !== 22 ||
postJiangdongProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postJiangdongProgressState.campaignProgress?.latestBattleTitle !== '강동 사절로' ||
postJiangdongProgressState.campaignProgress?.nextBattleTitle !== '적벽 전초전'
@@ -2304,15 +2304,155 @@ try {
if (
postRedCliffsProgressState?.activeTab !== 'progress' ||
postRedCliffsProgressState.campaignProgress?.completedKnown !== 21 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 21 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 22 ||
postRedCliffsProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postRedCliffsProgressState.campaignProgress?.latestBattleTitle !== '적벽 전초전' ||
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '적벽 화공전'
) {
throw new Error(`Expected post-Red Cliffs vanguard progress tab to complete known battles and keep fire attack preparation pending: ${JSON.stringify(postRedCliffsProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-redcliffs-progress.png', fullPage: true });
await page.mouse.click(1120, 38);
await page.waitForTimeout(180);
const fireAttackSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!fireAttackSortieState?.sortieVisible ||
!fireAttackSortieState.sortiePlan?.objectiveLine?.includes('적벽 화공전') ||
!fireAttackSortieState.sortieRoster?.some((unit) => unit.id === 'zhuge-liang' && unit.recruited && unit.recommended) ||
!fireAttackSortieState.sortieRoster?.some((unit) => unit.id === 'guan-yu' && unit.recommended) ||
!fireAttackSortieState.sortieRoster?.some((unit) => unit.id === 'zhao-yun' && unit.recruited && unit.recommended) ||
!fireAttackSortieState.sortieRoster?.some((unit) => unit.id === 'mi-zhu' && unit.recruited && unit.recommended) ||
fireAttackSortieState.sortieRoster?.length < 8 ||
fireAttackSortieState.sortiePlan?.maxCount !== 6
) {
throw new Error(`Expected twenty-first camp sortie prep to target Red Cliffs fire attack with Zhuge Liang, Guan Yu, Zhao Yun, and Mi Zhu recommendations: ${JSON.stringify(fireAttackSortieState)}`);
}
assertSortieTacticalRoster(fireAttackSortieState, [
'liu-bei',
'guan-yu',
'zhang-fei',
'jian-yong',
'mi-zhu',
'sun-qian',
'zhao-yun',
'zhuge-liang'
]);
const fireAttackPriorityUnits = ['zhuge-liang', 'guan-yu', 'zhao-yun', 'mi-zhu'];
for (const unitId of fireAttackPriorityUnits) {
const currentSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (!currentSortieState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)) {
const removable = currentSortieState.sortieRoster?.find(
(unit) => unit.selected && unit.id !== 'liu-bei' && !fireAttackPriorityUnits.includes(unit.id)
);
if (removable) {
await clickSortieRosterUnit(page, removable.id);
}
await clickSortieRosterUnit(page, unitId);
}
}
const fireAttackSortieReadyState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!fireAttackPriorityUnits.every((unitId) =>
fireAttackSortieReadyState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)
) ||
fireAttackSortieReadyState.sortiePlan?.selectedCount !== 6 ||
fireAttackSortieReadyState.sortiePlan?.recommendedSelectedCount < 5
) {
throw new Error(`Expected Red Cliffs fire attack sortie to deploy priority officers while preserving six-officer choice pressure: ${JSON.stringify(fireAttackSortieReadyState)}`);
}
await page.screenshot({ path: 'dist/verification-redcliffs-fire-sortie.png', fullPage: true });
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-redcliffs-fire-story.png', fullPage: true });
for (let i = 0; i < 36; i += 1) {
const enteredTwentySecondBattle = await page.evaluate(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'twenty-second-battle-red-cliffs-fire';
});
if (enteredTwentySecondBattle) {
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 === 'twenty-second-battle-red-cliffs-fire' && state?.battleOutcome === null && state?.phase === 'idle';
});
await page.screenshot({ path: 'dist/verification-twenty-second-battle.png', fullPage: true });
const twentySecondBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
const twentySecondEnemies = twentySecondBattleState.units.filter((unit) => unit.faction === 'enemy');
const twentySecondAllies = twentySecondBattleState.units.filter((unit) => unit.faction === 'ally');
const twentySecondEnemyBehaviors = new Set(twentySecondEnemies.map((unit) => unit.ai));
if (
twentySecondBattleState.camera?.mapWidth !== 44 ||
twentySecondBattleState.camera?.mapHeight !== 30 ||
twentySecondBattleState.victoryConditionLabel !== '조조 본선 퇴각' ||
twentySecondEnemies.length < 18 ||
!twentySecondEnemyBehaviors.has('aggressive') ||
!twentySecondEnemyBehaviors.has('guard') ||
!twentySecondEnemyBehaviors.has('hold') ||
!twentySecondEnemies.some((unit) => unit.id === 'redcliff-fire-leader-cao-cao') ||
!twentySecondAllies.some((unit) => unit.id === 'zhuge-liang') ||
!twentySecondAllies.some((unit) => unit.id === 'zhao-yun') ||
!twentySecondAllies.some((unit) => unit.id === 'mi-zhu')
) {
throw new Error(`Expected twenty-second battle to use Red Cliffs fire map, Cao Cao objective, mixed AI, and selected allied officers: ${JSON.stringify(twentySecondBattleState)}`);
}
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 twentySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
twentySecondCampState?.campBattleId !== 'twenty-second-battle-red-cliffs-fire' ||
twentySecondCampState.campTitle !== '적벽 화공전 후 군영' ||
twentySecondCampState.availableDialogueIds?.length !== 3 ||
!twentySecondCampState.availableDialogueIds.every((id) => id.endsWith('red-cliffs-fire')) ||
twentySecondCampState.availableVisitIds?.length !== 2 ||
!twentySecondCampState.report?.bonds?.some((bond) => bond.id === 'liu-bei__zhuge-liang') ||
!twentySecondCampState.report?.bonds?.some((bond) => bond.id === 'liu-bei__mi-zhu') ||
twentySecondCampState.rosterCollection?.total < 8 ||
twentySecondCampState.rosterCollection?.reserveTrainingCount < 2 ||
twentySecondCampState.rosterCollection?.reserveTrainingExp < 12
) {
throw new Error(`Expected twenty-second camp to expose Red Cliffs fire dialogue/visit sets, aftermath bonds, and reserve growth: ${JSON.stringify(twentySecondCampState)}`);
}
await page.screenshot({ path: 'dist/verification-redcliffs-fire-camp.png', fullPage: true });
await page.mouse.click(966, 38);
await page.waitForTimeout(180);
const postFireAttackProgressState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
postFireAttackProgressState?.activeTab !== 'progress' ||
postFireAttackProgressState.campaignProgress?.completedKnown !== 22 ||
postFireAttackProgressState.campaignProgress?.totalKnown !== 22 ||
postFireAttackProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postFireAttackProgressState.campaignProgress?.latestBattleTitle !== '적벽 화공전' ||
postFireAttackProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
) {
throw new Error(`Expected post-Red Cliffs fire progress tab to complete known battles and point toward Jing Province preparation: ${JSON.stringify(postFireAttackProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-redcliffs-fire-progress.png', fullPage: true });
await page.evaluate(() => window.__HEROS_GAME__?.scene.start('TitleScene'));
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
@@ -2324,7 +2464,7 @@ try {
return activeScenes.includes('CampScene');
});
console.log(`Verified title-to-twenty-first-battle flow, recruit sortie selection, result states, and debug API at ${targetUrl}`);
console.log(`Verified title-to-twenty-second-battle flow, recruit sortie selection, result states, and debug API at ${targetUrl}`);
} finally {
await browser?.close();
if (serverProcess && !serverProcess.killed) {