Record campaign arc and data-driven sorties
This commit is contained in:
@@ -6,3 +6,4 @@
|
||||
- For this project, whenever source changes are made, commit the changes and push them to the Gitea remote before finishing the task.
|
||||
- The game targets normal operation on PC/desktop browsers; do not prioritize mobile layout or mobile-specific work.
|
||||
- 이미지는 KOEI 삼국지 스타일을 활용하되, 실제 저작권 원본 이미지나 로고를 복제하지 않고 프로젝트 고유 자산으로 제작한다.
|
||||
- 캠페인 큰 줄기는 유비의 삼국지 서사를 따른다: 황건적 토벌 → 반동탁 흐름 → 공손찬 의탁 → 도겸에게 서주 인수 → 여포에게 서주 상실 → 조조 의탁 → 조조 이탈 → 원소 의탁 → 유표 의탁 → 제갈량 영입 → 적벽대전 → 형주·익주 확보 → 촉한 건국.
|
||||
|
||||
@@ -35,3 +35,4 @@ Build a small complete tactical RPG loop that can grow into a longer Romance of
|
||||
- Use original names, portraits, maps, and dialogue inspired by historical tactical RPGs.
|
||||
- Keep copyrighted scripts, sprites, portraits, music, and maps out of the repository.
|
||||
- Prefer data-driven scenarios so new chapters and battlefields can be added without rewriting scene code.
|
||||
- Follow Liu Bei's long-form campaign arc: Yellow Turban suppression -> anti-Dong Zhuo era -> service under Gongsun Zan -> inheritance of Xu Province from Tao Qian -> loss of Xu Province to Lu Bu -> service under Cao Cao -> break from Cao Cao -> service under Yuan Shao -> refuge under Liu Biao -> recruitment of Zhuge Liang -> Red Cliffs -> securing Jing and Yi Provinces -> founding of Shu Han.
|
||||
|
||||
@@ -358,7 +358,7 @@ try {
|
||||
return activeScenes.includes('StoryScene');
|
||||
});
|
||||
|
||||
for (let i = 0; i < 8; i += 1) {
|
||||
for (let i = 0; i < 14; i += 1) {
|
||||
const isSecondBattleActive = await page.evaluate(() => {
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
return state?.scene === 'BattleScene' && state?.battleId === 'second-battle-yellow-turban-pursuit';
|
||||
|
||||
57
src/game/data/campaignFlow.ts
Normal file
57
src/game/data/campaignFlow.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { CampaignStep } from '../state/campaignState';
|
||||
import { defaultBattleScenario, secondBattleScenario, thirdBattleScenario, type BattleScenarioId } from './battles';
|
||||
import {
|
||||
firstBattleVictoryPages,
|
||||
secondBattleIntroPages,
|
||||
secondBattleVictoryPages,
|
||||
thirdBattleIntroPages,
|
||||
type StoryPage
|
||||
} from './scenario';
|
||||
|
||||
export type SortieFlow = {
|
||||
afterBattleId: string;
|
||||
eyebrow: string;
|
||||
title: string;
|
||||
description: string;
|
||||
rewardHint: string;
|
||||
nextBattleId?: BattleScenarioId;
|
||||
campaignStep?: CampaignStep;
|
||||
pages: StoryPage[];
|
||||
unavailableNotice?: string;
|
||||
};
|
||||
|
||||
const sortieFlows: Record<string, SortieFlow> = {
|
||||
[defaultBattleScenario.id]: {
|
||||
afterBattleId: defaultBattleScenario.id,
|
||||
eyebrow: '다음 전장',
|
||||
title: secondBattleScenario.title,
|
||||
description: '탁현을 물러난 황건 잔당이 인근 마을을 위협하고 있습니다. 의용군은 첫 승리의 기세를 몰아 추격에 나섭니다.',
|
||||
rewardHint: '예상 보상: 군자금, 소모품, 의용군 명성',
|
||||
nextBattleId: secondBattleScenario.id,
|
||||
campaignStep: 'second-battle',
|
||||
pages: [...firstBattleVictoryPages, ...secondBattleIntroPages]
|
||||
},
|
||||
[secondBattleScenario.id]: {
|
||||
afterBattleId: secondBattleScenario.id,
|
||||
eyebrow: '다음 전장',
|
||||
title: thirdBattleScenario.title,
|
||||
description: '탁현을 넘어 광종으로 향하는 길목에서 황건 전령이 관군의 움직임을 본대로 전하려 합니다. 강가 요새와 좁은 길을 돌파해야 합니다.',
|
||||
rewardHint: `예상 보상: ${thirdBattleScenario.title} 개방`,
|
||||
nextBattleId: thirdBattleScenario.id,
|
||||
campaignStep: 'third-battle',
|
||||
pages: [...secondBattleVictoryPages, ...thirdBattleIntroPages]
|
||||
},
|
||||
[thirdBattleScenario.id]: {
|
||||
afterBattleId: thirdBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '광종 본전',
|
||||
description: '광종 구원로는 열렸지만 황건 본대는 아직 건재합니다. 다음 작업에서 광종 본전과 더 큰 전장 목표를 이어 붙일 수 있습니다.',
|
||||
rewardHint: '다음 장: 광종 본전 준비 중',
|
||||
pages: [],
|
||||
unavailableNotice: '광종 본전은 다음 장으로 이어집니다. 군영에서 성장 상태를 정비하세요.'
|
||||
}
|
||||
};
|
||||
|
||||
export function getSortieFlow(latestBattleId?: string) {
|
||||
return sortieFlows[latestBattleId ?? defaultBattleScenario.id] ?? sortieFlows[defaultBattleScenario.id];
|
||||
}
|
||||
@@ -2,8 +2,9 @@ import Phaser from 'phaser';
|
||||
import { soundDirector } from '../audio/SoundDirector';
|
||||
import { equipmentExpToNext, equipmentSlotLabels, equipmentSlots, getItem, type EquipmentSlot } from '../data/battleItems';
|
||||
import { getUnitClass } from '../data/battleRules';
|
||||
import { defaultBattleScenario, secondBattleScenario, thirdBattleScenario } from '../data/battles';
|
||||
import { firstBattleBonds, firstBattleUnits, secondBattleIntroPages, thirdBattleIntroPages, type PortraitKey, type UnitData } from '../data/scenario';
|
||||
import { defaultBattleScenario } from '../data/battles';
|
||||
import { getSortieFlow } from '../data/campaignFlow';
|
||||
import { firstBattleBonds, firstBattleUnits, type PortraitKey, type UnitData } from '../data/scenario';
|
||||
import {
|
||||
applyCampBondExp,
|
||||
getCampaignState,
|
||||
@@ -398,37 +399,17 @@ export class CampScene extends Phaser.Scene {
|
||||
bg.setStrokeStyle(1, palette.gold, 0.4);
|
||||
const completedDialogues = this.completedCampDialogues().length;
|
||||
const inventory = this.inventoryLabels().join(', ');
|
||||
const reward =
|
||||
this.campaign?.latestBattleId === thirdBattleScenario.id
|
||||
? '다음 장: 광종 본전 준비 중'
|
||||
: this.campaign?.latestBattleId === secondBattleScenario.id
|
||||
? `예상 보상: ${thirdBattleScenario.title} 개방`
|
||||
: '예상 보상: 군자금, 소모품, 의용군 명성';
|
||||
const reward = getSortieFlow(this.campaign?.latestBattleId).rewardHint;
|
||||
this.trackSortie(this.add.text(x + 16, y + 10, reward, this.textStyle(13, '#f2e3bf', true))).setDepth(depth + 1);
|
||||
this.trackSortie(this.add.text(x + 16, y + 30, `현재 준비: 대화 ${completedDialogues}/${campDialogues.length} · 보유 ${inventory || '없음'}`, this.textStyle(12, '#d4dce6'))).setDepth(depth + 1);
|
||||
}
|
||||
|
||||
private nextSortieBriefing() {
|
||||
if (this.campaign?.latestBattleId === thirdBattleScenario.id) {
|
||||
return {
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '광종 본전',
|
||||
description: '광종 구원로는 열렸지만 황건 본대는 아직 건재합니다. 다음 작업에서 광종 본전과 더 큰 전장 목표를 이어 붙일 수 있습니다.'
|
||||
};
|
||||
}
|
||||
|
||||
if (this.campaign?.latestBattleId === secondBattleScenario.id) {
|
||||
return {
|
||||
eyebrow: '다음 전장',
|
||||
title: thirdBattleScenario.title,
|
||||
description: '탁현을 넘어 광종으로 향하는 길목에서 황건 전령이 관군의 움직임을 본대로 전하려 합니다. 강가 요새와 좁은 길을 돌파해야 합니다.'
|
||||
};
|
||||
}
|
||||
|
||||
const flow = getSortieFlow(this.campaign?.latestBattleId);
|
||||
return {
|
||||
eyebrow: '다음 전장',
|
||||
title: secondBattleScenario.title,
|
||||
description: '탁현을 물러난 황건 잔당이 인근 마을을 위협하고 있습니다. 의용군은 첫 승리의 기세를 몰아 추격에 나섭니다.'
|
||||
eyebrow: flow.eyebrow,
|
||||
title: flow.title,
|
||||
description: flow.description
|
||||
};
|
||||
}
|
||||
|
||||
@@ -484,27 +465,19 @@ export class CampScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private startVictoryStory() {
|
||||
if (this.campaign?.latestBattleId === thirdBattleScenario.id) {
|
||||
const flow = getSortieFlow(this.campaign?.latestBattleId);
|
||||
|
||||
if (!flow.nextBattleId || !flow.campaignStep || flow.pages.length === 0) {
|
||||
this.hideSortiePrep();
|
||||
this.showCampNotice('광종 본전은 다음 장으로 이어집니다. 군영에서 성장 상태를 정비하세요.');
|
||||
this.showCampNotice(flow.unavailableNotice ?? '다음 장은 아직 준비 중입니다. 군영에서 성장 상태를 정비하세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.campaign?.latestBattleId === secondBattleScenario.id) {
|
||||
markCampaignStep('third-battle');
|
||||
this.scene.start('StoryScene', {
|
||||
pages: [...secondBattleScenario.victoryPages, ...thirdBattleIntroPages],
|
||||
nextScene: 'BattleScene',
|
||||
nextSceneData: { battleId: thirdBattleScenario.id }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
markCampaignStep('second-battle');
|
||||
markCampaignStep(flow.campaignStep);
|
||||
this.scene.start('StoryScene', {
|
||||
pages: secondBattleIntroPages,
|
||||
pages: flow.pages,
|
||||
nextScene: 'BattleScene',
|
||||
nextSceneData: { battleId: secondBattleScenario.id }
|
||||
nextSceneData: { battleId: flow.nextBattleId }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user