Add Chencang siege campaign chapter

This commit is contained in:
2026-06-24 11:03:12 +09:00
parent f9689c0149
commit 779b639bdf
10 changed files with 834 additions and 75 deletions

View File

@@ -51,6 +51,7 @@ import {
mengHuoPacificationBonds,
mengHuoSecondCaptureBonds,
nanzhongRecoveryBonds,
northernFifthBattleBonds,
northernFourthBattleBonds,
northernFirstBattleBonds,
northernSecondBattleBonds,
@@ -441,9 +442,10 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
'fifty-fifth-battle-northern-qishan-road',
'fifty-sixth-battle-tianshui-advance',
'fifty-seventh-battle-jieting-crisis',
'fifty-eighth-battle-qishan-retreat'
'fifty-eighth-battle-qishan-retreat',
'fifty-ninth-battle-chencang-siege'
],
nextHints: ['한중 창고 정비', '출전 무장 재편', '기산 출진로', '천수·가정 방면', '강유 합류', '다음 북벌 재정비']
nextHints: ['한중 창고 정비', '출전 무장 재편', '기산 출진로', '천수·가정 방면', '강유 합류', '진창 공성 재계산']
}
];
@@ -505,7 +507,8 @@ const campBattleIds = {
fiftyFifth: 'fifty-fifth-battle-northern-qishan-road',
fiftySixth: 'fifty-sixth-battle-tianshui-advance',
fiftySeventh: 'fifty-seventh-battle-jieting-crisis',
fiftyEighth: 'fifty-eighth-battle-qishan-retreat'
fiftyEighth: 'fifty-eighth-battle-qishan-retreat',
fiftyNinth: 'fifty-ninth-battle-chencang-siege'
} as const;
const defaultRequiredSortieUnitIds = ['liu-bei'];
@@ -1224,6 +1227,21 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
{ unitId: 'ma-liang', reason: '강유의 첫 출전과 후퇴 명분을 병사들에게 설득력 있게 정리합니다.' }
],
note: '기산 후퇴로는 강유를 처음 편성에 넣는 전투입니다. 제갈량을 중심으로 강유, 왕평, 조운, 마대, 보급·문서 담당 중 7명을 골라 퇴로를 지키십시오.'
},
'fifty-ninth-battle-chencang-siege': {
maxUnits: 7,
requiredUnitIds: ['zhuge-liang'],
excludedUnitIds: ['liu-bei'],
recommended: [
{ unitId: 'zhuge-liang', reason: '진창 공성전의 총지휘관입니다. 성벽 압박과 보급 철수 시점을 함께 계산해야 합니다.' },
{ unitId: 'jiang-wei', reason: '진창 길과 천수 방면 지형을 잇는 새 길잡이입니다. 강유의 역할이 전투 전반으로 넓어집니다.' },
{ unitId: 'wang-ping', reason: '공성 진영과 후방 표식을 안정시키는 장수입니다. 오래 끄는 성채전에서 진영 붕괴를 막습니다.' },
{ unitId: 'ma-dai', reason: '왕쌍의 기병 추격과 우회를 늦추는 기병 담당입니다. 조운을 빼는 선택도 여기서 고민하게 됩니다.' },
{ unitId: 'wei-yan', reason: '성문 압박을 맡길 돌파 장수입니다. 다만 무리한 전진을 보급 판단과 함께 제어해야 합니다.' },
{ unitId: 'huang-quan', reason: '진창 공성전의 군량 제한을 계산하는 보급 담당입니다. 장기전의 위험을 줄입니다.' },
{ unitId: 'fa-zheng', reason: '학소의 성벽 대응과 위군 군리의 빈틈을 읽는 책략 담당입니다.' }
],
note: '진창 공성전은 강유가 계속 중요하지만, 위연의 돌파와 조운·마대의 기동, 왕평의 진영 유지, 황권·법정의 보급 판단을 7명 안에서 갈라야 합니다.'
}
};
@@ -1257,6 +1275,21 @@ const sortieRulesByCampaignStep: Partial<Record<CampaignStep, SortieRuleDefiniti
{ unitId: 'ma-liang', reason: '강유의 첫 출전과 후퇴 명분을 군영의 말과 기록으로 정리합니다.' }
],
note: '기산 후퇴 이후는 엔딩이 아니라 북벌 재정비 단계입니다. 제갈량과 강유를 중심으로 다음 출정에 남길 교훈을 정리하십시오.'
},
'fifty-ninth-camp': {
maxUnits: 7,
requiredUnitIds: ['zhuge-liang'],
excludedUnitIds: ['liu-bei'],
recommended: [
{ unitId: 'zhuge-liang', reason: '진창 공성 이후 북방 계산을 다시 세워야 하는 중심입니다.' },
{ unitId: 'jiang-wei', reason: '진창 길과 천수 길을 비교해 다음 북벌에서 자신이 맡을 전선을 정리해야 합니다.' },
{ unitId: 'wei-yan', reason: '성채 앞 돌파 판단을 평가해야 합니다. 다음 전선에서 무리한 전진을 어떻게 쓸지 결정합니다.' },
{ unitId: 'wang-ping', reason: '공성 진영 표식과 후퇴 기준을 다음 북벌 군령으로 정리합니다.' },
{ unitId: 'ma-dai', reason: '왕쌍 추격 차단의 기병 운용을 다음 출정의 우회 기준으로 남깁니다.' },
{ unitId: 'huang-quan', reason: '오래 끈 공성전의 군량 손익을 장부로 다시 계산합니다.' },
{ unitId: 'fa-zheng', reason: '학소의 수비와 위군 대응을 계책 관점에서 정리합니다.' }
],
note: '진창 공성전 이후도 엔딩이 아니라 북벌 보급 재계산 단계입니다. 강유와 위연의 역할, 왕평과 황권의 제동 장치를 함께 보십시오.'
}
};
@@ -6207,6 +6240,87 @@ const campDialogues: CampDialogue[] = [
rewardExp: 27
}
]
},
{
id: 'northern-fifth-jiangwei-fazheng-wall',
title: '성벽을 재는 계책',
availableAfterBattleIds: [campBattleIds.fiftyNinth],
unitIds: ['jiang-wei', 'fa-zheng'],
bondId: 'jiang-wei__fa-zheng_northern-fifth',
rewardExp: 94,
lines: [
'강유: 진창의 성벽은 제가 알던 길과 달랐습니다. 길은 찾을 수 있지만, 학소 같은 수비장은 마음을 쉽게 비우지 않습니다.',
'법정: 그래서 성벽을 깨기 전에 성벽이 버티는 까닭을 보아야 합니다. 사람, 군량, 봉화, 명분 중 어느 하나라도 흔들리면 문은 칼보다 먼저 약해집니다.',
'강유: 다음에는 제가 길만 말하지 않겠습니다. 성이 버티는 시간을 함께 계산하겠습니다.'
],
choices: [
{
id: 'mark-wall-timing',
label: '성벽의 시간을 적는다',
response: '강유는 진창 성벽의 수비 교대와 봉화 시간을 기록했고, 법정은 다음 공성 계책의 기준으로 삼았습니다.',
rewardExp: 32
},
{
id: 'compare-weak-points',
label: '약한 지점을 비교한다',
response: '법정은 성문보다 먼저 보급막과 봉화대를 짚었고, 강유는 그 지점을 잇는 낮은 길을 덧그렸습니다.',
rewardExp: 30
}
]
},
{
id: 'northern-fifth-weiyan-jiangwei-restraint',
title: '돌파와 절제',
availableAfterBattleIds: [campBattleIds.fiftyNinth],
unitIds: ['wei-yan', 'jiang-wei'],
bondId: 'wei-yan__jiang-wei_northern-fifth',
rewardExp: 90,
lines: [
'위연: 성이 굳다고 물러서기만 하면 북벌은 늘 장부 위에서 끝날 것이오. 한 번은 목을 걸고 찔러야 합니다.',
'강유: 찌를 곳을 아는 것과 돌아올 길을 버리는 것은 다릅니다. 오늘 왕쌍이 뒤를 물었을 때 그 차이가 보였습니다.',
'위연: 좋소. 다음에는 그대가 길을 보시오. 나는 그 길이 진짜라면 가장 먼저 들어가겠소.'
],
choices: [
{
id: 'bind-breakthrough-to-return',
label: '돌파와 귀환을 묶는다',
response: '강유는 위연의 돌파로에 귀환 표식을 함께 그렸고, 위연은 다음 출전에서 무작정 깊이 들어가지 않겠다고 답했습니다.',
rewardExp: 31
},
{
id: 'test-forward-camp',
label: '전진 진영을 시험한다',
response: '위연의 전진 진영과 강유의 낮은 길이 함께 검토되며, 다음 북방 전장의 공격적인 선택지가 살아났습니다.',
rewardExp: 29
}
]
},
{
id: 'northern-fifth-huangquan-maliang-ledger',
title: '군량과 문서',
availableAfterBattleIds: [campBattleIds.fiftyNinth],
unitIds: ['huang-quan', 'ma-liang'],
bondId: 'huang-quan__ma-liang_northern-fifth',
rewardExp: 88,
lines: [
'황권: 진창 앞에서 하루를 더 버티려면, 한중 창고에서는 사흘을 먼저 움직여야 합니다.',
'마량: 병사들은 성이 열리지 않은 까닭을 패배로만 듣지 않아야 합니다. 돌아온 이유를 문서로 남기겠습니다.',
'황권: 숫자와 말이 함께 있어야 다음 북벌이 조급해지지 않습니다.'
],
choices: [
{
id: 'seal-chencang-ledger',
label: '진창 장부를 봉한다',
response: '황권은 소모된 군량과 지킨 수레를 따로 적었고, 마량은 진창 철수의 이유를 군영 고시문으로 정리했습니다.',
rewardExp: 30
},
{
id: 'write-regroup-notice',
label: '재정비 고시문을 쓴다',
response: '마량은 병사들이 낙담하지 않도록 진창에서 얻은 교훈을 적었고, 황권은 다음 지급 기준을 그 아래에 붙였습니다.',
rewardExp: 28
}
]
}
];
@@ -8903,6 +9017,36 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['콩 28', '상처약 18']
}
]
},
{
id: 'northern-fifth-chencang-ledger',
title: '진창 공성 장부',
location: '진창 외곽 공성막',
availableAfterBattleIds: [campBattleIds.fiftyNinth],
bondId: 'huang-quan__ma-liang_northern-fifth',
description: '황권과 마량이 진창 공성전에서 소모한 군량, 지킨 수레, 병사들에게 남길 재정비 고시문을 하나의 장부로 묶습니다.',
lines: [
'황권: 성문이 열리지 않아도 장부는 남습니다. 어느 날까지 버틸 수 있었는지 알아야 다음 전선에서 멈출 수 있습니다.',
'마량: 병사들에게는 왜 돌아왔는지도 말해야 합니다. 진창은 물러선 이름이 아니라 다음 계산의 경계입니다.',
'공성막 안에는 학소의 성벽, 왕쌍의 추격로, 촉한군이 지킨 수레 수가 함께 적혔습니다.'
],
choices: [
{
id: 'seal-chencang-siege-ledger',
label: '공성 장부를 봉한다',
response: '황권은 진창 공성 장부를 봉했고, 마량은 병사들이 낙담하지 않도록 재정비 고시문을 붙였습니다.',
bondExp: 72,
itemRewards: ['진창 공성 장부 1']
},
{
id: 'assign-chencang-regroup-route',
label: '재정비 보급로를 정한다',
response: '강유의 낮은 길, 왕평의 진영 표식, 황권의 군량 계산이 다음 북벌 보급로 후보로 묶였습니다.',
bondExp: 68,
gold: 2580,
itemRewards: ['콩 30', '상처약 20']
}
]
}
];
@@ -9009,7 +9153,8 @@ export class CampScene extends Phaser.Scene {
battleId === campBattleIds.fiftyFifth ||
battleId === campBattleIds.fiftySixth ||
battleId === campBattleIds.fiftySeventh ||
battleId === campBattleIds.fiftyEighth
battleId === campBattleIds.fiftyEighth ||
battleId === campBattleIds.fiftyNinth
) {
this.campaign = ensureCampaignRosterUnits(
[
@@ -9030,7 +9175,7 @@ export class CampScene extends Phaser.Scene {
...hanzhongOpeningRecruitUnits,
...hanzhongScoutRecruitUnits,
...hanzhongMainRecruitUnits,
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth ? jiangWeiRecruitUnits : [])
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth || battleId === campBattleIds.fiftyNinth ? jiangWeiRecruitUnits : [])
],
[
...xuzhouRecruitBonds,
@@ -9070,9 +9215,10 @@ export class CampScene extends Phaser.Scene {
...mengHuoFinalCaptureBonds,
...northernFirstBattleBonds,
...northernSecondBattleBonds,
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth ? northernThirdBattleBonds : []),
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth ? jiangWeiRecruitBonds : []),
...(battleId === campBattleIds.fiftyEighth ? northernFourthBattleBonds : [])
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth || battleId === campBattleIds.fiftyNinth ? northernThirdBattleBonds : []),
...(battleId === campBattleIds.fiftySeventh || battleId === campBattleIds.fiftyEighth || battleId === campBattleIds.fiftyNinth ? jiangWeiRecruitBonds : []),
...(battleId === campBattleIds.fiftyEighth || battleId === campBattleIds.fiftyNinth ? northernFourthBattleBonds : []),
...(battleId === campBattleIds.fiftyNinth ? northernFifthBattleBonds : [])
]
);
this.report = this.campaign.firstBattleReport ?? this.report;
@@ -9713,6 +9859,9 @@ export class CampScene extends Phaser.Scene {
if (this.campaign?.step === 'northern-campaign-prep-camp') {
return '북벌 준비 군영';
}
if (battleId === campBattleIds.fiftyNinth) {
return '진창 공성전 후 군영';
}
if (battleId === campBattleIds.fiftyEighth) {
return '기산 후퇴로 후 군영';
}