Expand early campaign release QA to battle 20
This commit is contained in:
@@ -197,49 +197,171 @@ const refugeCampaignBattles = [
|
||||
no: 14,
|
||||
id: 'fourteenth-battle-cao-break',
|
||||
selected: sunQianSortie,
|
||||
targets: ['cao-break-guard-a', 'cao-break-guard-b', 'cao-break-leader-che-zhou'],
|
||||
targets: [
|
||||
'cao-break-scout-a',
|
||||
'cao-break-scout-b',
|
||||
'cao-break-infantry-a',
|
||||
'cao-break-infantry-b',
|
||||
'cao-break-infantry-c',
|
||||
'cao-break-infantry-d',
|
||||
'cao-break-archer-a',
|
||||
'cao-break-archer-b',
|
||||
'cao-break-archer-c',
|
||||
'cao-break-cavalry-a',
|
||||
'cao-break-cavalry-b',
|
||||
'cao-break-cavalry-c',
|
||||
'cao-break-guard-a',
|
||||
'cao-break-guard-b',
|
||||
'cao-break-leader-che-zhou'
|
||||
],
|
||||
protected: ['liu-bei']
|
||||
},
|
||||
{
|
||||
no: 15,
|
||||
id: 'fifteenth-battle-yuan-refuge-road',
|
||||
selected: sunQianSortie,
|
||||
targets: ['yuan-refuge-guard-a', 'yuan-refuge-archer-c', 'yuan-refuge-leader-cai-yang'],
|
||||
targets: [
|
||||
'yuan-refuge-scout-a',
|
||||
'yuan-refuge-scout-b',
|
||||
'yuan-refuge-infantry-a',
|
||||
'yuan-refuge-infantry-b',
|
||||
'yuan-refuge-infantry-c',
|
||||
'yuan-refuge-infantry-d',
|
||||
'yuan-refuge-archer-a',
|
||||
'yuan-refuge-archer-b',
|
||||
'yuan-refuge-archer-c',
|
||||
'yuan-refuge-cavalry-a',
|
||||
'yuan-refuge-cavalry-b',
|
||||
'yuan-refuge-cavalry-c',
|
||||
'yuan-refuge-guard-a',
|
||||
'yuan-refuge-guard-b',
|
||||
'yuan-refuge-guard-c',
|
||||
'yuan-refuge-strategist-a',
|
||||
'yuan-refuge-leader-cai-yang'
|
||||
],
|
||||
protected: ['liu-bei']
|
||||
},
|
||||
{
|
||||
no: 16,
|
||||
id: 'sixteenth-battle-liu-biao-refuge',
|
||||
selected: liuBiaoSortie,
|
||||
targets: ['liu-biao-road-leader-cao-ren'],
|
||||
targets: [
|
||||
'liu-biao-road-scout-a',
|
||||
'liu-biao-road-scout-b',
|
||||
'liu-biao-road-infantry-a',
|
||||
'liu-biao-road-infantry-b',
|
||||
'liu-biao-road-infantry-c',
|
||||
'liu-biao-road-infantry-d',
|
||||
'liu-biao-road-archer-a',
|
||||
'liu-biao-road-archer-b',
|
||||
'liu-biao-road-archer-c',
|
||||
'liu-biao-road-archer-d',
|
||||
'liu-biao-road-cavalry-a',
|
||||
'liu-biao-road-cavalry-b',
|
||||
'liu-biao-road-cavalry-c',
|
||||
'liu-biao-road-cavalry-d',
|
||||
'liu-biao-road-guard-a',
|
||||
'liu-biao-road-guard-b',
|
||||
'liu-biao-road-strategist-a',
|
||||
'liu-biao-road-leader-cao-ren'
|
||||
],
|
||||
protected: ['liu-bei']
|
||||
},
|
||||
{
|
||||
no: 17,
|
||||
id: 'seventeenth-battle-wolong-visit-road',
|
||||
selected: liuBiaoSortie,
|
||||
targets: ['wolong-road-leader-cai-xun'],
|
||||
targets: [
|
||||
'wolong-road-scout-a',
|
||||
'wolong-road-scout-b',
|
||||
'wolong-road-infantry-a',
|
||||
'wolong-road-infantry-b',
|
||||
'wolong-road-infantry-c',
|
||||
'wolong-road-infantry-d',
|
||||
'wolong-road-archer-a',
|
||||
'wolong-road-archer-b',
|
||||
'wolong-road-archer-c',
|
||||
'wolong-road-cavalry-a',
|
||||
'wolong-road-cavalry-b',
|
||||
'wolong-road-guard-a',
|
||||
'wolong-road-guard-b',
|
||||
'wolong-road-strategist-a',
|
||||
'wolong-road-leader-cai-xun'
|
||||
],
|
||||
protected: ['liu-bei']
|
||||
},
|
||||
{
|
||||
no: 18,
|
||||
id: 'eighteenth-battle-bowang-ambush',
|
||||
selected: zhugeFirstSortie,
|
||||
targets: ['bowang-leader-xiahou-dun'],
|
||||
targets: [
|
||||
'bowang-scout-a',
|
||||
'bowang-scout-b',
|
||||
'bowang-infantry-a',
|
||||
'bowang-infantry-b',
|
||||
'bowang-infantry-c',
|
||||
'bowang-infantry-d',
|
||||
'bowang-archer-a',
|
||||
'bowang-archer-b',
|
||||
'bowang-archer-c',
|
||||
'bowang-cavalry-a',
|
||||
'bowang-cavalry-b',
|
||||
'bowang-cavalry-c',
|
||||
'bowang-guard-a',
|
||||
'bowang-guard-b',
|
||||
'bowang-strategist-a',
|
||||
'bowang-leader-xiahou-dun'
|
||||
],
|
||||
protected: ['liu-bei']
|
||||
},
|
||||
{
|
||||
no: 19,
|
||||
id: 'nineteenth-battle-changban-refuge',
|
||||
selected: zhugeFirstSortie,
|
||||
targets: ['changban-infantry-b', 'changban-cavalry-b', 'changban-guard-b', 'changban-leader-cao-chun'],
|
||||
targets: [
|
||||
'changban-scout-a',
|
||||
'changban-scout-b',
|
||||
'changban-cavalry-a',
|
||||
'changban-cavalry-b',
|
||||
'changban-cavalry-c',
|
||||
'changban-cavalry-d',
|
||||
'changban-infantry-a',
|
||||
'changban-infantry-b',
|
||||
'changban-infantry-c',
|
||||
'changban-infantry-d',
|
||||
'changban-archer-a',
|
||||
'changban-archer-b',
|
||||
'changban-archer-c',
|
||||
'changban-guard-a',
|
||||
'changban-guard-b',
|
||||
'changban-strategist-a',
|
||||
'changban-leader-cao-chun'
|
||||
],
|
||||
protected: ['liu-bei', 'zhao-yun']
|
||||
},
|
||||
{
|
||||
no: 20,
|
||||
id: 'twentieth-battle-jiangdong-envoy',
|
||||
selected: envoySortie,
|
||||
targets: ['envoy-road-leader-wen-pin'],
|
||||
targets: [
|
||||
'envoy-road-scout-a',
|
||||
'envoy-road-scout-b',
|
||||
'envoy-road-cavalry-a',
|
||||
'envoy-road-cavalry-b',
|
||||
'envoy-road-cavalry-c',
|
||||
'envoy-road-cavalry-d',
|
||||
'envoy-road-infantry-a',
|
||||
'envoy-road-infantry-b',
|
||||
'envoy-road-infantry-c',
|
||||
'envoy-road-infantry-d',
|
||||
'envoy-road-archer-a',
|
||||
'envoy-road-archer-b',
|
||||
'envoy-road-archer-c',
|
||||
'envoy-road-guard-a',
|
||||
'envoy-road-guard-b',
|
||||
'envoy-road-strategist-a',
|
||||
'envoy-road-leader-wen-pin'
|
||||
],
|
||||
protected: ['liu-bei', 'zhuge-liang', 'sun-qian']
|
||||
}
|
||||
];
|
||||
@@ -1005,9 +1127,9 @@ async function normalizeRepresentativeBattleUnits(page, battle) {
|
||||
}
|
||||
|
||||
const selectedIds = new Set([...(selected ?? []), ...(protectedUnitIds ?? [])]);
|
||||
const hpFloor = no >= 28 ? 86 : no >= 21 ? 82 : no >= 18 ? 76 : no >= 11 ? 68 : no >= 2 ? 56 : 0;
|
||||
const attackFloor = no >= 28 ? 78 : no >= 21 ? 70 : no >= 18 ? 54 : no >= 11 ? 42 : no >= 2 ? 24 : 0;
|
||||
const statFloor = no >= 28 ? 132 : no >= 21 ? 126 : no >= 18 ? 112 : no >= 11 ? 98 : no >= 2 ? 88 : 0;
|
||||
const hpFloor = no >= 28 ? 86 : no >= 21 ? 84 : no >= 18 ? 84 : no >= 14 ? 80 : no >= 11 ? 68 : no >= 2 ? 56 : 0;
|
||||
const attackFloor = no >= 28 ? 78 : no >= 21 ? 70 : no >= 18 ? 64 : no >= 14 ? 60 : no >= 11 ? 42 : no >= 2 ? 24 : 0;
|
||||
const statFloor = no >= 28 ? 132 : no >= 21 ? 126 : no >= 18 ? 122 : no >= 14 ? 118 : no >= 11 ? 98 : no >= 2 ? 88 : 0;
|
||||
|
||||
if (hpFloor <= 0) {
|
||||
return;
|
||||
@@ -1440,6 +1562,36 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
return safeTiles.sort((a, b) => b.score - a.score || a.focusDistance - b.focusDistance || (a.tile.cost ?? 0) - (b.tile.cost ?? 0))[0]?.tile;
|
||||
}
|
||||
|
||||
function scenarioAdvancePoint(unit) {
|
||||
if (no === 14) {
|
||||
const objectives = state().objectives ?? [];
|
||||
const relayDone = objectives.find((objective) => objective.id === 'relay')?.achieved;
|
||||
const gateDone = objectives.find((objective) => objective.id === 'gate')?.achieved;
|
||||
if (!relayDone) {
|
||||
return { x: 18, y: 16 };
|
||||
}
|
||||
if (!gateDone) {
|
||||
if (unit.x < 22 || unit.y > 18) {
|
||||
return { x: 23, y: 18 };
|
||||
}
|
||||
return { x: 25, y: 13 };
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function advancePointTile(unit, tiles) {
|
||||
const point = scenarioAdvancePoint(unit);
|
||||
if (!point || protectedIds.has(unit.id)) {
|
||||
return undefined;
|
||||
}
|
||||
const currentDistance = distance(unit, point);
|
||||
return tiles
|
||||
.filter((tile) => tile.x !== unit.x || tile.y !== unit.y)
|
||||
.filter((tile) => distance(tile, point) < currentDistance)
|
||||
.sort((a, b) => distance(a, point) - distance(b, point) || (a.cost ?? 0) - (b.cost ?? 0))[0];
|
||||
}
|
||||
|
||||
function chooseMove(unit) {
|
||||
const tiles = [{ x: unit.x, y: unit.y, cost: 0 }, ...scene.reachableTiles(unit)];
|
||||
const pressProtected = shouldPressProtected(unit);
|
||||
@@ -1481,6 +1633,11 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
})[0].tile;
|
||||
}
|
||||
|
||||
const scenarioTile = advancePointTile(unit, tiles);
|
||||
if (scenarioTile) {
|
||||
return scenarioTile;
|
||||
}
|
||||
|
||||
if (!protectedIds.has(unit.id) || pressProtected) {
|
||||
const focus = focusTarget(unit);
|
||||
if (focus) {
|
||||
@@ -1503,6 +1660,18 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
}
|
||||
}
|
||||
|
||||
const objective = currentSecureObjective();
|
||||
if (objective && (!protectedIds.has(unit.id) || pressProtected)) {
|
||||
const currentObjectiveDistance = objectiveDistance(unit, objective);
|
||||
const objectivePressureTile = tiles
|
||||
.filter((tile) => tile.x !== unit.x || tile.y !== unit.y)
|
||||
.filter((tile) => objectiveDistance(tile, objective) < currentObjectiveDistance)
|
||||
.sort((a, b) => objectiveDistance(a, objective) - objectiveDistance(b, objective) || (a.cost ?? 0) - (b.cost ?? 0))[0];
|
||||
if (objectivePressureTile) {
|
||||
return objectivePressureTile;
|
||||
}
|
||||
}
|
||||
|
||||
let best = { tile: tiles[0], score: Number.NEGATIVE_INFINITY };
|
||||
|
||||
for (const tile of tiles) {
|
||||
@@ -1589,6 +1758,13 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
resolveOutcome();
|
||||
}
|
||||
|
||||
function allyTurnPriority(unit) {
|
||||
const protectedPenalty = protectedIds.has(unit.id) ? 80 : 0;
|
||||
const vanguardBonus = ['guan-yu', 'zhang-fei', 'zhao-yun', 'huang-zhong', 'wei-yan', 'ma-chao', 'ma-dai'].includes(unit.id) ? -28 : 0;
|
||||
const supportPenalty = ['jian-yong', 'mi-zhu', 'sun-qian', 'ma-liang', 'yi-ji', 'gong-zhi'].includes(unit.id) ? 20 : 0;
|
||||
return protectedPenalty + supportPenalty + vanguardBonus;
|
||||
}
|
||||
|
||||
for (let round = 0; round < maxRounds; round += 1) {
|
||||
let snapshot = state();
|
||||
if (snapshot.battleOutcome) {
|
||||
@@ -1598,7 +1774,7 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
const acted = actedUnitIds();
|
||||
const allies = snapshot.units
|
||||
.filter((unit) => unit.faction === 'ally' && unit.hp > 0 && !acted.has(unit.id))
|
||||
.sort((a, b) => a.hp / a.maxHp - b.hp / b.maxHp);
|
||||
.sort((a, b) => allyTurnPriority(a) - allyTurnPriority(b) || a.hp / a.maxHp - b.hp / b.maxHp);
|
||||
|
||||
for (const allyState of allies) {
|
||||
snapshot = state();
|
||||
@@ -1652,6 +1828,10 @@ async function playBattleWithoutDebugVictory(page, battle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (no >= 14 && shouldHoldBattleEndingTarget(enemy, currentSecureObjective())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const behavior = scene.enemyBehavior(enemy);
|
||||
let target = scene.chooseEnemyTarget(enemy, behavior);
|
||||
if (!target) {
|
||||
|
||||
Reference in New Issue
Block a user