Add Baidi entrustment milestone

This commit is contained in:
2026-06-23 20:03:58 +09:00
parent d88cc65972
commit 199a1cee68
7 changed files with 305 additions and 19 deletions

View File

@@ -65,6 +65,7 @@ import {
markCampaignStep,
saveCampaignState,
setCampaignReserveTrainingFocus,
type CampaignStep,
type CampaignState,
type CampaignReserveTrainingFocusDefinition,
type CampaignReserveTrainingFocusId,
@@ -78,6 +79,7 @@ type CampDialogue = {
id: string;
title: string;
availableAfterBattleIds: string[];
availableDuringSteps?: CampaignStep[];
unitIds: [string, string];
bondId: string;
rewardExp: number;
@@ -97,6 +99,7 @@ type CampVisitDefinition = {
title: string;
location: string;
availableAfterBattleIds: string[];
availableDuringSteps?: CampaignStep[];
description: string;
bondId?: string;
lines: string[];
@@ -4811,6 +4814,90 @@ const campDialogues: CampDialogue[] = [
rewardExp: 17
}
]
},
{
id: 'baidi-liu-zhuge-entrustment',
title: '마지막 부탁',
availableAfterBattleIds: [campBattleIds.fortySixth],
availableDuringSteps: ['baidi-entrustment-camp'],
unitIds: ['liu-bei', 'zhuge-liang'],
bondId: 'liu-bei__zhuge-liang',
rewardExp: 58,
lines: [
'유비: 공명, 내 뜻이 사람을 살리는 데서 시작했으나 끝내 많은 사람을 잃게 했소.',
'제갈량: 폐하의 뜻은 아직 남았습니다. 신은 그 뜻이 흔들리지 않도록 나라의 숨을 이어 가겠습니다.',
'유비: 후주와 촉한의 백성을 부탁하오. 그대의 어깨에 너무 큰 짐을 남기는구려.'
],
choices: [
{
id: 'entrust-people-first',
label: '백성을 먼저 부탁한다',
response: '제갈량은 군사보다 먼저 백성을 살피겠다고 답했고, 유비는 긴 숨을 내쉬며 고개를 끄덕였습니다.',
rewardExp: 20
},
{
id: 'entrust-state-ledger',
label: '나라의 장부를 맡긴다',
response: '유비는 남은 장부와 인장을 제갈량에게 맡겼고, 제갈량은 말없이 두 손으로 받아 들었습니다.',
rewardExp: 19
}
]
},
{
id: 'baidi-zhuge-maliang-record',
title: '유탁의 기록',
availableAfterBattleIds: [campBattleIds.fortySixth],
availableDuringSteps: ['baidi-entrustment-camp'],
unitIds: ['zhuge-liang', 'ma-liang'],
bondId: 'zhuge-liang__ma-liang_yiling-fire',
rewardExp: 54,
lines: [
'마량: 백제성의 말은 조정에서 여러 뜻으로 해석될 것입니다. 지금 정확히 적어 두어야 합니다.',
'제갈량: 기록이 흔들리면 사람의 마음도 흔들립니다. 폐하의 뜻은 무리한 복수가 아니라 남은 나라를 살리는 데 있습니다.',
'마량: 그 뜻을 문서로 남기겠습니다. 장수들이 각자 다르게 듣지 않도록 하겠습니다.'
],
choices: [
{
id: 'write-entrustment-edict',
label: '유탁 문서를 정리한다',
response: '마량은 백제성에서 오간 말을 조심스럽게 적었고, 제갈량은 다음 조정의 첫 문장을 함께 고쳤습니다.',
rewardExp: 18
},
{
id: 'prepare-regency-council',
label: '섭정 의정을 준비한다',
response: '제갈량과 마량은 장수들이 모일 순서와 논의할 안건을 정리해, 백제성 이후의 혼란을 줄였습니다.',
rewardExp: 17
}
]
},
{
id: 'baidi-liu-huangquan-retreat',
title: '남은 군의 숨',
availableAfterBattleIds: [campBattleIds.fortySixth],
availableDuringSteps: ['baidi-entrustment-camp'],
unitIds: ['liu-bei', 'huang-quan'],
bondId: 'liu-bei__huang-quan_yiling-fire',
rewardExp: 54,
lines: [
'황권: 폐하, 남은 군을 살리려면 패전의 책임보다 먼저 흩어진 부대의 위치를 확인해야 합니다.',
'유비: 옳소. 나의 잘못을 따지는 일은 뒤로 미루고, 살아 있는 자들이 돌아올 길을 먼저 여시오.',
'황권: 백제성의 깃발 아래 다시 셈하겠습니다. 잃은 길을 기록해야 다음 길이 생깁니다.'
],
choices: [
{
id: 'recover-retreat-roster',
label: '퇴각 명부를 회수한다',
response: '황권은 흩어진 퇴각 명부를 다시 모았고, 유비는 이름 하나하나를 놓치지 말라고 당부했습니다.',
rewardExp: 18
},
{
id: 'open-baidi-gates',
label: '성문 수용 순서를 정한다',
response: '백제성의 수용 순서가 정리되어, 부상병과 패잔병이 더 큰 혼란 없이 성 안으로 들어왔습니다.',
rewardExp: 17
}
]
}
];
@@ -6700,6 +6787,68 @@ const campVisits: CampVisitDefinition[] = [
itemRewards: ['탁주 4']
}
]
},
{
id: 'baidi-regency-council',
title: '섭정 의정 정리',
location: '백제성 내전',
availableAfterBattleIds: [campBattleIds.fortySixth],
availableDuringSteps: ['baidi-entrustment-camp'],
bondId: 'zhuge-liang__ma-liang_yiling-fire',
description: '제갈량과 마량이 백제성 내전에서 유탁 이후의 조정 순서와 장수들의 역할을 정리합니다.',
lines: [
'마량: 장수들이 모두 슬픔 속에 있습니다. 첫 의정에서 책임을 묻기보다 각자의 자리를 먼저 알려야 합니다.',
'제갈량: 나라가 흔들릴 때는 말의 순서가 군령이 됩니다. 백제성에서 나갈 첫 문서를 가볍게 쓸 수 없습니다.',
'내전의 등불 아래, 촉한의 다음 명령서와 장수 배치안이 조용히 정리되었습니다.'
],
choices: [
{
id: 'draft-regency-order',
label: '섭정 명령서를 쓴다',
response: '섭정 명령서가 준비되어, 백제성 이후 조정과 군영이 한 목소리로 움직일 기반이 생겼습니다.',
bondExp: 42,
gold: 1280,
itemRewards: ['섭정 의정 초안 1']
},
{
id: 'assign-officer-places',
label: '장수들의 자리를 나눈다',
response: '마량은 장수별 임무를 정리했고, 제갈량은 급히 움직일 부대와 성 안에 남을 부대를 구분했습니다.',
bondExp: 40,
itemRewards: ['상처약 7']
}
]
},
{
id: 'baidi-gate-recovery',
title: '백제성 성문 수습',
location: '백제성 서문',
availableAfterBattleIds: [campBattleIds.fortySixth],
availableDuringSteps: ['baidi-entrustment-camp'],
bondId: 'zhao-yun__wang-ping_yiling-fire',
description: '조운과 왕평이 백제성 서문에서 돌아오는 패잔병과 부상병의 흐름을 나누고, 추격 정찰을 막습니다.',
lines: [
'왕평: 서문으로 한꺼번에 몰리면 부상병이 먼저 눌립니다. 낮은 길과 높은 길을 나누어 들여야 합니다.',
'조운: 내가 성 밖을 맡겠소. 추격 정찰이 섞여 들어오지 못하게 끝까지 살피겠소.',
'서문 앞에는 부상병, 기병, 군량 수레가 따로 들어오는 표식이 세워졌습니다.'
],
choices: [
{
id: 'separate-wounded-gate',
label: '부상병 통로를 나눈다',
response: '부상병 통로가 따로 열려, 백제성 안의 혼란이 줄고 병력 회복 준비가 빨라졌습니다.',
bondExp: 40,
itemRewards: ['상처약 8']
},
{
id: 'screen-wu-scouts',
label: '오군 정찰을 걸러낸다',
response: '조운과 왕평은 성문 밖 검문선을 세워, 오군 척후가 패잔병 틈에 섞이는 일을 막았습니다.',
bondExp: 38,
gold: 1260,
itemRewards: ['탁주 5']
}
]
}
];
@@ -7478,6 +7627,9 @@ export class CampScene extends Phaser.Scene {
if (this.campaign?.step === 'hanzhong-king-camp') {
return '한중왕 즉위 준비 군영';
}
if (this.campaign?.step === 'baidi-entrustment-camp') {
return '백제성 유탁 후 군영';
}
if (battleId === campBattleIds.fortySixth) {
return '이릉 화공전 후 군영';
}
@@ -7622,7 +7774,8 @@ export class CampScene extends Phaser.Scene {
private availableCampDialogues() {
const battleId = this.currentCampBattleId();
const dialogues = campDialogues.filter((dialogue) => dialogue.availableAfterBattleIds.includes(battleId));
const battleDialogues = campDialogues.filter((dialogue) => dialogue.availableAfterBattleIds.includes(battleId));
const dialogues = this.filterCampEventsByStep(battleDialogues);
return dialogues.length > 0 ? dialogues : campDialogues.filter((dialogue) => dialogue.availableAfterBattleIds.includes(defaultBattleScenario.id));
}
@@ -7633,7 +7786,7 @@ export class CampScene extends Phaser.Scene {
private availableCampVisits() {
const battleId = this.currentCampBattleId();
return campVisits.filter((visit) => visit.availableAfterBattleIds.includes(battleId));
return this.filterCampEventsByStep(campVisits.filter((visit) => visit.availableAfterBattleIds.includes(battleId)));
}
private completedAvailableVisits() {
@@ -7641,6 +7794,15 @@ export class CampScene extends Phaser.Scene {
return this.availableCampVisits().filter((visit) => completed.includes(visit.id));
}
private filterCampEventsByStep<T extends { availableDuringSteps?: CampaignStep[] }>(events: T[]) {
const step = this.campaign?.step;
if (!step) {
return events.filter((event) => !event.availableDuringSteps);
}
const stepEvents = events.filter((event) => event.availableDuringSteps?.includes(step));
return stepEvents.length > 0 ? stepEvents : events.filter((event) => !event.availableDuringSteps);
}
private renderStaticButtons() {
this.addTabButton('장수', 'status', 654, 38);
this.addTabButton('대화', 'dialogue', 732, 38);