Add Meng Huo pacification battle

This commit is contained in:
2026-06-23 20:59:52 +09:00
parent eb471d9648
commit 688b51f3cc
11 changed files with 824 additions and 63 deletions

View File

@@ -41,6 +41,7 @@ import {
luoCastleRecruitBonds,
luoCastleRecruitUnits,
maichengIsolationBonds,
mengHuoPacificationBonds,
nanzhongRecoveryBonds,
wulingRecruitBonds,
wulingRecruitUnits,
@@ -407,9 +408,10 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
'forty-fourth-battle-maicheng-isolation',
'forty-fifth-battle-yiling-vanguard',
'forty-sixth-battle-yiling-fire',
'forty-seventh-battle-nanzhong-stabilization'
'forty-seventh-battle-nanzhong-stabilization',
'forty-eighth-battle-meng-huo-main-force'
],
nextHints: ['왕업 선언', '번성 포위', '형주 위기', '이릉 화공', '남중 안정']
nextHints: ['왕업 선언', '번성 포위', '형주 위기', '이릉 화공', '남중 안정', '맹획 회유']
}
];
@@ -460,7 +462,8 @@ const campBattleIds = {
fortyFourth: 'forty-fourth-battle-maicheng-isolation',
fortyFifth: 'forty-fifth-battle-yiling-vanguard',
fortySixth: 'forty-sixth-battle-yiling-fire',
fortySeventh: 'forty-seventh-battle-nanzhong-stabilization'
fortySeventh: 'forty-seventh-battle-nanzhong-stabilization',
fortyEighth: 'forty-eighth-battle-meng-huo-main-force'
} as const;
const defaultRequiredSortieUnitIds = ['liu-bei'];
@@ -1021,6 +1024,20 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
{ unitId: 'ma-chao', reason: '남중 기병과 빠른 차단선에 대응하는 강한 측면 카드입니다.' }
],
note: '남중 안정로는 백제성 이후 첫 전투입니다. 유비가 아니라 제갈량이 필수이며, 산길, 마을, 창고를 동시에 보아야 합니다.'
},
'forty-eighth-battle-meng-huo-main-force': {
maxUnits: 7,
requiredUnitIds: ['zhuge-liang'],
recommended: [
{ unitId: 'zhuge-liang', reason: '맹획 생포와 회유 방침을 직접 지휘하는 필수 장수입니다.' },
{ unitId: 'ma-liang', reason: '회유 문서와 마을 설득 선택지의 핵심 참모입니다.' },
{ unitId: 'wang-ping', reason: '늪지와 산채 길을 읽어 복병과 포로 수용소를 안정시킵니다.' },
{ unitId: 'huang-quan', reason: '포로 명부와 군량 장부를 나누어 약탈 없는 전후 처리를 돕습니다.' },
{ unitId: 'zhao-yun', reason: '맹수 기병의 첫 돌격을 받아 내고 후위를 회수합니다.' },
{ unitId: 'ma-chao', reason: '강한 기병 압박으로 맹획의 측면 돌파를 묶습니다.' },
{ unitId: 'huang-zhong', reason: '고지 궁병과 주술사를 안정적으로 견제합니다.' }
],
note: '맹획 본대전은 제갈량이 필수이며, 맹획을 베기보다 생포해 돌려보낼 명분을 만드는 전투입니다. 회유, 포로 장부, 맹수 기병 대응을 균형 있게 고르십시오.'
}
};
@@ -4996,6 +5013,87 @@ const campDialogues: CampDialogue[] = [
rewardExp: 17
}
]
},
{
id: 'menghuo-zhuge-maliang-release',
title: '풀어 보내는 이유',
availableAfterBattleIds: [campBattleIds.fortyEighth],
unitIds: ['zhuge-liang', 'ma-liang'],
bondId: 'zhuge-liang__ma-liang_menghuo',
rewardExp: 58,
lines: [
'마량: 맹획을 잡았는데 바로 돌려보내면 병사들이 의아해할 것입니다.',
'제갈량: 남중은 칼로 눌러도 산으로 숨습니다. 맹획이 직접 보고 돌아가야, 마을들이 촉한군의 뜻을 의심하지 않습니다.',
'마량: 그 뜻을 문서로 남기겠습니다. 처단이 아니라 회유라는 군령을 분명히 하겠습니다.'
],
choices: [
{
id: 'write-release-edict',
label: '석방 군령을 적는다',
response: '마량은 맹획 석방의 이유를 짧고 분명하게 적었고, 제갈량은 포로와 병사 앞에서 그 문장을 읽게 했습니다.',
rewardExp: 20
},
{
id: 'explain-to-officers',
label: '장수들에게 설명한다',
response: '제갈량은 장수들에게 남중을 얻는 싸움은 반복해서 설득하는 싸움이라고 설명했습니다.',
rewardExp: 19
}
]
},
{
id: 'menghuo-zhaoyun-machao-charge',
title: '맹수 돌격을 막은 기병',
availableAfterBattleIds: [campBattleIds.fortyEighth],
unitIds: ['zhao-yun', 'ma-chao'],
bondId: 'zhao-yun__ma-chao_menghuo',
rewardExp: 54,
lines: [
'마초: 남중의 기병은 말만 타는 것이 아니더군. 짐승과 함께 밀고 들어오니 보통 돌격과 달랐소.',
'조운: 기세를 부러뜨리되 깊이 쫓지 않는 것이 중요했습니다. 오늘의 목표는 섬멸이 아니었으니까요.',
'마초: 다음에는 더 거칠게 올 것이오. 그렇다면 더 단단히 받아 주면 되겠지.'
],
choices: [
{
id: 'hold-beast-charge-line',
label: '돌격 차단선을 정리한다',
response: '조운과 마초는 맹수 기병이 몰리는 길목과 기병이 빠질 길을 따로 표시했습니다.',
rewardExp: 18
},
{
id: 'restrain-pursuit',
label: '추격 금지를 확인한다',
response: '마초는 병사들에게 깊은 추격을 금했고, 조운은 포로가 흩어지지 않도록 후위를 세웠습니다.',
rewardExp: 17
}
]
},
{
id: 'menghuo-huangquan-wangping-captives',
title: '포로와 산길 장부',
availableAfterBattleIds: [campBattleIds.fortyEighth],
unitIds: ['huang-quan', 'wang-ping'],
bondId: 'huang-quan__wang-ping_menghuo',
rewardExp: 54,
lines: [
'황권: 포로를 군량 장부처럼 세면 안 됩니다. 누구는 반란군이고, 누구는 끌려온 마을 사람입니다.',
'왕평: 산길도 같습니다. 군대가 쓰는 길과 마을이 살아가는 길을 구분하지 않으면 다음에 모두 막힙니다.',
'황권: 포로 명부와 산길 표식을 함께 정리합시다. 다음 회유의 근거가 될 것입니다.'
],
choices: [
{
id: 'separate-captive-ledger',
label: '포로 명부를 나눈다',
response: '황권은 반란군, 마을 사람, 길잡이를 따로 적었고 왕평은 각자가 돌아갈 길을 표시했습니다.',
rewardExp: 18
},
{
id: 'mark-return-routes',
label: '귀환 산길을 표시한다',
response: '왕평은 포로가 돌아갈 낮은 산길을 정했고, 황권은 촉한군이 침범하지 말아야 할 마을 밭을 함께 적었습니다.',
rewardExp: 17
}
]
}
];
@@ -7007,6 +7105,65 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['마을 회유 문서 2']
}
]
},
{
id: 'menghuo-captive-camp-reassurance',
title: '포로 수용소 안정',
location: '남중 포로 수용소',
availableAfterBattleIds: [campBattleIds.fortyEighth],
bondId: 'huang-quan__wang-ping_menghuo',
description: '황권과 왕평이 포로 수용소를 돌며 반란군, 끌려온 주민, 길잡이를 구분하고 석방 순서를 정합니다.',
lines: [
'왕평: 묶인 사람들 중에는 병사보다 마을 사람이 많습니다. 모두 적으로 두면 다음 산길이 닫힙니다.',
'황권: 명부를 세 갈래로 나누겠습니다. 죄를 물을 자, 돌려보낼 자, 길 안내를 부탁할 자를 섞지 않겠습니다.',
'수용소의 말뚝에는 처벌보다 먼저 귀환 순서를 알리는 작은 패가 걸렸습니다.'
],
choices: [
{
id: 'release-dragged-villagers',
label: '끌려온 주민을 돌려보낸다',
response: '왕평은 돌아갈 산길을 안내했고, 황권은 주민들의 이름을 명부에서 따로 지워 원한을 줄였습니다.',
bondExp: 44,
itemRewards: ['남중 포로 명부 1']
},
{
id: 'sort-rebel-captives',
label: '반란군 포로를 분리한다',
response: '황권은 반란군 포로를 수장별로 나누었고, 왕평은 서로 다른 마을 사람이 함께 묶이지 않도록 조정했습니다.',
bondExp: 42,
gold: 1420,
itemRewards: ['상처약 9']
}
]
},
{
id: 'menghuo-southern-market-reopen',
title: '남중 장터 재개',
location: '남중 산마을 장터',
availableAfterBattleIds: [campBattleIds.fortyEighth],
bondId: 'zhuge-liang__ma-liang_menghuo',
description: '제갈량과 마량이 전투 뒤 닫힌 장터를 다시 열어, 촉한군이 약탈군이 아니라 질서를 되돌리는 군대임을 보입니다.',
lines: [
'마량: 장터가 닫힌 채로 오래가면 마을 사람들은 산으로 숨고, 반란군은 다시 그 틈을 파고들 것입니다.',
'제갈량: 군량은 값을 치르고 사십시오. 오늘 장터에서 보이는 태도가 다음 전장의 말보다 빠르게 퍼집니다.',
'장터에는 촉한군의 보호 표식과 물품 가격표가 함께 걸렸습니다.'
],
choices: [
{
id: 'pay-for-supplies',
label: '군량값을 치른다',
response: '제갈량은 군량값을 먼저 지급하게 했고, 마량은 그 사실을 마을 어른들 앞에서 분명히 알렸습니다.',
bondExp: 44,
itemRewards: ['콩 12']
},
{
id: 'post-market-rules',
label: '장터 군령을 게시한다',
response: '마량은 약탈 금지와 보호 구역을 적은 군령을 걸었고, 제갈량은 이를 어기는 병사를 엄히 다스리겠다고 밝혔습니다.',
bondExp: 42,
itemRewards: ['맹획 회유 서신 1']
}
]
}
];
@@ -7102,7 +7259,8 @@ export class CampScene extends Phaser.Scene {
battleId === campBattleIds.fortyFourth ||
battleId === campBattleIds.fortyFifth ||
battleId === campBattleIds.fortySixth ||
battleId === campBattleIds.fortySeventh
battleId === campBattleIds.fortySeventh ||
battleId === campBattleIds.fortyEighth
) {
this.campaign = ensureCampaignRosterUnits(
[
@@ -7152,7 +7310,8 @@ export class CampScene extends Phaser.Scene {
...maichengIsolationBonds,
...yilingVanguardBonds,
...yilingFireBonds,
...nanzhongRecoveryBonds
...nanzhongRecoveryBonds,
...mengHuoPacificationBonds
]
);
this.report = this.campaign.firstBattleReport ?? this.report;
@@ -7790,6 +7949,9 @@ export class CampScene extends Phaser.Scene {
if (this.campaign?.step === 'baidi-entrustment-camp') {
return '백제성 유탁 후 군영';
}
if (battleId === campBattleIds.fortyEighth) {
return '맹획 본대전 후 군영';
}
if (battleId === campBattleIds.fortySeventh) {
return '남중 안정로 후 군영';
}