Add Jiameng Pass Ma Chao chapter

This commit is contained in:
2026-06-23 13:01:25 +09:00
parent aca7d6568a
commit edbdaac773
11 changed files with 878 additions and 40 deletions

View File

@@ -1736,7 +1736,7 @@ try {
if (
progressTabState?.activeTab !== 'progress' ||
progressTabState.campaignProgress?.completedKnown !== 17 ||
progressTabState.campaignProgress?.totalKnown !== 33 ||
progressTabState.campaignProgress?.totalKnown !== 34 ||
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 !== 33 ||
postBowangProgressState.campaignProgress?.totalKnown !== 34 ||
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 !== 33 ||
postChangbanProgressState.campaignProgress?.totalKnown !== 34 ||
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 !== 33 ||
postJiangdongProgressState.campaignProgress?.totalKnown !== 34 ||
postJiangdongProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postJiangdongProgressState.campaignProgress?.latestBattleTitle !== '강동 사절로' ||
postJiangdongProgressState.campaignProgress?.nextBattleTitle !== '적벽 전초전'
@@ -2304,7 +2304,7 @@ try {
if (
postRedCliffsProgressState?.activeTab !== 'progress' ||
postRedCliffsProgressState.campaignProgress?.completedKnown !== 21 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 33 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 34 ||
postRedCliffsProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postRedCliffsProgressState.campaignProgress?.latestBattleTitle !== '적벽 전초전' ||
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '적벽 화공전'
@@ -2444,7 +2444,7 @@ try {
if (
postFireAttackProgressState?.activeTab !== 'progress' ||
postFireAttackProgressState.campaignProgress?.completedKnown !== 22 ||
postFireAttackProgressState.campaignProgress?.totalKnown !== 33 ||
postFireAttackProgressState.campaignProgress?.totalKnown !== 34 ||
postFireAttackProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postFireAttackProgressState.campaignProgress?.latestBattleTitle !== '적벽 화공전' ||
postFireAttackProgressState.campaignProgress?.nextBattleTitle !== '형주 남부 진입전'
@@ -2587,7 +2587,7 @@ try {
if (
postJingzhouProgressState?.activeTab !== 'progress' ||
postJingzhouProgressState.campaignProgress?.completedKnown !== 23 ||
postJingzhouProgressState.campaignProgress?.totalKnown !== 33 ||
postJingzhouProgressState.campaignProgress?.totalKnown !== 34 ||
postJingzhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postJingzhouProgressState.campaignProgress?.latestBattleTitle !== '형주 남부 진입전' ||
postJingzhouProgressState.campaignProgress?.nextBattleTitle !== '계양 설득전'
@@ -2729,7 +2729,7 @@ try {
if (
postGuiyangProgressState?.activeTab !== 'progress' ||
postGuiyangProgressState.campaignProgress?.completedKnown !== 24 ||
postGuiyangProgressState.campaignProgress?.totalKnown !== 33 ||
postGuiyangProgressState.campaignProgress?.totalKnown !== 34 ||
postGuiyangProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postGuiyangProgressState.campaignProgress?.latestBattleTitle !== '계양 설득전' ||
postGuiyangProgressState.campaignProgress?.nextBattleTitle !== '무릉 산길 확보전'
@@ -2872,7 +2872,7 @@ try {
if (
postWulingProgressState?.activeTab !== 'progress' ||
postWulingProgressState.campaignProgress?.completedKnown !== 25 ||
postWulingProgressState.campaignProgress?.totalKnown !== 33 ||
postWulingProgressState.campaignProgress?.totalKnown !== 34 ||
postWulingProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postWulingProgressState.campaignProgress?.latestBattleTitle !== '무릉 산길 확보전' ||
postWulingProgressState.campaignProgress?.nextBattleTitle !== '장사 노장 대면전'
@@ -3021,7 +3021,7 @@ try {
if (
postChangshaProgressState?.activeTab !== 'progress' ||
postChangshaProgressState.campaignProgress?.completedKnown !== 26 ||
postChangshaProgressState.campaignProgress?.totalKnown !== 33 ||
postChangshaProgressState.campaignProgress?.totalKnown !== 34 ||
postChangshaProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postChangshaProgressState.campaignProgress?.latestBattleTitle !== '장사 노장 대면전' ||
postChangshaProgressState.campaignProgress?.nextBattleTitle !== '익주 원군로'
@@ -3166,7 +3166,7 @@ try {
if (
postYizhouProgressState?.activeTab !== 'progress' ||
postYizhouProgressState.campaignProgress?.completedKnown !== 27 ||
postYizhouProgressState.campaignProgress?.totalKnown !== 33 ||
postYizhouProgressState.campaignProgress?.totalKnown !== 34 ||
postYizhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postYizhouProgressState.campaignProgress?.latestBattleTitle !== '익주 원군로' ||
postYizhouProgressState.campaignProgress?.nextBattleTitle !== '부수관 진입전'
@@ -3313,7 +3313,7 @@ try {
if (
postFuPassProgressState?.activeTab !== 'progress' ||
postFuPassProgressState.campaignProgress?.completedKnown !== 28 ||
postFuPassProgressState.campaignProgress?.totalKnown !== 33 ||
postFuPassProgressState.campaignProgress?.totalKnown !== 34 ||
postFuPassProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postFuPassProgressState.campaignProgress?.latestBattleTitle !== '부수관 진입전' ||
postFuPassProgressState.campaignProgress?.nextBattleTitle !== '낙성 외곽전'
@@ -3462,7 +3462,7 @@ try {
if (
postLuoProgressState?.activeTab !== 'progress' ||
postLuoProgressState.campaignProgress?.completedKnown !== 29 ||
postLuoProgressState.campaignProgress?.totalKnown !== 33 ||
postLuoProgressState.campaignProgress?.totalKnown !== 34 ||
postLuoProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuoProgressState.campaignProgress?.latestBattleTitle !== '낙성 외곽전' ||
postLuoProgressState.campaignProgress?.nextBattleTitle !== '낙봉파 매복전'
@@ -3608,7 +3608,7 @@ try {
if (
postLuofengProgressState?.activeTab !== 'progress' ||
postLuofengProgressState.campaignProgress?.completedKnown !== 30 ||
postLuofengProgressState.campaignProgress?.totalKnown !== 33 ||
postLuofengProgressState.campaignProgress?.totalKnown !== 34 ||
postLuofengProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuofengProgressState.campaignProgress?.latestBattleTitle !== '낙봉파 매복전' ||
postLuofengProgressState.campaignProgress?.nextBattleTitle !== '낙성 본성 공략'
@@ -3760,7 +3760,7 @@ try {
if (
postLuoMainProgressState?.activeTab !== 'progress' ||
postLuoMainProgressState.campaignProgress?.completedKnown !== 31 ||
postLuoMainProgressState.campaignProgress?.totalKnown !== 33 ||
postLuoMainProgressState.campaignProgress?.totalKnown !== 34 ||
postLuoMainProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuoMainProgressState.campaignProgress?.latestBattleTitle !== '낙성 본성 공략' ||
postLuoMainProgressState.campaignProgress?.nextBattleTitle !== '면죽관 압박전'
@@ -3913,7 +3913,7 @@ try {
if (
postMianzhuProgressState?.activeTab !== 'progress' ||
postMianzhuProgressState.campaignProgress?.completedKnown !== 32 ||
postMianzhuProgressState.campaignProgress?.totalKnown !== 33 ||
postMianzhuProgressState.campaignProgress?.totalKnown !== 34 ||
postMianzhuProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postMianzhuProgressState.campaignProgress?.latestBattleTitle !== '면죽관 압박전' ||
postMianzhuProgressState.campaignProgress?.nextBattleTitle !== '성도 항복 권고전'
@@ -4067,15 +4067,170 @@ try {
if (
postChengduProgressState?.activeTab !== 'progress' ||
postChengduProgressState.campaignProgress?.completedKnown !== 33 ||
postChengduProgressState.campaignProgress?.totalKnown !== 33 ||
postChengduProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postChengduProgressState.campaignProgress?.totalKnown !== 34 ||
postChengduProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postChengduProgressState.campaignProgress?.latestBattleTitle !== '성도 항복 권고전' ||
postChengduProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
postChengduProgressState.campaignProgress?.nextBattleTitle !== '가맹관 마초 대면전'
) {
throw new Error(`Expected post-Chengdu progress tab to complete Yi Province capture and pause before Shu-Han foundation: ${JSON.stringify(postChengduProgressState?.campaignProgress)}`);
throw new Error(`Expected post-Chengdu progress tab to complete Yi Province capture and open Jiameng Pass: ${JSON.stringify(postChengduProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-chengdu-progress.png', fullPage: true });
await page.mouse.click(1120, 38);
await page.waitForTimeout(180);
const jiamengSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!jiamengSortieState?.sortieVisible ||
!jiamengSortieState.sortiePlan?.objectiveLine?.includes('가맹관 마초 대면전') ||
!jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'huang-quan' && unit.recruited && unit.recommended) ||
!jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'zhao-yun' && unit.recruited && unit.recommended) ||
!jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'zhang-fei' && unit.recommended) ||
!jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'fa-zheng' && unit.recruited && unit.recommended) ||
!jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'huang-zhong' && unit.recruited && unit.recommended) ||
jiamengSortieState.sortieRoster?.some((unit) => unit.id === 'ma-chao') ||
jiamengSortieState.sortieRoster?.length < 19 ||
jiamengSortieState.sortiePlan?.maxCount !== 6
) {
throw new Error(`Expected Chengdu camp sortie prep to target Jiameng Pass with Huang Quan selectable and Ma Chao absent before victory: ${JSON.stringify(jiamengSortieState)}`);
}
assertSortieTacticalRoster(jiamengSortieState, [
'liu-bei',
'guan-yu',
'zhang-fei',
'jian-yong',
'mi-zhu',
'sun-qian',
'zhao-yun',
'zhuge-liang',
'ma-liang',
'yi-ji',
'gong-zhi',
'huang-zhong',
'wei-yan',
'pang-tong',
'fa-zheng',
'wu-yi',
'yan-yan',
'li-yan',
'huang-quan'
]);
const jiamengPriorityUnits = ['huang-quan', 'zhao-yun', 'zhang-fei', 'fa-zheng', 'huang-zhong'];
for (const unitId of jiamengPriorityUnits) {
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' && !jiamengPriorityUnits.includes(unit.id)
);
if (removable) {
await clickSortieRosterUnit(page, removable.id);
}
await clickSortieRosterUnit(page, unitId);
}
}
const jiamengSortieReadyState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!jiamengPriorityUnits.every((unitId) =>
jiamengSortieReadyState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)
) ||
jiamengSortieReadyState.sortiePlan?.selectedCount !== 6 ||
jiamengSortieReadyState.sortiePlan?.recommendedSelectedCount < 6
) {
throw new Error(`Expected Jiameng Pass sortie to deploy Huang Quan, Zhao Yun, Zhang Fei, Fa Zheng, and Huang Zhong while preserving six-officer pressure: ${JSON.stringify(jiamengSortieReadyState)}`);
}
await page.screenshot({ path: 'dist/verification-jiameng-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-jiameng-story.png', fullPage: true });
for (let i = 0; i < 50; i += 1) {
const enteredThirtyFourthBattle = await page.evaluate(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'thirty-fourth-battle-jiameng-pass';
});
if (enteredThirtyFourthBattle) {
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 === 'thirty-fourth-battle-jiameng-pass' && state?.battleOutcome === null && state?.phase === 'idle';
});
await page.screenshot({ path: 'dist/verification-thirty-fourth-battle.png', fullPage: true });
const thirtyFourthBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
const thirtyFourthEnemies = thirtyFourthBattleState.units.filter((unit) => unit.faction === 'enemy');
const thirtyFourthAllies = thirtyFourthBattleState.units.filter((unit) => unit.faction === 'ally');
const thirtyFourthEnemyBehaviors = new Set(thirtyFourthEnemies.map((unit) => unit.ai));
if (
thirtyFourthBattleState.camera?.mapWidth !== 68 ||
thirtyFourthBattleState.camera?.mapHeight !== 50 ||
thirtyFourthBattleState.victoryConditionLabel !== '마초 돌격 저지' ||
thirtyFourthEnemies.length < 22 ||
!thirtyFourthEnemyBehaviors.has('aggressive') ||
!thirtyFourthEnemyBehaviors.has('guard') ||
!thirtyFourthEnemyBehaviors.has('hold') ||
!thirtyFourthEnemies.some((unit) => unit.id === 'jiameng-leader-ma-chao') ||
!thirtyFourthEnemies.some((unit) => unit.id === 'jiameng-officer-pang-de') ||
!thirtyFourthAllies.some((unit) => unit.id === 'huang-quan') ||
!thirtyFourthAllies.some((unit) => unit.id === 'zhao-yun') ||
!thirtyFourthAllies.some((unit) => unit.id === 'zhang-fei') ||
!thirtyFourthAllies.some((unit) => unit.id === 'fa-zheng') ||
!thirtyFourthAllies.some((unit) => unit.id === 'huang-zhong') ||
thirtyFourthAllies.some((unit) => unit.id === 'ma-chao')
) {
throw new Error(`Expected thirty-fourth battle to use Jiameng map, Ma Chao objective, Huang Quan first sortie, selected allied officers, and mixed AI: ${JSON.stringify(thirtyFourthBattleState)}`);
}
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 thirtyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
thirtyFourthCampState?.campBattleId !== 'thirty-fourth-battle-jiameng-pass' ||
thirtyFourthCampState.campTitle !== '가맹관 대면전 후 군영' ||
thirtyFourthCampState.availableDialogueIds?.length !== 3 ||
!thirtyFourthCampState.availableDialogueIds.every((id) => id.endsWith('jiameng')) ||
thirtyFourthCampState.availableVisitIds?.length !== 2 ||
!thirtyFourthCampState.campaign?.roster?.some((unit) => unit.id === 'ma-chao') ||
!thirtyFourthCampState.sortieRoster?.some((unit) => unit.id === 'ma-chao' && unit.recruited) ||
thirtyFourthCampState.rosterCollection?.total < 20
) {
throw new Error(`Expected thirty-fourth camp to recruit Ma Chao and expose Jiameng dialogue/visit sets: ${JSON.stringify(thirtyFourthCampState)}`);
}
await page.screenshot({ path: 'dist/verification-jiameng-camp.png', fullPage: true });
await page.mouse.click(966, 38);
await page.waitForTimeout(180);
const postJiamengProgressState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
postJiamengProgressState?.activeTab !== 'progress' ||
postJiamengProgressState.campaignProgress?.completedKnown !== 34 ||
postJiamengProgressState.campaignProgress?.totalKnown !== 34 ||
postJiamengProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postJiamengProgressState.campaignProgress?.latestBattleTitle !== '가맹관 마초 대면전' ||
postJiamengProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
) {
throw new Error(`Expected post-Jiameng progress tab to complete Ma Chao chapter and pause on the next Hanzhong step: ${JSON.stringify(postJiamengProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-jiameng-progress.png', fullPage: true });
await page.evaluate(() => {
const game = window.__HEROS_GAME__;
game?.scene.stop('CampScene');
@@ -4094,7 +4249,7 @@ try {
return activeScenes.includes('CampScene');
});
console.log(`Verified title-to-thirty-third-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan joins, Luofeng, Luo main gate, Mianzhu, and Chengdu surrender battles, result states, and debug API at ${targetUrl}`);
console.log(`Verified title-to-thirty-fourth-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, and Ma Chao joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, and Jiameng Pass battles, result states, and debug API at ${targetUrl}`);
} finally {
await browser?.close();
if (serverProcess && !serverProcess.killed) {