Add Mianzhu Gate sortie chapter

This commit is contained in:
2026-06-23 12:15:04 +09:00
parent 004ec3cfff
commit 9ac621da76
11 changed files with 870 additions and 35 deletions

View File

@@ -7,6 +7,8 @@ import { getSortieFlow } from '../data/campaignFlow';
import {
caoBreakRecruitBonds,
caoBreakRecruitUnits,
chengduPressureRecruitBonds,
chengduPressureRecruitUnits,
changshaRecruitBonds,
changshaRecruitUnits,
firstBattleBonds,
@@ -322,7 +324,8 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
'twenty-eighth-battle-fu-pass-entry',
'twenty-ninth-battle-luo-outer-wall',
'thirtieth-battle-luofeng-ambush',
'thirty-first-battle-luo-main-gate'
'thirty-first-battle-luo-main-gate',
'thirty-second-battle-mianzhu-gate'
],
nextHints: ['형주 방위', '익주 진입', '방통·법정 합류']
},
@@ -367,7 +370,8 @@ const campBattleIds = {
twentyEighth: 'twenty-eighth-battle-fu-pass-entry',
twentyNinth: 'twenty-ninth-battle-luo-outer-wall',
thirtieth: 'thirtieth-battle-luofeng-ambush',
thirtyFirst: 'thirty-first-battle-luo-main-gate'
thirtyFirst: 'thirty-first-battle-luo-main-gate',
thirtySecond: 'thirty-second-battle-mianzhu-gate'
} as const;
const requiredSortieUnitIds = new Set(['liu-bei']);
@@ -714,6 +718,18 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
{ unitId: 'zhang-fei', reason: '성문 앞 친위대를 짧게 무너뜨리는 돌파력이 필요합니다.' }
],
note: '낙성 본성 공략은 열여섯 명 중 여섯 명만 출전합니다. 설득을 노리면 책사와 오의를, 빠른 돌파를 노리면 장비와 황충 같은 전투 무장을 우선하십시오.'
},
'thirty-second-battle-mianzhu-gate': {
maxUnits: 6,
recommended: [
{ unitId: 'liu-bei', reason: '성도 앞 항복 명분과 패배 조건의 중심입니다.' },
{ unitId: 'yan-yan', reason: '엄안의 첫 출전입니다. 이엄과 익주 장수들을 설득하는 증거가 됩니다.' },
{ unitId: 'fa-zheng', reason: '성도 수비장들의 심리와 면죽관 창고 사정을 읽는 책사입니다.' },
{ unitId: 'wu-yi', reason: '익주 안쪽 길과 관문 배치를 아는 새 합류 장수입니다.' },
{ unitId: 'pang-tong', reason: '무리한 돌파 대신 항복 권고와 퇴로 확보를 동시에 계산합니다.' },
{ unitId: 'huang-zhong', reason: '관문 궁병과 고지 수비를 안정적으로 견제합니다.' }
],
note: '면죽관 압박전은 열일곱 명 중 여섯 명만 출전합니다. 엄안이 새로 후보에 들어오며, 이엄을 설득하려면 익주 출신 장수와 책사를 함께 고르는 편이 좋습니다.'
}
};
@@ -3309,6 +3325,87 @@ const campDialogues: CampDialogue[] = [
rewardExp: 11
}
]
},
{
id: 'liu-li-after-mianzhu',
title: '성도 앞의 군율',
availableAfterBattleIds: [campBattleIds.thirtySecond],
unitIds: ['liu-bei', 'li-yan'],
bondId: 'liu-bei__li-yan',
rewardExp: 36,
lines: [
'이엄: 면죽관을 내주었으나, 성도 앞의 군율까지 무너지면 익주는 오래 앙금을 품을 것입니다.',
'유비: 항복한 장수의 말이라도 백성을 살리는 말이면 곧 군령이오. 그대가 익주 병사의 마음을 잡아 주시오.',
'이엄: 그렇다면 창고와 관문을 맡아, 항복한 병사도 약탈을 두려워하지 않게 하겠습니다.'
],
choices: [
{
id: 'trust-li-yan-discipline',
label: '군율 정비를 맡긴다',
response: '이엄은 면죽관 창고 명부를 다시 정리하고, 항복 병사에게도 같은 배급 규칙을 적용했습니다.',
rewardExp: 14
},
{
id: 'ask-li-yan-chengdu-order',
label: '성도 질서를 묻는다',
response: '이엄은 성도 안쪽 창고, 문지기, 장수들의 이해관계를 짚어 다음 권고문의 근거를 보탰습니다.',
rewardExp: 13
}
]
},
{
id: 'zhuge-li-after-mianzhu',
title: '내정과 책략',
availableAfterBattleIds: [campBattleIds.thirtySecond],
unitIds: ['zhuge-liang', 'li-yan'],
bondId: 'zhuge-liang__li-yan',
rewardExp: 34,
lines: [
'제갈량: 성을 얻는 일보다 얻은 뒤의 질서가 더 어렵습니다. 이엄 장군은 그 무게를 알고 있군요.',
'이엄: 저는 관문을 막는 법은 알지만, 사람 마음을 여는 법은 아직 배워야 합니다.',
'제갈량: 그렇다면 관문의 숫자와 사람의 사정을 함께 보지요. 다음 싸움은 이미 싸움 뒤의 정치와 맞닿아 있습니다.'
],
choices: [
{
id: 'map-chengdu-storehouses',
label: '성도 창고도를 맞춘다',
response: '제갈량의 큰 지도 위에 이엄의 창고 명부가 겹치며, 성도 항복 뒤 혼란을 줄일 길이 보였습니다.',
rewardExp: 13
},
{
id: 'write-surrender-terms',
label: '항복 조건을 다듬는다',
response: '두 사람은 유장에게 보낼 문장에 처벌보다 안정을 먼저 적었습니다.',
rewardExp: 12
}
]
},
{
id: 'yan-li-after-mianzhu',
title: '익주 장수의 결단',
availableAfterBattleIds: [campBattleIds.thirtySecond],
unitIds: ['yan-yan', 'li-yan'],
bondId: 'yan-yan__li-yan',
rewardExp: 34,
lines: [
'엄안: 나도 성문 위에서 끝까지 버티려 했소. 그러나 백성이 살아야 장수의 절개도 남는 법이오.',
'이엄: 노장께서 먼저 길을 여셨기에 저도 검을 내려놓을 수 있었습니다.',
'엄안: 이제는 우리가 익주 장수들에게 말해야 하오. 항복이 부끄러움이 아니라 백성을 살리는 선택이 될 수 있다고.'
],
choices: [
{
id: 'share-yizhou-officer-names',
label: '익주 장수 명단을 맞춘다',
response: '엄안과 이엄은 끝까지 버틸 장수와 설득 가능한 장수를 나누어, 다음 전장의 말길을 열었습니다.',
rewardExp: 13
},
{
id: 'honor-yizhou-soldiers',
label: '항복 병사를 예우한다',
response: '두 장수가 함께 병사들을 달래자, 익주 병사들은 유비군 군영을 조금 덜 두려워하게 되었습니다.',
rewardExp: 12
}
]
}
];
@@ -4298,6 +4395,66 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['익주 창고 장부 1']
}
]
},
{
id: 'mianzhu-storehouse-relief',
title: '면죽관 창고 구호',
location: '면죽관 창고',
availableAfterBattleIds: [campBattleIds.thirtySecond],
bondId: 'liu-bei__li-yan',
description: '유비와 이엄이 면죽관 창고를 열어 항복 병사와 백성에게 공평하게 배급할 방법을 정합니다.',
lines: [
'이엄: 창고를 빼앗긴 병사들은 패배보다 굶주림을 더 두려워합니다.',
'유비: 그렇다면 먼저 명부를 세우고, 우리 병사와 항복 병사를 같은 줄에 세웁시다.',
'창고 앞의 긴장된 줄은 천천히 낮아졌고, 면죽관의 문은 전리품이 아니라 구호소처럼 쓰이기 시작했습니다.'
],
choices: [
{
id: 'equal-storehouse-ration',
label: '배급 줄을 하나로 합친다',
response: '유비군과 항복 병사가 같은 줄에서 배급을 받자, 성도까지 보낼 소문이 한층 부드러워졌습니다.',
bondExp: 28,
itemRewards: ['콩 6', '상처약 3']
},
{
id: 'record-mianzhu-ledger',
label: '창고 장부를 남긴다',
response: '이엄은 창고 장부에 손댄 곡식과 남긴 곡식을 모두 적어, 다음 성도 권고의 증거를 만들었습니다.',
bondExp: 26,
gold: 420,
itemRewards: ['면죽관 창고 장부 1']
}
]
},
{
id: 'chengdu-surrender-council',
title: '성도 항복 권고 회의',
location: '면죽관 본막',
availableAfterBattleIds: [campBattleIds.thirtySecond],
bondId: 'zhuge-liang__li-yan',
description: '제갈량과 이엄이 성도에 보낼 항복 조건을 정리하고, 유장이 받아들일 만한 명분을 다듬습니다.',
lines: [
'제갈량: 권고문은 이기는 군대의 칼이 아니라, 성 안의 사람이 붙잡을 난간이어야 합니다.',
'이엄: 유장공이 체면을 잃지 않는 문장이라면, 문을 여는 사람도 배신자가 아니라 중재자가 될 수 있습니다.',
'두 사람은 항복 뒤 관직과 창고, 병사의 처우를 조목조목 적어 다음 장의 실마리를 만들었습니다.'
],
choices: [
{
id: 'soften-surrender-terms',
label: '항복 조건을 부드럽게 쓴다',
response: '권고문은 위협보다 보전과 질서를 앞세웠고, 성도 안쪽으로 들어갈 여지가 넓어졌습니다.',
bondExp: 28,
itemRewards: ['성도 항복 권고문 1']
},
{
id: 'prepare-city-officer-list',
label: '성도 장수 명단을 정리한다',
response: '이엄의 기억과 제갈량의 판단이 겹쳐지며, 다음 설득전에서 먼저 만날 장수들이 정해졌습니다.',
bondExp: 26,
gold: 440,
itemRewards: ['성도 장수 명단 1']
}
]
}
];
@@ -4384,6 +4541,43 @@ export class CampScene extends Phaser.Scene {
return;
}
if (battleId === campBattleIds.thirtySecond) {
this.campaign = ensureCampaignRosterUnits(
[
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits,
...jingzhouRecruitUnits,
...guiyangRecruitUnits,
...wulingRecruitUnits,
...changshaRecruitUnits,
...yizhouRecruitUnits,
...fuPassRecruitUnits,
...luoCastleRecruitUnits,
...luoCastleProperRecruitUnits,
...chengduPressureRecruitUnits
],
[
...xuzhouRecruitBonds,
...caoBreakRecruitBonds,
...liuBiaoRecruitBonds,
...zhugeRecruitBonds,
...jingzhouRecruitBonds,
...guiyangRecruitBonds,
...wulingRecruitBonds,
...changshaRecruitBonds,
...yizhouRecruitBonds,
...fuPassRecruitBonds,
...luoCastleRecruitBonds,
...luoCastleProperRecruitBonds,
...chengduPressureRecruitBonds
]
);
this.report = this.campaign.firstBattleReport ?? this.report;
return;
}
if (battleId === campBattleIds.thirtyFirst) {
this.campaign = ensureCampaignRosterUnits(
[
@@ -4660,6 +4854,9 @@ export class CampScene extends Phaser.Scene {
private currentCampTitle() {
const battleId = this.currentCampBattleId();
if (battleId === campBattleIds.thirtySecond) {
return '면죽관 압박전 후 군영';
}
if (battleId === campBattleIds.thirtyFirst) {
return '낙성 본성 공략 후 군영';
}