Add Hanzhong decisive battle chapter

This commit is contained in:
2026-06-23 14:09:12 +09:00
parent 24b7db0b14
commit b4c34afeed
11 changed files with 894 additions and 41 deletions

View File

@@ -19,6 +19,7 @@ import {
fuPassRecruitUnits,
guiyangRecruitBonds,
guiyangRecruitUnits,
hanzhongDecisiveBonds,
hanzhongOpeningRecruitBonds,
hanzhongOpeningRecruitUnits,
hanzhongMainRecruitBonds,
@@ -346,7 +347,8 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
battleIds: [
'thirty-fourth-battle-jiameng-pass',
'thirty-fifth-battle-yangping-scout',
'thirty-sixth-battle-dingjun-vanguard'
'thirty-sixth-battle-dingjun-vanguard',
'thirty-seventh-battle-hanzhong-decisive'
],
nextHints: ['왕업 선언', '오호대장군', '북벌 준비']
}
@@ -388,7 +390,8 @@ const campBattleIds = {
thirtyThird: 'thirty-third-battle-chengdu-surrender',
thirtyFourth: 'thirty-fourth-battle-jiameng-pass',
thirtyFifth: 'thirty-fifth-battle-yangping-scout',
thirtySixth: 'thirty-sixth-battle-dingjun-vanguard'
thirtySixth: 'thirty-sixth-battle-dingjun-vanguard',
thirtySeventh: 'thirty-seventh-battle-hanzhong-decisive'
} as const;
const requiredSortieUnitIds = new Set(['liu-bei']);
@@ -795,6 +798,19 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
{ unitId: 'zhuge-liang', reason: '한중 본전으로 이어질 산악 전선과 왕평 설득을 설계합니다.' }
],
note: '정군산 전초전은 스물한 명 중 여섯 명만 출전합니다. 황충과 법정의 고지 압박, 마초·마대의 우회 기병, 제갈량의 큰 전선 설계를 모두 담을지 고민하게 됩니다.'
},
'thirty-seventh-battle-hanzhong-decisive': {
maxUnits: 7,
recommended: [
{ unitId: 'liu-bei', reason: '한중을 얻는 명분과 패배 조건의 중심입니다.' },
{ unitId: 'huang-zhong', reason: '정군산의 여세를 이어 고지 압박을 맡는 핵심 장수입니다.' },
{ unitId: 'fa-zheng', reason: '조조군 본진을 흔드는 유인책과 고지 운용의 핵심 참모입니다.' },
{ unitId: 'wang-ping', reason: '한중 산길과 보급로를 잇는 길잡이이며 생존 목표와 맞물립니다.' },
{ unitId: 'ma-chao', reason: '북쪽 기병대를 묶고 퇴로를 흔드는 기동 축입니다.' },
{ unitId: 'ma-dai', reason: '마초의 돌격을 회수하고 좁은 산길 기병 운용을 보조합니다.' },
{ unitId: 'zhuge-liang', reason: '한중 승리 이후 한중왕 즉위와 촉한 건국 흐름까지 설계합니다.' }
],
note: '한중 결전은 스물두 명 중 일곱 명만 출전합니다. 왕평까지 합류한 뒤 처음으로 출전 슬롯이 늘지만, 여전히 핵심 무장과 보조 참모를 모두 담기는 어렵습니다.'
}
};
@@ -3795,6 +3811,87 @@ const campDialogues: CampDialogue[] = [
rewardExp: 12
}
]
},
{
id: 'liu-wang-after-hanzhong-decisive',
title: '한중의 새 주인',
availableAfterBattleIds: [campBattleIds.thirtySeventh],
unitIds: ['liu-bei', 'wang-ping'],
bondId: 'liu-bei__wang-ping',
rewardExp: 40,
lines: [
'왕평: 한중의 병사들은 이긴 사람보다 오래 지켜 줄 사람을 기다립니다.',
'유비: 내가 이 땅을 얻었다면, 먼저 이 땅의 길과 사람을 배워야겠구려.',
'왕평: 그 말씀을 병사들에게 전하겠습니다. 길을 아는 자들이 먼저 마음을 열 것입니다.'
],
choices: [
{
id: 'promise-hanzhong-stability',
label: '한중을 안정시키겠다',
response: '유비는 왕평에게 한중 병사들의 가족과 창고를 먼저 돌보라고 명했고, 왕평은 산길 병사들의 마음을 모으기 시작했습니다.',
rewardExp: 15
},
{
id: 'listen-local-soldiers',
label: '현지 병사의 말을 듣는다',
response: '왕평은 오래된 길잡이와 창고병을 불러 한중을 지키는 실제 고충을 유비에게 전했습니다.',
rewardExp: 14
}
]
},
{
id: 'fa-wang-after-hanzhong-decisive',
title: '산길 계책',
availableAfterBattleIds: [campBattleIds.thirtySeventh],
unitIds: ['fa-zheng', 'wang-ping'],
bondId: 'fa-zheng__wang-ping',
rewardExp: 38,
lines: [
'법정: 오늘의 승리는 적을 밀어낸 것보다 길을 끊은 순서가 좋았습니다.',
'왕평: 계책이 너무 빠르면 병사가 따라오지 못합니다. 길은 속도보다 끊기지 않는 것이 먼저입니다.',
'법정: 그 균형을 알았으니, 다음에는 더 멀리 움직일 수 있겠군요.'
],
choices: [
{
id: 'plan-supply-chain',
label: '보급로를 다시 짠다',
response: '법정과 왕평은 전투에서 확인한 창고, 물길, 산길을 하나의 보급망으로 다시 정리했습니다.',
rewardExp: 14
},
{
id: 'mark-decoy-routes',
label: '유인로를 표시한다',
response: '왕평은 실제로 쓸 길과 적에게 보일 길을 구분했고, 법정은 그 차이를 다음 계책의 재료로 삼았습니다.',
rewardExp: 14
}
]
},
{
id: 'huang-fa-after-hanzhong-decisive',
title: '정군산의 여세',
availableAfterBattleIds: [campBattleIds.thirtySeventh],
unitIds: ['huang-zhong', 'fa-zheng'],
bondId: 'huang-zhong__fa-zheng',
rewardExp: 38,
lines: [
'황충: 오늘은 늙은 몸보다 군사의 눈이 먼저 적을 베었소.',
'법정: 장군의 칼이 움직일 때를 맞췄을 뿐입니다. 그 순간을 놓치지 않은 것은 장군입니다.',
'황충: 그렇다면 다음에도 나를 너무 아끼지 마시오. 좋은 때라면 늙은 말도 달릴 줄 아오.'
],
choices: [
{
id: 'honor-veteran-charge',
label: '노장의 돌격을 기린다',
response: '법정은 황충의 돌격로를 병사들에게 설명했고, 노장의 결단은 한중 승리의 상징이 되었습니다.',
rewardExp: 14
},
{
id: 'temper-next-charge',
label: '다음 돌격을 아낀다',
response: '황충은 법정의 만류를 웃으며 받아들였고, 다음 큰 싸움을 위해 병사들의 숨을 고르게 했습니다.',
rewardExp: 13
}
]
}
];
@@ -5084,6 +5181,66 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['탁주 4']
}
]
},
{
id: 'hanzhong-king-audience',
title: '한중왕 즉위 논의',
location: '한중 본막',
availableAfterBattleIds: [campBattleIds.thirtySeventh],
bondId: 'liu-bei__wang-ping',
description: '유비, 제갈량, 왕평이 한중의 이름을 어떻게 세우고 백성에게 어떤 약속을 먼저 보일지 논의합니다.',
lines: [
'제갈량: 한중을 얻은 뒤에는 군사보다 이름이 먼저 움직입니다. 이름이 있어야 백성이 어디에 기대야 하는지 압니다.',
'왕평: 한중 병사들은 새 명령보다 새 약속을 더 기다립니다.',
'유비는 한중왕의 이름이 칼끝의 승리만이 아니라 백성의 질서가 되어야 함을 마음에 새겼습니다.'
],
choices: [
{
id: 'prepare-king-edict',
label: '즉위 격문을 준비한다',
response: '제갈량은 유비의 뜻을 격문 초안으로 정리했고, 왕평은 한중 병사들이 이해할 말로 고쳐 적었습니다.',
bondExp: 34,
itemRewards: ['한중왕 격문 초안 1']
},
{
id: 'promise-local-relief',
label: '한중 구휼을 약속한다',
response: '유비는 창고를 먼저 백성과 병사 가족에게 열도록 명했고, 한중의 불안은 조금씩 잦아들었습니다.',
bondExp: 32,
gold: 720,
itemRewards: ['콩 12', '상처약 6']
}
]
},
{
id: 'hanzhong-north-gate-supply',
title: '북문 보급 정비',
location: '한중 북쪽 창고',
availableAfterBattleIds: [campBattleIds.thirtySeventh],
bondId: 'fa-zheng__wang-ping',
description: '법정과 왕평이 조조군이 남긴 창고와 퇴로를 조사해 다음 국경 전선의 보급 기준을 세웁니다.',
lines: [
'법정: 이 창고가 비면 한중은 승리한 날부터 다시 흔들립니다.',
'왕평: 산길 창고는 큰 것 하나보다 작은 것 셋이 낫습니다. 막히는 길이 달마다 달라지기 때문입니다.',
'두 사람은 조조군이 남긴 표식과 한중 병사들의 기억을 맞춰 북문 보급망을 다시 그렸습니다.'
],
choices: [
{
id: 'split-mountain-stores',
label: '산길 창고를 나눈다',
response: '왕평은 보급을 작은 창고로 나누었고, 법정은 적이 한 번에 끊기 어렵도록 운송 순서를 바꾸었습니다.',
bondExp: 34,
itemRewards: ['한중 보급표 1', '탁주 4']
},
{
id: 'audit-cao-stores',
label: '조조군 창고를 조사한다',
response: '남겨진 장부에서 말먹이와 활시위가 발견되어, 다음 전선에서 기병과 궁병을 함께 운용할 여유가 생겼습니다.',
bondExp: 32,
gold: 760,
itemRewards: ['말먹이 2', '활시위 2']
}
]
}
];
@@ -5170,6 +5327,52 @@ export class CampScene extends Phaser.Scene {
return;
}
if (battleId === campBattleIds.thirtySeventh) {
this.campaign = ensureCampaignRosterUnits(
[
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits,
...jingzhouRecruitUnits,
...guiyangRecruitUnits,
...wulingRecruitUnits,
...changshaRecruitUnits,
...yizhouRecruitUnits,
...fuPassRecruitUnits,
...luoCastleRecruitUnits,
...luoCastleProperRecruitUnits,
...chengduPressureRecruitUnits,
...chengduSurrenderRecruitUnits,
...hanzhongOpeningRecruitUnits,
...hanzhongScoutRecruitUnits,
...hanzhongMainRecruitUnits
],
[
...xuzhouRecruitBonds,
...caoBreakRecruitBonds,
...liuBiaoRecruitBonds,
...zhugeRecruitBonds,
...jingzhouRecruitBonds,
...guiyangRecruitBonds,
...wulingRecruitBonds,
...changshaRecruitBonds,
...yizhouRecruitBonds,
...fuPassRecruitBonds,
...luoCastleRecruitBonds,
...luoCastleProperRecruitBonds,
...chengduPressureRecruitBonds,
...chengduSurrenderRecruitBonds,
...hanzhongOpeningRecruitBonds,
...hanzhongScoutRecruitBonds,
...hanzhongMainRecruitBonds,
...hanzhongDecisiveBonds
]
);
this.report = this.campaign.firstBattleReport ?? this.report;
return;
}
if (battleId === campBattleIds.thirtySixth) {
this.campaign = ensureCampaignRosterUnits(
[
@@ -5651,6 +5854,9 @@ export class CampScene extends Phaser.Scene {
private currentCampTitle() {
const battleId = this.currentCampBattleId();
if (battleId === campBattleIds.thirtySeventh) {
return '한중 결전 후 군영';
}
if (battleId === campBattleIds.thirtySixth) {
return '정군산 전초전 후 군영';
}