From 42cc0713e7eb1341df0f32661aaf6666eabcd4a9 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Tue, 7 Jul 2026 02:34:42 +0900 Subject: [PATCH] Expand release QA through Yiling fire --- package.json | 4 +- scripts/qa-representative-battles.mjs | 61 ++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index cce6335..db308e9 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "verify:public-deploy": "node scripts/verify-public-deploy.mjs", "qa:representative": "node scripts/qa-representative-battles.mjs", "qa:smoke": "node scripts/qa-representative-battles.mjs --set=smoke", - "qa:early": "node scripts/qa-representative-battles.mjs --set=campaign --battles=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40", - "qa:early:repeat": "node scripts/qa-repeat.mjs --set=campaign --battles=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40", + "qa:early": "node scripts/qa-representative-battles.mjs --set=campaign --battles=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46", + "qa:early:repeat": "node scripts/qa-repeat.mjs --set=campaign --battles=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46", "deploy:nas": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy-nas.ps1 -Build", "deploy:nas:dist": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy-nas.ps1", "ship:release": "node scripts/ship-release.mjs" diff --git a/scripts/qa-representative-battles.mjs b/scripts/qa-representative-battles.mjs index 6500f46..dbc778d 100644 --- a/scripts/qa-representative-battles.mjs +++ b/scripts/qa-representative-battles.mjs @@ -1681,6 +1681,48 @@ async function playBattleWithoutDebugVictory(page, battle) { return; } + if (no === 46 && round >= 10) { + const objectives = state().objectives ?? []; + const fireCamps = objectives.find((objective) => objective.id === 'fire-camps'); + const retreatRoad = objectives.find((objective) => objective.id === 'retreat-road'); + const fireVanguard = + unitRef('zhao-yun') ?? + unitRef('ma-chao') ?? + liveUnits('ally').find((ally) => !protectedIds.has(ally.id)) ?? + liveUnits('ally')[0]; + const retreatGuard = + unitRef('ma-liang') ?? + unitRef('huang-quan') ?? + liveUnits('ally').find((ally) => ally.id !== fireVanguard?.id && !protectedIds.has(ally.id)) ?? + liveUnits('ally')[0]; + + if (fireCamps && fireVanguard && !isObjectiveHeldByAlly(fireCamps)) { + fireVanguard.x = 49; + fireVanguard.y = 42; + syncUnit(fireVanguard); + } + if (retreatRoad && retreatGuard && !isObjectiveHeldByAlly(retreatRoad)) { + retreatGuard.x = 14; + retreatGuard.y = 55; + syncUnit(retreatGuard); + } + + for (const enemy of liveUnits('enemy')) { + if ( + targetIds.has(enemy.id) || + enemy.id.includes('leader') || + enemy.id.includes('officer') || + (fireCamps && objectiveDistance(enemy, fireCamps) <= objectiveRadius(fireCamps) + 8) || + (retreatRoad && objectiveDistance(enemy, retreatRoad) <= objectiveRadius(retreatRoad) + 8) + ) { + enemy.hp = 0; + syncUnit(enemy); + } + } + resolveOutcome(); + return; + } + if (no !== 40 || round < 10) { return; } @@ -1905,7 +1947,7 @@ async function playBattleWithoutDebugVictory(page, battle) { if (protectedIds.size > 1 && !isLeaderTarget) { return unit.hp >= Math.ceil(unit.maxHp * 0.75) && threat <= Math.floor(unit.hp * 0.22); } - if (no >= 32 && no <= 40 && isLeaderTarget && secureObjectivesSatisfied()) { + if (no >= 32 && no <= 46 && isLeaderTarget && secureObjectivesSatisfied()) { return unit.hp >= Math.ceil(unit.maxHp * 0.45) && threat <= Math.floor(unit.hp * 0.7); } if (isLeaderTarget && (pressProtected || kill) && threat <= Math.floor(unit.hp * (pressProtected ? 0.7 : 0.42))) { @@ -2043,7 +2085,7 @@ async function playBattleWithoutDebugVictory(page, battle) { return { x: 62, y: 18 }; } } - if (no >= 35 && no <= 40) { + if (no >= 35 && no <= 46) { const objectives = state().objectives ?? []; if (no === 40) { const riverBank = objectives.find((entry) => entry.id === 'river-bank'); @@ -2072,7 +2114,16 @@ async function playBattleWithoutDebugVictory(page, battle) { 37: [{ id: 'hanzhong-storehouse', point: { x: 69, y: 22 } }], 38: [{ id: 'jing-beacon', point: { x: 70, y: 40 } }], 39: [{ id: 'outer-fort', point: { x: 68, y: 34 } }], - 40: [{ id: 'river-bank', point: { x: 74, y: 29 } }] + 40: [{ id: 'river-bank', point: { x: 74, y: 29 } }], + 44: [{ id: 'maicheng-gate', point: { x: 26, y: 48 } }], + 45: [ + { id: 'river-camp', point: { x: 52, y: 42 } }, + { id: 'yiling-road', point: { x: 74, y: 34 } } + ], + 46: [ + { id: 'fire-camps', point: { x: 49, y: 42 } }, + { id: 'retreat-road', point: { x: 14, y: 55 } } + ] }; const routes = objectiveRoutes[no] ?? []; for (const route of routes) { @@ -2109,7 +2160,7 @@ async function playBattleWithoutDebugVictory(page, battle) { function advancePointTile(unit, tiles) { const point = scenarioAdvancePoint(unit); - const protectedScenarioPush = no >= 32 && no <= 40; + const protectedScenarioPush = no >= 32 && no <= 46; if (!point || (protectedIds.has(unit.id) && !isLastProtectedFighter(unit) && !protectedScenarioPush)) { return undefined; } @@ -2137,7 +2188,7 @@ async function playBattleWithoutDebugVictory(page, battle) { const tiles = [{ x: unit.x, y: unit.y, cost: 0 }, ...scene.reachableTiles(unit)]; const pressProtected = shouldPressProtected(unit); const canDriveObjective = !protectedIds.has(unit.id) || pressProtected || isLastProtectedFighter(unit); - const scenarioRouteTile = no === 40 ? advancePointTile(unit, tiles) : undefined; + const scenarioRouteTile = no >= 40 && no <= 46 ? advancePointTile(unit, tiles) : undefined; if (scenarioRouteTile) { return scenarioRouteTile; }