diff --git a/docs/roadmap.md b/docs/roadmap.md index 1841a72..93e7775 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -70,16 +70,17 @@ Build a small complete tactical RPG loop that can grow into a longer Romance of - Forty-fourth battle Maicheng isolation route, using Guan Yu's sealed retreat, Wu's reed-ford ambushes, Wei cavalry pressure, and a seven-officer sortie choice across an 88x70 battlefield to open one more road out of the encirclement - Forty-fifth battle Yiling vanguard route, turning Jing Province's loss into Liu Bei's revenge march and using a 90x72 river-forest battlefield to establish the first Yiling camp against Lu Xun's waiting line - Forty-sixth battle Yiling fire-attack route, using Lu Xun's delayed fire plan, stretched Shu-Han camps, a 92x74 burning river-forest battlefield, and a seven-officer retreat-route sortie choice to break through toward Baidi Castle +- Baidi Castle entrustment story milestone, where Liu Bei's retreat from Yiling becomes a playable camp transition into Zhuge Liang's regency burden and post-defeat recovery planning - Camp progress timeline tab that summarizes Liu Bei's long campaign arc, completed battles, current chapter, latest battle, and next major chapter - Tactical sortie preparation panel with battle-specific sortie limits, recommended officers with reasons, class role, named equipment, core stats, bond partner, next-map terrain suitability, focused officer analysis, deployment preview, formation roles, active bond count, recruited-officer count, reserve roster summary, and readiness advice for each deployable officer - Officer collection support in camp, including full roster status, selected/reserve/recommended markers, selectable reserve drill focus, and post-battle reserve training growth for benched officers - Treasure equipment effects wired into battle previews and resolution, including named weapon damage bonuses, defensive treasure mitigation, support recovery bonuses, turn-start charm recovery, and equipment-specific growth bonuses -- Flow verification script from title through the forty-sixth battle victory, King of Hanzhong council milestone, Shu-Han foundation milestone, recruit sortie selection, Liu Biao visit rewards, Zhuge Liang recruitment, Bowang/Changban/Jiangdong/Red Cliffs/Jing Province/Guiyang/Wuling/Changsha/Yi Province/Fu Pass/Luo Castle/Luofeng/Luo main gate/Mianzhu/Chengdu/Jiameng/Yangping/Dingjun/Hanzhong/Jing defense/Fan Castle/Han River/Fan siege/Jing rear/Gongan collapse/Maicheng isolation/Yiling vanguard/Yiling fire camp states, campaign timeline state, and camp save state +- Flow verification script from title through the Baidi entrustment camp, King of Hanzhong council milestone, Shu-Han foundation milestone, recruit sortie selection, Liu Biao visit rewards, Zhuge Liang recruitment, Bowang/Changban/Jiangdong/Red Cliffs/Jing Province/Guiyang/Wuling/Changsha/Yi Province/Fu Pass/Luo Castle/Luofeng/Luo main gate/Mianzhu/Chengdu/Jiameng/Yangping/Dingjun/Hanzhong/Jing defense/Fan Castle/Han River/Fan siege/Jing rear/Gongan collapse/Maicheng isolation/Yiling vanguard/Yiling fire camp states, campaign timeline state, and camp save state ## Next Steps -1. Build the Baidi Castle entrustment chapter, using Liu Bei's retreat, final counsel, and Zhuge Liang's regency burden as the next story milestone -2. Expand post-Yiling camp consequences with grief checks, overheated revenge choices, and recovery decisions that affect sortie recommendations +1. Build the Nanman pacification preparation chapter, using the Baidi entrustment aftermath, southern instability, and Zhuge Liang's state-rebuilding priorities as the next campaign tension +2. Expand post-Baidi camp consequences with grief checks, recovery policy choices, and regency decisions that affect sortie recommendations 3. Expand reserve planning into individual officer assignments, including targeted class practice, paired bond training, and camp task slots 4. Add a dedicated treasure/equipment management view so players can compare special effects and growth 5. Keep expanding scenarios through the long campaign instead of treating the current slice as an ending diff --git a/scripts/verify-flow.mjs b/scripts/verify-flow.mjs index 94007ad..c68ba10 100644 --- a/scripts/verify-flow.mjs +++ b/scripts/verify-flow.mjs @@ -6216,12 +6216,78 @@ try { postYilingFireProgressState.campaignProgress?.completedKnown !== 46 || postYilingFireProgressState.campaignProgress?.totalKnown !== 46 || postYilingFireProgressState.campaignProgress?.latestBattleTitle !== '이릉 화공전' || - postYilingFireProgressState.campaignProgress?.nextBattleTitle !== '준비 중' + postYilingFireProgressState.campaignProgress?.nextBattleTitle !== '백제성 유탁' ) { - throw new Error(`Expected post-Yiling-fire progress tab to complete the forty-sixth battle and pause before Baidi Castle: ${JSON.stringify(postYilingFireProgressState?.campaignProgress)}`); + throw new Error(`Expected post-Yiling-fire progress tab to complete the forty-sixth battle and point to Baidi entrustment: ${JSON.stringify(postYilingFireProgressState?.campaignProgress)}`); } await page.screenshot({ path: 'dist/verification-post-yiling-fire-progress.png', fullPage: true }); + await page.mouse.click(1120, 38); + await page.waitForTimeout(180); + const baidiEntrustmentSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp()); + if ( + !baidiEntrustmentSortieState?.sortieVisible || + baidiEntrustmentSortieState.campaign?.step !== 'forty-sixth-camp' || + baidiEntrustmentSortieState.campTitle !== '이릉 화공전 후 군영' + ) { + throw new Error(`Expected Baidi entrustment story to be available from the Yiling fire camp: ${JSON.stringify(baidiEntrustmentSortieState)}`); + } + await page.screenshot({ path: 'dist/verification-baidi-entrustment-prep.png', fullPage: true }); + + await page.mouse.click(1068, 646); + await page.waitForFunction(() => { + const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? []; + return activeScenes.includes('StoryScene'); + }); + await page.screenshot({ path: 'dist/verification-baidi-entrustment-story.png', fullPage: true }); + + for (let i = 0; i < 30; i += 1) { + const returnedToBaidiCamp = await page.evaluate(() => { + const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? []; + const camp = window.__HEROS_DEBUG__?.camp?.(); + return activeScenes.includes('CampScene') && camp?.campaign?.step === 'baidi-entrustment-camp'; + }); + if (returnedToBaidiCamp) { + break; + } + await page.keyboard.press('Space'); + await page.waitForTimeout(320); + } + await page.waitForFunction(() => { + const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? []; + const camp = window.__HEROS_DEBUG__?.camp?.(); + return activeScenes.includes('CampScene') && camp?.campaign?.step === 'baidi-entrustment-camp'; + }); + + const baidiCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp()); + if ( + baidiCampState?.campaign?.step !== 'baidi-entrustment-camp' || + baidiCampState.campTitle !== '백제성 유탁 후 군영' || + baidiCampState.campBattleId !== 'forty-sixth-battle-yiling-fire' || + baidiCampState.availableDialogueIds?.length !== 3 || + !baidiCampState.availableDialogueIds.every((id) => id.includes('baidi')) || + baidiCampState.availableVisitIds?.length !== 2 || + !baidiCampState.availableVisitIds.every((id) => id.includes('baidi')) || + baidiCampState.rosterCollection?.total < 22 + ) { + throw new Error(`Expected Baidi entrustment camp to expose Baidi-only dialogue/visit sets and preserve the full officer roster: ${JSON.stringify(baidiCampState)}`); + } + await page.screenshot({ path: 'dist/verification-baidi-entrustment-camp.png', fullPage: true }); + + await page.mouse.click(966, 38); + await page.waitForTimeout(180); + const postBaidiProgressState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp()); + if ( + postBaidiProgressState?.activeTab !== 'progress' || + postBaidiProgressState.campaignProgress?.completedKnown !== 46 || + postBaidiProgressState.campaignProgress?.totalKnown !== 46 || + postBaidiProgressState.campaignProgress?.latestBattleTitle !== '이릉 화공전' || + postBaidiProgressState.campaignProgress?.nextBattleTitle !== '준비 중' + ) { + throw new Error(`Expected Baidi entrustment progress tab to keep the forty-sixth battle complete and pause before Nanman prep: ${JSON.stringify(postBaidiProgressState?.campaignProgress)}`); + } + await page.screenshot({ path: 'dist/verification-post-baidi-progress.png', fullPage: true }); + await page.evaluate(() => { const game = window.__HEROS_GAME__; game?.scene.stop('CampScene'); @@ -6253,11 +6319,11 @@ try { activeScenes: window.__HEROS_DEBUG__?.activeScenes() ?? [], camp: window.__HEROS_DEBUG__?.camp?.() ?? null })); - if (!titleContinueState.activeScenes.includes('CampScene')) { - throw new Error(`Expected title continue to reopen the latest camp after Yiling fire: ${JSON.stringify(titleContinueState)}`); + if (!titleContinueState.activeScenes.includes('CampScene') || titleContinueState.camp?.campaign?.step !== 'baidi-entrustment-camp') { + throw new Error(`Expected title continue to reopen the latest Baidi entrustment camp: ${JSON.stringify(titleContinueState)}`); } - console.log(`Verified title-to-forty-sixth-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng, Yangping, Dingjun, Hanzhong decisive battle, King of Hanzhong council, Shu-Han foundation state, Jing Province defense vanguard, Fan Castle vanguard, Han River flood, Fan Castle siege, Jing rear crisis, Gongan collapse, Maicheng isolation, Yiling vanguard, and Yiling fire attack state at ${targetUrl}`); + console.log(`Verified title-to-Baidi-entrustment flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng, Yangping, Dingjun, Hanzhong decisive battle, King of Hanzhong council, Shu-Han foundation state, Jing Province defense vanguard, Fan Castle vanguard, Han River flood, Fan Castle siege, Jing rear crisis, Gongan collapse, Maicheng isolation, Yiling vanguard, Yiling fire attack, and Baidi entrustment state at ${targetUrl}`); } finally { await browser?.close(); if (serverProcess && !serverProcess.killed) { diff --git a/src/game/data/campaignFlow.ts b/src/game/data/campaignFlow.ts index 3aad6f2..1b55842 100644 --- a/src/game/data/campaignFlow.ts +++ b/src/game/data/campaignFlow.ts @@ -49,6 +49,7 @@ import { type BattleScenarioId } from './battles'; import { + baidiEntrustmentPages, eighthBattleIntroPages, eighthBattleVictoryPages, eighteenthBattleIntroPages, @@ -68,7 +69,6 @@ import { fortyFifthBattleIntroPages, fortyFifthBattleVictoryPages, fortySixthBattleIntroPages, - fortySixthBattleVictoryPages, fifthBattleIntroPages, fifthBattleVictoryPages, fifteenthBattleIntroPages, @@ -664,13 +664,24 @@ const sortieFlows: Record = { }, [fortySixthBattleScenario.id]: { afterBattleId: fortySixthBattleScenario.id, - eyebrow: '다음 장 준비', - title: '백제성의 남은 뜻', + eyebrow: '군영 의정', + title: '백제성 유탁', description: - '이릉의 불길을 뚫고 퇴로는 열었지만 복수전은 꺾였습니다. 다음 장에서는 백제성으로 물러난 유비가 남은 나라의 길과 후계를 정하는 이야기를 다룹니다.', - rewardHint: '다음 장: 백제성 유탁과 촉한 정비 준비 중', - pages: fortySixthBattleVictoryPages, - unavailableNotice: '백제성 유탁과 촉한 정비는 다음 작업에서 이어집니다. 지금은 이릉 화공전 뒤의 성장, 공명도, 보급을 정비할 수 있습니다.' + '이릉의 불길을 뚫고 퇴로는 열었지만 복수전은 꺾였습니다. 출진 준비를 통해 새 전투가 아니라 백제성으로 물러난 유비의 마지막 부탁과 제갈량 중심 체제 전환을 진행합니다.', + rewardHint: '군영 목표: 백제성 유탁 / 제갈량 섭정 준비', + campaignStep: 'baidi-entrustment-camp', + pages: baidiEntrustmentPages, + unavailableNotice: '백제성 유탁이 완료되었습니다. 다음 작업에서는 남중 안정과 촉한 재정비 흐름을 이어 준비합니다.' + }, + 'baidi-entrustment-camp': { + afterBattleId: fortySixthBattleScenario.id, + eyebrow: '다음 장 준비', + title: '남만 평정 준비', + description: + '유비의 유탁 뒤 촉한은 제갈량을 중심으로 다시 숨을 고릅니다. 다음 장에서는 남중의 불안을 정리하고, 북벌을 준비할 내정을 세우는 흐름으로 확장합니다.', + rewardHint: '다음 장: 남만 평정과 촉한 재정비 준비 중', + pages: [], + unavailableNotice: '남만 평정과 촉한 재정비는 다음 작업에서 이어집니다. 지금은 백제성 유탁 뒤의 성장, 공명도, 보급을 정비할 수 있습니다.' } }; diff --git a/src/game/data/scenario.ts b/src/game/data/scenario.ts index a899913..7086624 100644 --- a/src/game/data/scenario.ts +++ b/src/game/data/scenario.ts @@ -3033,6 +3033,50 @@ export const fortySixthBattleVictoryPages: StoryPage[] = [ } ]; +export const baidiEntrustmentPages: StoryPage[] = [ + { + id: 'baidi-entrustment-arrival', + bgm: 'story-dark', + chapter: '백제성의 밤', + background: 'story-militia', + speaker: '제갈량', + text: '이릉의 불길을 지나 백제성에 닿은 촉한군은 승전의 북소리 대신 낮은 숨소리로 밤을 맞았습니다. 전장은 멀어졌지만, 나라가 잃은 무게는 성 안까지 따라왔습니다.' + }, + { + id: 'baidi-entrustment-liu-bei', + bgm: 'story-dark', + chapter: '남은 말', + background: 'story-liu-bei', + speaker: '유비', + portrait: 'liuBei', + text: '내가 사람을 얻어 나라를 세웠으나, 분노를 이기지 못해 사람을 잃었소. 공명, 남은 촉한을 그대에게 부탁하오. 후주가 따를 만하면 보필하고, 부족하면 나라의 뜻을 먼저 보시오.' + }, + { + id: 'baidi-entrustment-zhuge', + bgm: 'battle-prep', + chapter: '받아 든 짐', + background: 'story-three-heroes', + speaker: '제갈량', + text: '신은 감히 두 마음을 품지 않겠습니다. 폐하께서 남기신 뜻이 백성에게 닿을 때까지, 군영의 장부와 조정의 붓과 전장의 깃발을 모두 놓지 않겠습니다.' + }, + { + id: 'baidi-entrustment-officers', + bgm: 'militia-theme', + chapter: '새 질서', + background: 'story-sortie', + speaker: '조운', + text: '장수들은 백제성 뜰에서 조용히 군례를 올렸습니다. 이제 유비의 분노가 남긴 상처를 수습하고, 제갈량을 중심으로 촉한의 다음 길을 다시 세워야 합니다.' + }, + { + id: 'baidi-entrustment-next', + bgm: 'story-dark', + chapter: '남쪽의 불안', + background: 'story-militia', + speaker: '황권', + text: '이릉의 패전 뒤 촉한은 안팎으로 흔들리고 있습니다. 남중의 불안과 북방의 압박을 동시에 볼 수는 없습니다. 먼저 나라 안을 다독이고, 흩어진 장수들의 마음을 모아야 합니다.' + } +]; + export const firstBattleMap: BattleMap = { width: 20, height: 18, diff --git a/src/game/scenes/CampScene.ts b/src/game/scenes/CampScene.ts index 628b551..997b2b7 100644 --- a/src/game/scenes/CampScene.ts +++ b/src/game/scenes/CampScene.ts @@ -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(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); diff --git a/src/game/scenes/TitleScene.ts b/src/game/scenes/TitleScene.ts index 818e029..6b96f1b 100644 --- a/src/game/scenes/TitleScene.ts +++ b/src/game/scenes/TitleScene.ts @@ -393,7 +393,8 @@ export class TitleScene extends Phaser.Scene { campaign.step === 'forty-fifth-camp' || campaign.step === 'forty-sixth-camp' || campaign.step === 'hanzhong-king-camp' || - campaign.step === 'shu-han-foundation-camp' + campaign.step === 'shu-han-foundation-camp' || + campaign.step === 'baidi-entrustment-camp' ) { this.scene.start('CampScene'); return; diff --git a/src/game/state/campaignState.ts b/src/game/state/campaignState.ts index 7fb135b..c5be44a 100644 --- a/src/game/state/campaignState.ts +++ b/src/game/state/campaignState.ts @@ -135,7 +135,8 @@ export type CampaignStep = | 'forty-sixth-battle' | 'forty-sixth-camp' | 'hanzhong-king-camp' - | 'shu-han-foundation-camp'; + | 'shu-han-foundation-camp' + | 'baidi-entrustment-camp'; export type CampaignUnitProgressSnapshot = { unitId: string;