Polish sortie prep guidance

This commit is contained in:
2026-07-04 04:01:26 +09:00
parent d4e964a7ed
commit e7e0ad7dab

View File

@@ -183,6 +183,7 @@ type SortieChecklistItem = {
label: string;
complete: boolean;
detail: string;
priority?: 'required' | 'recommended';
};
type SortieUnitTacticalSummary = {
@@ -11265,9 +11266,10 @@ export class CampScene extends Phaser.Scene {
const y = Math.floor((this.scale.height - height) / 2);
const flow = this.currentSortieFlow();
const isBattleSortie = Boolean(flow.nextBattleId);
const checklist = this.sortieChecklist();
const prepTitle = isBattleSortie ? '출진 준비' : '군영 의정';
const prepSubtitle = isBattleSortie
? '대화, 보급, 상인 정비를 마친 뒤 함께 출전할 무장을 선택합니다.'
? this.sortiePrepSubtitle(checklist)
: '군영 대화와 장부를 정리한 뒤 다음 장면에 함께할 무장을 선택합니다.';
const shade = this.trackSortie(this.add.rectangle(0, 0, this.scale.width, this.scale.height, 0x020406, 0.68));
@@ -11283,13 +11285,13 @@ export class CampScene extends Phaser.Scene {
const title = this.trackSortie(this.add.text(x + 34, y + 28, prepTitle, this.textStyle(30, '#f2e3bf', true)));
title.setDepth(depth + 2);
const subtitle = this.trackSortie(
this.add.text(x + 34, y + 70, prepSubtitle, this.textStyle(15, '#d4dce6'))
this.add.text(x + 34, y + 70, this.compactText(prepSubtitle, 72), this.textStyle(15, '#d4dce6'))
);
subtitle.setDepth(depth + 2);
this.renderSortieHeaderSummary(x + 690, y + 26, 464, 58, depth + 2);
this.renderSortieBriefing(x + 34, y + 104, 560, 168, depth + 2);
this.renderSortieChecklist(x + 612, y + 104, 542, 168, depth + 2);
this.renderSortieChecklist(x + 612, y + 104, 542, 168, depth + 2, checklist);
this.renderSortieUnitSummary(x + 34, y + 292, 390, 286, depth + 2);
this.renderSortieFormationPlan(x + 442, y + 292, 350, 286, depth + 2);
this.renderSortieFocusPanel(x + 810, y + 292, 344, 286, depth + 2);
@@ -11376,20 +11378,19 @@ export class CampScene extends Phaser.Scene {
this.trackSortie(this.add.text(x + 8, y + 18, this.compactText(value, 13), this.textStyle(10, '#f2e3bf', true))).setDepth(depth + 1);
}
private renderSortieChecklist(x: number, y: number, width: number, height: number, depth: number) {
private renderSortieChecklist(x: number, y: number, width: number, height: number, depth: number, items = this.sortieChecklist()) {
const bg = this.trackSortie(this.add.rectangle(x, y, width, height, 0x0d141c, 0.92));
bg.setOrigin(0);
bg.setDepth(depth);
bg.setStrokeStyle(1, palette.gold, 0.5);
this.trackSortie(this.add.text(x + 18, y + 14, '준비 체크', this.textStyle(18, '#f2e3bf', true))).setDepth(depth + 1);
const items = this.sortieChecklist();
const rowGap = Math.max(15, Math.floor((height - 50) / Math.max(1, items.length)));
const compact = rowGap < 20;
items.forEach((item, index) => {
const rowY = y + 42 + index * rowGap;
const color = item.complete ? '#a8ffd0' : '#ffdf7b';
const status = item.complete ? '완료' : '주의';
const color = item.complete ? '#a8ffd0' : item.priority === 'required' ? '#ff9d7d' : '#ffdf7b';
const status = item.complete ? '완료' : item.priority === 'required' ? '필수' : '권장';
this.trackSortie(this.add.text(x + 18, rowY, status, this.textStyle(compact ? 10 : 13, color, true))).setDepth(depth + 1);
this.trackSortie(this.add.text(x + 68, rowY, item.label, this.textStyle(compact ? 11 : 14, '#d4dce6', true))).setDepth(depth + 1);
const detail = this.trackSortie(this.add.text(x + 184, rowY, this.compactText(item.detail, compact ? 36 : 42), this.textStyle(compact ? 10 : 12, item.complete ? '#9fb0bf' : '#d8b15f')));
@@ -12524,6 +12525,18 @@ export class CampScene extends Phaser.Scene {
};
}
private sortiePrepSubtitle(checklist: SortieChecklistItem[]) {
const nextRequired = checklist.find((item) => !item.complete && item.priority === 'required');
const nextRecommended = checklist.find((item) => !item.complete);
const next = nextRequired ?? nextRecommended;
if (!next) {
return '정비가 끝났습니다. 전열과 보급을 확인한 뒤 출진하십시오.';
}
const prefix = next.priority === 'required' ? '필수' : '권장';
return `${prefix}: ${next.label} - ${next.detail}`;
}
private currentSortieFlow() {
return getSortieFlow(this.campaign?.latestBattleId, this.campaign?.step);
}
@@ -12571,47 +12584,56 @@ export class CampScene extends Phaser.Scene {
{
label: requiredLabel,
complete: requiredComplete,
detail: requiredDetail
detail: requiredDetail,
priority: 'required'
},
{
label: '부상 장수 확인',
complete: injured.length === 0,
detail: injured.length === 0 ? '전원 완전한 병력' : `${injured.map((unit) => unit.name).join(', ')} 회복 권장`
detail: injured.length === 0 ? '전원 완전한 병력' : `${injured.map((unit) => unit.name).join(', ')} 회복 권장`,
priority: 'recommended'
},
{
label: '출전 구성',
complete: requiredUnitIds.every((id) => selected.some((unit) => unit.id === id)) && selected.length > 0,
detail: selected.length > 0 ? selected.map((unit) => unit.name).join(', ') : '출전 무장 선택 필요'
detail: selected.length > 0 ? selected.map((unit) => unit.name).join(', ') : '출전 무장 선택 필요',
priority: 'required'
},
{
label: '추천 병종',
complete: recommendedClassComplete,
detail: recommendedClassLine
detail: recommendedClassLine,
priority: 'recommended'
},
{
label: '전열 역할',
complete: rolesReady,
detail: `전열 ${roleCounts.front} · 돌파 ${roleCounts.flank} · 후원 ${roleCounts.support}`
detail: `전열 ${roleCounts.front} · 돌파 ${roleCounts.flank} · 후원 ${roleCounts.support}`,
priority: 'recommended'
},
{
label: '전투 보급',
complete: assignedSupplyCount > 0 || supplyCount > 0,
detail: supplyCount > 0 ? `배정 ${assignedSupplyCount}/${supplyCount}` : '정비 탭에서 보급 확인'
complete: supplyCount === 0 || assignedSupplyCount > 0,
detail: supplyCount > 0 ? `배정 ${assignedSupplyCount}/${supplyCount}` : '보급 없음',
priority: 'recommended'
},
{
label: '공명 대화',
complete: availableDialogues.length === 0 || completedDialogues >= availableDialogues.length,
detail: `${completedDialogues}/${availableDialogues.length} 완료`
detail: `${completedDialogues}/${availableDialogues.length} 완료`,
priority: 'recommended'
},
{
label: '현지 방문',
complete: availableVisits.length === 0 || completedVisits > 0,
detail: availableVisits.length === 0 ? '방문 없음' : `${completedVisits}/${availableVisits.length} 완료`
detail: availableVisits.length === 0 ? '방문 없음' : `${completedVisits}/${availableVisits.length} 완료`,
priority: 'recommended'
},
{
label: '장비 상태',
complete: this.visitedTabs.has('status'),
detail: this.visitedTabs.has('status') ? '장수 탭 확인됨' : '장수 탭 확인 권장'
detail: this.visitedTabs.has('status') ? '장수 탭 확인됨' : '장수 탭 확인 권장',
priority: 'recommended'
}
];
}
@@ -14249,6 +14271,7 @@ export class CampScene extends Phaser.Scene {
}
getDebugState() {
const sortieChecklist = this.sortieChecklist();
return {
scene: this.scene.key,
activeTab: this.activeTab,
@@ -14262,6 +14285,8 @@ export class CampScene extends Phaser.Scene {
sortieDeploymentPreview: this.sortieDeploymentPreviewDebug(),
sortieFocusedUnitId: this.sortieFocusedUnitId,
sortieFocusedUnit: this.sortieFocusedUnitSummary(),
sortieChecklist,
sortieNextAction: this.sortiePrepSubtitle(sortieChecklist),
reserveTrainingFocus: this.reserveTrainingFocusDefinition(),
reserveTrainingFocusOptions: campaignReserveTrainingFocusDefinitions.map((focus) => ({ ...focus })),
sortieRosterView: this.sortieRosterViewState(this.sortieAllies().length),