From fcc2e28e05bd613360c25bfd3a699f2b314e0c00 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sun, 28 Jun 2026 01:13:23 +0900 Subject: [PATCH] QA and tune final Meng Huo captures --- scripts/qa-representative-battles.mjs | 41 ++++++++++++++++++- src/game/data/battles.ts | 32 +++++++-------- src/game/data/scenario.ts | 59 +++++++++++++++++++++++++-- src/game/scenes/BattleScene.ts | 8 ++-- 4 files changed, 114 insertions(+), 26 deletions(-) diff --git a/scripts/qa-representative-battles.mjs b/scripts/qa-representative-battles.mjs index d4cb22b..642a7fc 100644 --- a/scripts/qa-representative-battles.mjs +++ b/scripts/qa-representative-battles.mjs @@ -43,6 +43,10 @@ const nanzhongStabilizationSortie = ['zhuge-liang', 'zhao-yun', 'wang-ping', 'ma const mengHuoMainSortie = ['zhuge-liang', 'ma-liang', 'wang-ping', 'huang-quan', 'zhao-yun', 'ma-chao', 'huang-zhong']; const mengHuoSecondSortie = ['zhuge-liang', 'huang-quan', 'wang-ping', 'ma-liang', 'zhao-yun', 'huang-zhong', 'ma-chao']; const mengHuoThirdSortie = ['zhuge-liang', 'ma-liang', 'huang-quan', 'wang-ping', 'zhao-yun', 'ma-chao', 'huang-zhong']; +const mengHuoFourthSortie = ['zhuge-liang', 'ma-liang', 'huang-quan', 'wang-ping', 'zhao-yun', 'ma-chao', 'ma-dai']; +const mengHuoFifthSortie = ['zhuge-liang', 'huang-quan', 'ma-liang', 'wang-ping', 'zhao-yun', 'huang-zhong', 'ma-dai']; +const mengHuoSixthSortie = ['zhuge-liang', 'ma-liang', 'huang-quan', 'wang-ping', 'zhao-yun', 'wei-yan', 'ma-dai']; +const mengHuoFinalSortie = ['zhuge-liang', 'huang-quan', 'ma-liang', 'wang-ping', 'zhao-yun', 'ma-dai', 'huang-zhong']; const earlyCampaignBattles = [ { no: 1, id: 'first-battle-zhuo-commandery', selected: [], targets: ['rebel-leader'], protected: ['liu-bei'] }, @@ -403,6 +407,37 @@ const yilingCampaignBattles = [ } ]; +const nanzhongFinalCampaignBattles = [ + { + no: 51, + id: 'fifty-first-battle-meng-huo-fourth-capture', + selected: mengHuoFourthSortie, + targets: ['menghuo-fourth-leader'], + protected: ['zhuge-liang'] + }, + { + no: 52, + id: 'fifty-second-battle-meng-huo-fifth-capture', + selected: mengHuoFifthSortie, + targets: ['menghuo-fifth-leader'], + protected: ['zhuge-liang'] + }, + { + no: 53, + id: 'fifty-third-battle-meng-huo-sixth-capture', + selected: mengHuoSixthSortie, + targets: ['menghuo-sixth-leader'], + protected: ['zhuge-liang'] + }, + { + no: 54, + id: 'fifty-fourth-battle-meng-huo-final-capture', + selected: mengHuoFinalSortie, + targets: ['menghuo-final-leader'], + protected: ['zhuge-liang'] + } +]; + const allRepresentativeBattles = [ { no: 1, id: 'first-battle-zhuo-commandery', selected: [], targets: ['rebel-leader'], protected: ['liu-bei'] }, { @@ -469,7 +504,8 @@ const qaBattleSets = { refuge: refugeCampaignBattles, southern: southernCampaignBattles, hanzhong: hanzhongCampaignBattles, - yiling: yilingCampaignBattles + yiling: yilingCampaignBattles, + nanzhongFinal: nanzhongFinalCampaignBattles }; const qaSetName = process.env.QA_SET ?? 'representative'; const qaBattleSet = qaBattleSets[qaSetName]; @@ -841,7 +877,8 @@ async function playBattleWithoutDebugVictory(page, battle) { const focus = attack?.target ?? focusTarget(unit); const isProtected = protectedIds.has(unit.id); const shouldPress = isProtected && shouldPressProtected(unit); - const threat = incomingThreat(unit, tile); + const needsThreatCheck = isProtected || unit.hp <= Math.ceil(unit.maxHp * 0.55); + const threat = needsThreatCheck ? incomingThreat(unit, tile) : 0; const canUseAttack = attack && (!isProtected || canTakeAttack(unit, attack, threat)); const approach = focus ? -distance(unit, focus) * (isProtected ? (shouldPress ? 42 : 5) : 36) : 0; const attackScore = canUseAttack ? attack.score + (targetIds.has(attack.target.id) ? 2400 : 1350) : approach; diff --git a/src/game/data/battles.ts b/src/game/data/battles.ts index 617a0d8..52f2228 100644 --- a/src/game/data/battles.ts +++ b/src/game/data/battles.ts @@ -3342,7 +3342,7 @@ export const fiftyFirstBattleScenario: BattleScenarioDefinition = { bonds: fiftyFirstBattleBonds, mapTextureKey: 'battle-map-fifty-first', leaderUnitId: 'menghuo-fourth-leader', - quickVictoryTurnLimit: 94, + quickVictoryTurnLimit: 24, baseVictoryGold: 12280, objectives: [ { @@ -3383,13 +3383,13 @@ export const fiftyFirstBattleScenario: BattleScenarioDefinition = { { id: 'quick', kind: 'quick-victory', - label: '94턴 이내 네 번째 생포', + label: '24턴 이내 네 번째 생포', rewardGold: 2780, - maxTurn: 94 + maxTurn: 24 } ], defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }], - itemRewards: ['콩 66', '상처약 50', '탁주 22', '호족 보증 장부 1', '회유 퇴로 표식 1'], + itemRewards: ['콩 46', '상처약 34', '탁주 16', '호족 보증 장부 1', '회유 퇴로 표식 1'], victoryPages: fiftyFirstBattleVictoryPages, nextCampScene: 'CampScene' }; @@ -3409,7 +3409,7 @@ export const fiftySecondBattleScenario: BattleScenarioDefinition = { bonds: fiftySecondBattleBonds, mapTextureKey: 'battle-map-fifty-second', leaderUnitId: 'menghuo-fifth-leader', - quickVictoryTurnLimit: 98, + quickVictoryTurnLimit: 26, baseVictoryGold: 12940, objectives: [ { @@ -3450,13 +3450,13 @@ export const fiftySecondBattleScenario: BattleScenarioDefinition = { { id: 'quick', kind: 'quick-victory', - label: '98턴 이내 다섯 번째 생포', + label: '26턴 이내 다섯 번째 생포', rewardGold: 2920, - maxTurn: 98 + maxTurn: 26 } ], defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }], - itemRewards: ['콩 70', '상처약 54', '탁주 24', '강경파 분리 장부 1', '남중 회유 깃발 1'], + itemRewards: ['콩 50', '상처약 38', '탁주 18', '강경파 분리 장부 1', '남중 회유 깃발 1'], victoryPages: fiftySecondBattleVictoryPages, nextCampScene: 'CampScene' }; @@ -3476,7 +3476,7 @@ export const fiftyThirdBattleScenario: BattleScenarioDefinition = { bonds: fiftyThirdBattleBonds, mapTextureKey: 'battle-map-fifty-third', leaderUnitId: 'menghuo-sixth-leader', - quickVictoryTurnLimit: 102, + quickVictoryTurnLimit: 28, baseVictoryGold: 13620, objectives: [ { @@ -3517,13 +3517,13 @@ export const fiftyThirdBattleScenario: BattleScenarioDefinition = { { id: 'quick', kind: 'quick-victory', - label: '102턴 이내 여섯 번째 생포', + label: '28턴 이내 여섯 번째 생포', rewardGold: 3060, - maxTurn: 102 + maxTurn: 28 } ], defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }], - itemRewards: ['콩 74', '상처약 58', '탁주 26', '남중 신뢰 장부 1', '계곡 회유 표식 1'], + itemRewards: ['콩 54', '상처약 42', '탁주 20', '남중 신뢰 장부 1', '계곡 회유 표식 1'], victoryPages: fiftyThirdBattleVictoryPages, nextCampScene: 'CampScene' }; @@ -3543,7 +3543,7 @@ export const fiftyFourthBattleScenario: BattleScenarioDefinition = { bonds: fiftyFourthBattleBonds, mapTextureKey: 'battle-map-fifty-fourth', leaderUnitId: 'menghuo-final-leader', - quickVictoryTurnLimit: 106, + quickVictoryTurnLimit: 30, baseVictoryGold: 14360, objectives: [ { @@ -3584,13 +3584,13 @@ export const fiftyFourthBattleScenario: BattleScenarioDefinition = { { id: 'quick', kind: 'quick-victory', - label: '106턴 이내 마지막 생포', + label: '30턴 이내 마지막 생포', rewardGold: 3220, - maxTurn: 106 + maxTurn: 30 } ], defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }], - itemRewards: ['콩 80', '상처약 64', '탁주 30', '남중 평정 장부 1', '맹획 항복 서약 1'], + itemRewards: ['콩 60', '상처약 46', '탁주 22', '남중 평정 장부 1', '맹획 항복 서약 1'], victoryPages: fiftyFourthBattleVictoryPages, nextCampScene: 'CampScene' }; diff --git a/src/game/data/scenario.ts b/src/game/data/scenario.ts index 97ecf6c..50e07f2 100644 --- a/src/game/data/scenario.ts +++ b/src/game/data/scenario.ts @@ -17207,7 +17207,7 @@ const fiftyFirstBattleAllyPositions: Record = 'wang-ping': { x: 29, y: 56 } }; -export const fiftyFirstBattleUnits: UnitData[] = [ +const fiftyFirstBattleUnitsBase: UnitData[] = [ ...[ ...firstBattleUnits.filter((unit) => unit.faction === 'ally' && unit.id !== 'liu-bei'), ...xuzhouRecruitUnits, @@ -17270,6 +17270,18 @@ export const fiftyFirstBattleUnits: UnitData[] = [ createThirtyFirstEnemyUnit('menghuo-fourth-leader', '맹획', '남만왕', 'rebelLeader', 156, 1048, 258, 96, 43) ]; +export const fiftyFirstBattleUnits: UnitData[] = tuneEnemyUnitGroup(fiftyFirstBattleUnitsBase, ['menghuo-fourth-'], { + hpScale: 0.32, + attackScale: 0.5, + overrides: { + 'menghuo-fourth-officer-wutugu': { hp: 420, attack: 148, x: 60, y: 40 }, + 'menghuo-fourth-officer-mangyachang': { hp: 410, attack: 148, x: 62, y: 56 }, + 'menghuo-fourth-officer-dongtuna': { hp: 380, attack: 140, x: 58, y: 52 }, + 'menghuo-fourth-officer-ahuinan': { hp: 370, attack: 138, x: 56, y: 48 }, + 'menghuo-fourth-leader': { hp: 900, attack: 160, x: 62, y: 44 } + } +}); + const fiftySecondBattleAllyPositions: Record = { 'guan-yu': { x: 15, y: 65 }, 'zhang-fei': { x: 20, y: 67 }, @@ -17294,7 +17306,7 @@ const fiftySecondBattleAllyPositions: Record = 'wang-ping': { x: 30, y: 58 } }; -export const fiftySecondBattleUnits: UnitData[] = [ +const fiftySecondBattleUnitsBase: UnitData[] = [ ...[ ...firstBattleUnits.filter((unit) => unit.faction === 'ally' && unit.id !== 'liu-bei'), ...xuzhouRecruitUnits, @@ -17358,6 +17370,18 @@ export const fiftySecondBattleUnits: UnitData[] = [ createThirtyFirstEnemyUnit('menghuo-fifth-leader', '맹획', '남만왕', 'rebelLeader', 162, 1100, 270, 98, 45) ]; +export const fiftySecondBattleUnits: UnitData[] = tuneEnemyUnitGroup(fiftySecondBattleUnitsBase, ['menghuo-fifth-'], { + hpScale: 0.3, + attackScale: 0.48, + overrides: { + 'menghuo-fifth-officer-zhurong': { hp: 460, attack: 154, x: 62, y: 58 }, + 'menghuo-fifth-officer-mulu': { hp: 450, attack: 154, x: 64, y: 42 }, + 'menghuo-fifth-officer-duosi': { hp: 400, attack: 144, x: 60, y: 56 }, + 'menghuo-fifth-officer-mengyou': { hp: 390, attack: 142, x: 58, y: 50 }, + 'menghuo-fifth-leader': { hp: 1500, attack: 172, x: 64, y: 46 } + } +}); + const fiftyThirdBattleAllyPositions: Record = { 'guan-yu': { x: 16, y: 67 }, 'zhang-fei': { x: 21, y: 69 }, @@ -17382,7 +17406,7 @@ const fiftyThirdBattleAllyPositions: Record = 'wang-ping': { x: 31, y: 60 } }; -export const fiftyThirdBattleUnits: UnitData[] = [ +const fiftyThirdBattleUnitsBase: UnitData[] = [ ...[ ...firstBattleUnits.filter((unit) => unit.faction === 'ally' && unit.id !== 'liu-bei'), ...xuzhouRecruitUnits, @@ -17447,6 +17471,19 @@ export const fiftyThirdBattleUnits: UnitData[] = [ createThirtyFirstEnemyUnit('menghuo-sixth-leader', '맹획', '남만왕', 'rebelLeader', 168, 1140, 280, 100, 47) ]; +export const fiftyThirdBattleUnits: UnitData[] = tuneEnemyUnitGroup(fiftyThirdBattleUnitsBase, ['menghuo-sixth-'], { + hpScale: 0.29, + attackScale: 0.46, + overrides: { + 'menghuo-sixth-officer-zhurong': { hp: 500, attack: 158, x: 63, y: 60 }, + 'menghuo-sixth-officer-mulu': { hp: 490, attack: 158, x: 65, y: 44 }, + 'menghuo-sixth-officer-duosi': { hp: 430, attack: 148, x: 61, y: 58 }, + 'menghuo-sixth-officer-mengyou': { hp: 420, attack: 146, x: 60, y: 52 }, + 'menghuo-sixth-officer-dailai': { hp: 450, attack: 150, x: 63, y: 64 }, + 'menghuo-sixth-leader': { hp: 1650, attack: 180, x: 65, y: 48 } + } +}); + const fiftyFourthBattleAllyPositions: Record = { 'guan-yu': { x: 17, y: 69 }, 'zhang-fei': { x: 22, y: 71 }, @@ -17471,7 +17508,7 @@ const fiftyFourthBattleAllyPositions: Record = 'wang-ping': { x: 32, y: 62 } }; -export const fiftyFourthBattleUnits: UnitData[] = [ +const fiftyFourthBattleUnitsBase: UnitData[] = [ ...[ ...firstBattleUnits.filter((unit) => unit.faction === 'ally' && unit.id !== 'liu-bei'), ...xuzhouRecruitUnits, @@ -17537,6 +17574,20 @@ export const fiftyFourthBattleUnits: UnitData[] = [ createThirtyFirstEnemyUnit('menghuo-final-leader', '맹획', '남만왕', 'rebelLeader', 174, 1180, 288, 102, 49) ]; +export const fiftyFourthBattleUnits: UnitData[] = tuneEnemyUnitGroup(fiftyFourthBattleUnitsBase, ['menghuo-final-'], { + hpScale: 0.28, + attackScale: 0.44, + overrides: { + 'menghuo-final-officer-zhurong': { hp: 520, attack: 164, x: 64, y: 62 }, + 'menghuo-final-officer-mulu': { hp: 520, attack: 164, x: 66, y: 46 }, + 'menghuo-final-officer-duosi': { hp: 460, attack: 152, x: 62, y: 60 }, + 'menghuo-final-officer-mengyou': { hp: 440, attack: 150, x: 61, y: 54 }, + 'menghuo-final-officer-dailai': { hp: 480, attack: 156, x: 64, y: 66 }, + 'menghuo-final-officer-ahuinan': { hp: 440, attack: 148, x: 62, y: 68 }, + 'menghuo-final-leader': { hp: 1800, attack: 190, x: 66, y: 50 } + } +}); + const fiftyFifthBattleAllyPositions: Record = { 'guan-yu': { x: 18, y: 76 }, 'zhang-fei': { x: 23, y: 78 }, diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index 47989ab..1b39606 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -2541,7 +2541,7 @@ const enemyAiByUnitId: Record = { 'menghuo-fourth-officer-mangyachang': 'aggressive', 'menghuo-fourth-officer-dongtuna': 'guard', 'menghuo-fourth-officer-ahuinan': 'guard', - 'menghuo-fourth-leader': 'hold', + 'menghuo-fourth-leader': 'aggressive', 'menghuo-fifth-scout-a': 'aggressive', 'menghuo-fifth-scout-b': 'aggressive', 'menghuo-fifth-scout-c': 'aggressive', @@ -2582,7 +2582,7 @@ const enemyAiByUnitId: Record = { 'menghuo-fifth-officer-mulu': 'aggressive', 'menghuo-fifth-officer-duosi': 'guard', 'menghuo-fifth-officer-mengyou': 'guard', - 'menghuo-fifth-leader': 'hold', + 'menghuo-fifth-leader': 'aggressive', 'menghuo-sixth-scout-a': 'aggressive', 'menghuo-sixth-scout-b': 'aggressive', 'menghuo-sixth-scout-c': 'aggressive', @@ -2624,7 +2624,7 @@ const enemyAiByUnitId: Record = { 'menghuo-sixth-officer-duosi': 'guard', 'menghuo-sixth-officer-mengyou': 'guard', 'menghuo-sixth-officer-dailai': 'aggressive', - 'menghuo-sixth-leader': 'hold', + 'menghuo-sixth-leader': 'aggressive', 'menghuo-final-scout-a': 'aggressive', 'menghuo-final-scout-b': 'aggressive', 'menghuo-final-scout-c': 'aggressive', @@ -2667,7 +2667,7 @@ const enemyAiByUnitId: Record = { 'menghuo-final-officer-mengyou': 'guard', 'menghuo-final-officer-dailai': 'aggressive', 'menghuo-final-officer-ahuinan': 'guard', - 'menghuo-final-leader': 'hold' + 'menghuo-final-leader': 'aggressive' }; const defaultEnemyAiByClass: Partial> = {