Add Jing Province entry chapter

This commit is contained in:
2026-06-23 07:42:11 +09:00
parent 302f0e0a76
commit d26a16d2a1
11 changed files with 1120 additions and 29 deletions

View File

@@ -9,6 +9,8 @@ import {
caoBreakRecruitUnits,
firstBattleBonds,
firstBattleUnits,
jingzhouRecruitBonds,
jingzhouRecruitUnits,
liuBiaoRecruitBonds,
liuBiaoRecruitUnits,
xuzhouRecruitBonds,
@@ -295,7 +297,7 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
title: '형주·익주 확보',
period: '근본을 세우다',
description: '형주와 익주를 기반으로 삼아 유비군이 유랑군에서 국가의 뿌리로 바뀌는 장입니다.',
battleIds: [],
battleIds: ['twenty-third-battle-jingzhou-south-entry'],
nextHints: ['형주 방위', '익주 진입', '장수 대거 합류']
},
{
@@ -330,7 +332,8 @@ const campBattleIds = {
nineteenth: 'nineteenth-battle-changban-refuge',
twentieth: 'twentieth-battle-jiangdong-envoy',
twentyFirst: 'twenty-first-battle-red-cliffs-vanguard',
twentySecond: 'twenty-second-battle-red-cliffs-fire'
twentySecond: 'twenty-second-battle-red-cliffs-fire',
twentyThird: 'twenty-third-battle-jingzhou-south-entry'
} as const;
const requiredSortieUnitIds = new Set(['liu-bei']);
@@ -569,6 +572,18 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
{ unitId: 'mi-zhu', reason: '화공전의 장기 피해를 버티기 위한 회복과 보급을 맡습니다.' }
],
note: '적벽 화공전은 강 위의 결전입니다. 제갈량의 책략과 전열 유지, 화선 접안로 확보를 중심으로 여섯 명을 고르십시오.'
},
'twenty-third-battle-jingzhou-south-entry': {
maxUnits: 6,
recommended: [
{ unitId: 'liu-bei', reason: '형주 남부 진입의 명분이자 패배 조건의 중심입니다.' },
{ unitId: 'zhuge-liang', reason: '마을을 해치지 않고 길목을 여는 작전 핵심입니다.' },
{ unitId: 'guan-yu', reason: '형도영의 보병 전열을 정면에서 받아낼 주력입니다.' },
{ unitId: 'zhao-yun', reason: '척후와 기병을 빠르게 끊어 마을을 안정시키기 좋습니다.' },
{ unitId: 'sun-qian', reason: '마량과 형주 선비층으로 이어질 외교 명분을 정리합니다.' },
{ unitId: 'mi-zhu', reason: '긴 남부 길목에서 회복과 보급을 맡기 좋습니다.' }
],
note: '형주 남부 진입전은 마을 안정과 길목 돌파가 동시에 필요한 전장입니다. 마량은 승리 후 합류하므로 이번 전투 뒤 다음 출전 후보로 늘어납니다.'
}
};
@@ -2408,6 +2423,87 @@ const campDialogues: CampDialogue[] = [
rewardExp: 9
}
]
},
{
id: 'liu-ma-after-jingzhou-south-entry',
title: '백미를 맞이하다',
availableAfterBattleIds: [campBattleIds.twentyThird],
unitIds: ['liu-bei', 'ma-liang'],
bondId: 'liu-bei__ma-liang',
rewardExp: 28,
lines: [
'마량: 주공께서 형주 남부의 마을을 먼저 살피셨다는 말을 들었습니다. 그래서 저도 붓을 들고 찾아왔습니다.',
'유비: 땅을 얻는 일보다 사람을 잃지 않는 일이 먼저요. 선생이 남부의 길과 민심을 알려 준다면 큰 힘이 되겠소.',
'마량: 칼로 열 수 없는 문은 말과 문서로 열겠습니다. 다음 군현부터는 제가 앞서 백성의 사정을 살피겠습니다.'
],
choices: [
{
id: 'ask-ma-liang-local-voices',
label: '군현의 민심을 묻는다',
response: '마량은 영릉과 계양의 토호, 마을 장로, 상인 길목을 차분히 짚어 주었고 유비군의 다음 행군 명분이 선명해졌다.',
rewardExp: 12
},
{
id: 'entrust-scholar-letters',
label: '선비들에게 보낼 글을 맡긴다',
response: '유비는 형주 선비들에게 보낼 첫 문장을 마량에게 맡겼고, 백미의 이름은 군영 안에서 조용히 힘을 얻기 시작했다.',
rewardExp: 10
}
]
},
{
id: 'zhuge-ma-after-jingzhou-south-entry',
title: '형주의 지맥',
availableAfterBattleIds: [campBattleIds.twentyThird],
unitIds: ['zhuge-liang', 'ma-liang'],
bondId: 'zhuge-liang__ma-liang',
rewardExp: 26,
lines: [
'제갈량: 큰 계책은 지도를 보지만, 실제 길은 그곳에 사는 사람의 입에서 나옵니다. 마량 선생의 기록이 필요합니다.',
'마량: 형주 남부는 길 하나가 성 하나와 같습니다. 어디를 먼저 설득하고 어디를 피해야 할지 적어 두겠습니다.',
'제갈량: 좋습니다. 이번부터 출전 명단을 고를 때도 전열만이 아니라 문서와 설득을 함께 보아야 합니다.'
],
choices: [
{
id: 'map-commandery-roads',
label: '남부 군현의 길을 표시한다',
response: '마량이 좁은 산길과 마을 우회로를 표시하자, 제갈량의 다음 전장 배치안이 훨씬 촘촘해졌다.',
rewardExp: 11
},
{
id: 'compare-scholar-networks',
label: '선비들의 관계망을 맞춰 본다',
response: '두 사람은 선비층의 관계를 병력 배치처럼 정리했고, 싸우지 않고 열 수 있는 문이 몇 곳 보이기 시작했다.',
rewardExp: 10
}
]
},
{
id: 'sun-ma-after-jingzhou-south-entry',
title: '문서와 백미',
availableAfterBattleIds: [campBattleIds.twentyThird],
unitIds: ['sun-qian', 'ma-liang'],
bondId: 'sun-qian__ma-liang',
rewardExp: 24,
lines: [
'손건: 외교 문서는 말이 곧 병사입니다. 마량 선생이 남부의 이름과 체면을 바로잡아 주면 설득이 쉬워질 겁니다.',
'마량: 손건 선생의 문장은 군영 밖에서도 곧게 들립니다. 거기에 현지의 호칭과 예법을 붙이면 문이 열릴 것입니다.',
'손건: 다음 출전부터는 칼을 드는 장수뿐 아니라, 문서를 들고 갈 장수도 생각해야겠군요.'
],
choices: [
{
id: 'draft-commandery-letters',
label: '군현에 보낼 서신을 쓴다',
response: '손건과 마량은 군현별 서신 초안을 만들었고, 전투 사이 선택지가 더 넓어질 준비가 갖춰졌다.',
rewardExp: 10
},
{
id: 'sort-local-titles',
label: '토호들의 호칭을 정리한다',
response: '사소한 호칭 하나가 문을 닫기도 연다. 두 사람은 남부 토호들의 이름과 예를 새로 정리했다.',
rewardExp: 9
}
]
}
];
@@ -2857,6 +2953,66 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['민심 기록 1']
}
]
},
{
id: 'lingling-village-relief',
title: '영릉 마을 구호',
location: '영릉 외곽 마을',
availableAfterBattleIds: [campBattleIds.twentyThird],
bondId: 'liu-bei__ma-liang',
description: '형도영의 가병이 물러난 뒤, 유비와 마량이 마을을 돌며 남은 상처와 민심을 살핍니다.',
lines: [
'마량: 이 마을은 길목이라 어느 군대가 지나가도 먼저 흔들립니다. 오늘은 곡식보다 안심할 말이 필요합니다.',
'유비: 우리가 지나간 뒤에도 마을이 버틸 수 있어야 하오. 남은 약과 곡식을 나누고, 군율을 다시 세우시오.',
'마을 장로들은 처음에는 문을 반쯤만 열었지만, 약과 곡식이 먼저 들어오자 조심스레 군영의 이름을 물었습니다.'
],
choices: [
{
id: 'leave-village-medicine',
label: '상처약을 남긴다',
response: '마량은 약을 받은 집마다 이름을 적었고, 유비군이 약탈군이 아니라는 소문이 영릉 주변으로 퍼졌다.',
bondExp: 22,
itemRewards: ['상처약 2']
},
{
id: 'write-relief-record',
label: '구호 기록을 남긴다',
response: '유비와 마량은 마을별 필요 물자를 문서로 남겼고, 다음 보급 계획이 한결 정확해졌다.',
bondExp: 18,
gold: 160,
itemRewards: ['형주 민심 기록 1']
}
]
},
{
id: 'southern-commandery-ledger',
title: '남부 군현 문서',
location: '임시 군막',
availableAfterBattleIds: [campBattleIds.twentyThird],
bondId: 'zhuge-liang__ma-liang',
description: '제갈량과 마량이 영릉 이후 차례로 열어야 할 군현의 길, 토호, 마을 사정을 정리합니다.',
lines: [
'제갈량: 전투로 이긴 곳은 하루면 흔들리고, 문서로 묶은 곳은 다음 계절까지 버팁니다.',
'마량: 계양은 먼저 설득할 사람이 있고, 무릉은 길이 험합니다. 장사는 장수의 이름부터 살펴야 합니다.',
'두 사람의 지도가 펼쳐지자 형주 남부는 막연한 땅이 아니라, 차례로 준비해야 할 선택지로 보이기 시작했습니다.'
],
choices: [
{
id: 'mark-guiyang-route',
label: '계양으로 가는 길을 표시한다',
response: '마량이 계양 길목과 설득 대상을 적자, 제갈량은 다음 군현 확보 순서를 새로 정리했다.',
bondExp: 20,
itemRewards: ['남부 군현 지도 1']
},
{
id: 'estimate-wuling-risk',
label: '무릉의 위험을 계산한다',
response: '험한 길과 분산된 마을이 지도에 표시되며, 다음 전장에는 기동 장수와 보급 장수의 선택이 더 중요해졌다.',
bondExp: 18,
gold: 180,
itemRewards: ['군현 문서 1']
}
]
}
];
@@ -2942,6 +3098,15 @@ export class CampScene extends Phaser.Scene {
return;
}
if (battleId === campBattleIds.twentyThird) {
this.campaign = ensureCampaignRosterUnits(
[...xuzhouRecruitUnits, ...caoBreakRecruitUnits, ...liuBiaoRecruitUnits, ...zhugeRecruitUnits, ...jingzhouRecruitUnits],
[...xuzhouRecruitBonds, ...caoBreakRecruitBonds, ...liuBiaoRecruitBonds, ...zhugeRecruitBonds, ...jingzhouRecruitBonds]
);
this.report = this.campaign.firstBattleReport ?? this.report;
return;
}
if (
battleId === campBattleIds.seventeenth ||
battleId === campBattleIds.eighteenth ||
@@ -3006,6 +3171,9 @@ export class CampScene extends Phaser.Scene {
private currentCampTitle() {
const battleId = this.currentCampBattleId();
if (battleId === campBattleIds.twentyThird) {
return '형주 남부 진입 후 군영';
}
if (battleId === campBattleIds.twentySecond) {
return '적벽 화공전 후 군영';
}