feat: turn first victory recall into camp preparation
This commit is contained in:
@@ -24,6 +24,10 @@ import { getUnitClass, terrainRules, type TerrainType, type UnitClassKey } from
|
||||
import { defaultBattleScenario, getBattleScenario, type BattleScenarioDefinition, type BattleScenarioId } from '../data/battles';
|
||||
import { getSortieFlow, type SortieFlow } from '../data/campaignFlow';
|
||||
import { getCampSoundscape, type CampSoundscape } from '../data/campSoundscapes';
|
||||
import {
|
||||
resolveFirstBattleCampFollowup,
|
||||
type FirstBattleCampFollowup
|
||||
} from '../data/firstBattleCampFollowup';
|
||||
import {
|
||||
findCityStayAfterBattle,
|
||||
type CityEquipmentOffer,
|
||||
@@ -11353,6 +11357,9 @@ export class CampScene extends Phaser.Scene {
|
||||
private cityDialogueChoiceButtons: Phaser.GameObjects.Rectangle[] = [];
|
||||
private cityEquipmentOfferViews: CityEquipmentOfferView[] = [];
|
||||
private selectedDialogueId = campDialogues[0].id;
|
||||
private campDialogueRowButtons: Record<string, Phaser.GameObjects.Rectangle> = {};
|
||||
private campDialogueChoiceButtons: Record<string, Phaser.GameObjects.Rectangle> = {};
|
||||
private campDialogueBodyText?: Phaser.GameObjects.Text;
|
||||
private selectedVisitId = campVisits[0].id;
|
||||
private equipmentInventoryPage = 0;
|
||||
private equipmentPanelBackground?: Phaser.GameObjects.Rectangle;
|
||||
@@ -11399,6 +11406,9 @@ export class CampScene extends Phaser.Scene {
|
||||
private sortiePrimaryActionButton?: CampActionButtonView;
|
||||
private sortieNextActionGuideBackground?: Phaser.GameObjects.Rectangle;
|
||||
private sortieNextActionGuideText?: Phaser.GameObjects.Text;
|
||||
private firstBattleFollowupCtaButton?: Phaser.GameObjects.Rectangle;
|
||||
private firstBattleFollowupCard?: Phaser.GameObjects.Rectangle;
|
||||
private firstBattleFollowupSummaryText?: Phaser.GameObjects.Text;
|
||||
private visitedTabs = new Set<CampTab>();
|
||||
private selectedSortieUnitIds: string[] = [];
|
||||
private sortieFormationAssignments: SortieFormationAssignments = {};
|
||||
@@ -11471,6 +11481,9 @@ export class CampScene extends Phaser.Scene {
|
||||
this.cityInformationActionButton = undefined;
|
||||
this.cityDialogueChoiceButtons = [];
|
||||
this.cityEquipmentOfferViews = [];
|
||||
this.campDialogueRowButtons = {};
|
||||
this.campDialogueChoiceButtons = {};
|
||||
this.campDialogueBodyText = undefined;
|
||||
this.dialogueObjects = [];
|
||||
this.sortieObjects = [];
|
||||
this.sortieComparisonPanelView = undefined;
|
||||
@@ -11535,6 +11548,9 @@ export class CampScene extends Phaser.Scene {
|
||||
this.sortiePrimaryActionButton = undefined;
|
||||
this.sortieNextActionGuideBackground = undefined;
|
||||
this.sortieNextActionGuideText = undefined;
|
||||
this.firstBattleFollowupCtaButton = undefined;
|
||||
this.firstBattleFollowupCard = undefined;
|
||||
this.firstBattleFollowupSummaryText = undefined;
|
||||
this.visitedTabs = new Set(['status']);
|
||||
this.campaign = getCampaignState();
|
||||
this.report = this.campaign.firstBattleReport ?? getFirstBattleReport() ?? this.createFallbackReport();
|
||||
@@ -12783,11 +12799,42 @@ export class CampScene extends Phaser.Scene {
|
||||
);
|
||||
}
|
||||
|
||||
private firstBattleCampFollowup(): FirstBattleCampFollowup | undefined {
|
||||
if (!this.isFirstSortiePrepSlice()) {
|
||||
return undefined;
|
||||
}
|
||||
const resolution = resolveFirstBattleCampFollowup(this.report);
|
||||
return resolution.source === 'campaign' ? resolution : undefined;
|
||||
}
|
||||
|
||||
private campDialogueWithFirstBattleFollowup(dialogue: CampDialogue) {
|
||||
const followup = this.firstBattleCampFollowup();
|
||||
if (!followup || dialogue.id !== followup.targetDialogueId) {
|
||||
return dialogue;
|
||||
}
|
||||
return {
|
||||
...dialogue,
|
||||
title: followup.dialogueTitle,
|
||||
lines: [...followup.dialogueLines]
|
||||
};
|
||||
}
|
||||
|
||||
private hasPendingFirstBattleCampFollowup() {
|
||||
const followup = this.firstBattleCampFollowup();
|
||||
return Boolean(
|
||||
followup &&
|
||||
!this.completedCampDialogues().includes(followup.targetDialogueId)
|
||||
);
|
||||
}
|
||||
|
||||
private availableCampDialogues() {
|
||||
const battleId = this.currentCampBattleId();
|
||||
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));
|
||||
const available = dialogues.length > 0
|
||||
? dialogues
|
||||
: campDialogues.filter((dialogue) => dialogue.availableAfterBattleIds.includes(defaultBattleScenario.id));
|
||||
return available.map((dialogue) => this.campDialogueWithFirstBattleFollowup(dialogue));
|
||||
}
|
||||
|
||||
private completedAvailableDialogues() {
|
||||
@@ -13744,8 +13791,14 @@ export class CampScene extends Phaser.Scene {
|
||||
}));
|
||||
text.setOrigin(0.5);
|
||||
text.setInteractive({ useHandCursor: true });
|
||||
const badgeLabel = tab === 'city' ? '새' : width < 70 ? 'N' : 'NEW';
|
||||
const newBadge = tab === 'city' || tab === 'supplies' || tab === 'equipment'
|
||||
const badgeLabel = tab === 'city'
|
||||
? '새'
|
||||
: tab === 'dialogue'
|
||||
? '회고'
|
||||
: width < 70
|
||||
? 'N'
|
||||
: 'NEW';
|
||||
const newBadge = tab === 'city' || tab === 'dialogue' || tab === 'supplies' || tab === 'equipment'
|
||||
? this.scaleLegacyCampUi(this.add.text(x + width / 2 - 10, y - 17, badgeLabel, {
|
||||
...this.textStyle(9, '#fff2b8', true),
|
||||
backgroundColor: '#8a3f25',
|
||||
@@ -13779,6 +13832,7 @@ export class CampScene extends Phaser.Scene {
|
||||
indicator.setAlpha(active ? 1 : 0.66);
|
||||
newBadge?.setVisible(Boolean(
|
||||
(tab === 'city' && this.hasPendingCityStayActions()) ||
|
||||
(tab === 'dialogue' && this.hasPendingFirstBattleCampFollowup()) ||
|
||||
(tab === 'supplies' && pendingCategories.has('supplies')) ||
|
||||
(tab === 'equipment' && pendingCategories.has('equipment'))
|
||||
));
|
||||
@@ -14172,20 +14226,77 @@ export class CampScene extends Phaser.Scene {
|
||||
});
|
||||
|
||||
const commandY = y + height - 104;
|
||||
const firstBattleFollowup = firstSortie ? this.firstBattleCampFollowup() : undefined;
|
||||
const command = this.trackSortie(this.add.rectangle(x + 18, commandY, width - 36, 86, 0x211b14, 0.94));
|
||||
command.setOrigin(0);
|
||||
command.setDepth(depth + 1);
|
||||
command.setStrokeStyle(1, palette.gold, 0.6);
|
||||
this.trackSortie(this.add.text(x + 34, commandY + 12, '지휘관 판단', this.textStyle(14, '#ffdf7b', true))).setDepth(depth + 2);
|
||||
this.trackSortie(
|
||||
this.add.text(x + 34, commandY + 36, scenario.tacticalGuide?.summary ?? scenario.openingObjectiveLines[1] ?? (firstSortie
|
||||
if (firstBattleFollowup) {
|
||||
this.firstBattleFollowupCard = command;
|
||||
}
|
||||
const commandTitle = firstBattleFollowup
|
||||
? `지난 전투 인계 · ${firstBattleFollowup.mentorName}`
|
||||
: '지휘관 판단';
|
||||
this.trackSortie(this.add.text(x + 34, commandY + 12, commandTitle, this.textStyle(14, '#ffdf7b', true))).setDepth(depth + 2);
|
||||
const commandSummary = firstBattleFollowup
|
||||
? firstBattleFollowup.achieved
|
||||
? `${firstBattleFollowup.originalOrderLabel} 완수 → ${firstBattleFollowup.recommendedNextOrderLabel} · ${firstBattleFollowup.focusCriterionLabel}`
|
||||
: `${firstBattleFollowup.originalOrderLabel} 보완 → ${firstBattleFollowup.focusCriterionLabel}`
|
||||
: scenario.tacticalGuide?.summary ?? scenario.openingObjectiveLines[1] ?? (firstSortie
|
||||
? '세 형제가 서로 다른 길을 맡아 적의 전열을 흔드십시오.'
|
||||
: '전열·돌파·후원의 균형으로 적의 주력을 나누십시오.'), {
|
||||
...this.textStyle(13, '#d4dce6'),
|
||||
wordWrap: { width: width - 68, useAdvancedWrap: true },
|
||||
lineSpacing: 3
|
||||
: '전열·돌파·후원의 균형으로 적의 주력을 나누십시오.');
|
||||
const commandSummaryText = this.trackSortie(
|
||||
this.add.text(x + 34, commandY + 36, commandSummary, {
|
||||
...this.textStyle(firstBattleFollowup ? 11 : 13, '#d4dce6'),
|
||||
wordWrap: { width: firstBattleFollowup ? width - 214 : width - 68, useAdvancedWrap: true },
|
||||
lineSpacing: firstBattleFollowup ? 2 : 3
|
||||
})
|
||||
).setDepth(depth + 2);
|
||||
);
|
||||
commandSummaryText.setDepth(depth + 2);
|
||||
if (firstBattleFollowup) {
|
||||
this.firstBattleFollowupSummaryText = commandSummaryText;
|
||||
}
|
||||
if (firstBattleFollowup) {
|
||||
const buttonWidth = 132;
|
||||
const buttonX = x + width - 86;
|
||||
const buttonY = commandY + 51;
|
||||
const button = this.trackSortie(this.add.rectangle(buttonX, buttonY, buttonWidth, 34, 0x4a371d, 0.98));
|
||||
button.setDepth(depth + 2);
|
||||
button.setStrokeStyle(2, palette.gold, 0.92);
|
||||
button.setInteractive({ useHandCursor: true });
|
||||
button.on('pointerover', () => button.setFillStyle(0x654c25, 1));
|
||||
button.on('pointerout', () => button.setFillStyle(0x4a371d, 0.98));
|
||||
button.on('pointerdown', () => this.openFirstBattleFollowupOrderBrowser());
|
||||
this.firstBattleFollowupCtaButton = button;
|
||||
const label = this.trackSortie(
|
||||
this.add.text(
|
||||
buttonX,
|
||||
buttonY,
|
||||
`${firstBattleFollowup.recommendedNextOrderLabel} 군령 보기`,
|
||||
this.textStyle(11, '#fff2b8', true)
|
||||
)
|
||||
);
|
||||
label.setOrigin(0.5);
|
||||
label.setDepth(depth + 3);
|
||||
label.setInteractive({ useHandCursor: true });
|
||||
label.on('pointerover', () => button.setFillStyle(0x654c25, 1));
|
||||
label.on('pointerout', () => button.setFillStyle(0x4a371d, 0.98));
|
||||
label.on('pointerdown', () => this.openFirstBattleFollowupOrderBrowser());
|
||||
}
|
||||
}
|
||||
|
||||
private openFirstBattleFollowupOrderBrowser() {
|
||||
if (!this.firstBattleCampFollowup() || !this.nextSortieScenario()) {
|
||||
return;
|
||||
}
|
||||
this.sortiePrepStep = 'formation';
|
||||
this.closeSortieRecommendationBrowserState();
|
||||
this.closeSortiePresetBrowserState();
|
||||
this.sortieFormationPanelMode = 'order';
|
||||
this.sortieHoveredUnitId = undefined;
|
||||
this.sortiePinnedSwapCandidateUnitId = undefined;
|
||||
soundDirector.playSelect();
|
||||
this.showSortiePrep();
|
||||
}
|
||||
|
||||
private renderFirstSortieArtwork(x: number, y: number, width: number, height: number, depth: number, alpha: number) {
|
||||
@@ -14627,8 +14738,12 @@ export class CampScene extends Phaser.Scene {
|
||||
bg.setDepth(depth);
|
||||
bg.setStrokeStyle(1, palette.gold, 0.7);
|
||||
|
||||
const firstBattleFollowup = this.firstBattleCampFollowup();
|
||||
this.trackSortie(this.add.text(x + 18, y + 13, '작전 명령', this.textStyle(19, '#f2e3bf', true))).setDepth(depth + 1);
|
||||
this.trackSortie(this.add.text(x + 126, y + 18, '편성과 별개 · 전투 능력 보너스 없음', this.textStyle(10, '#9fb0bf', true)))
|
||||
const orderBrowserHint = firstBattleFollowup
|
||||
? `지난 전투 ${firstBattleFollowup.statusLabel} · ${firstBattleFollowup.recommendationTitle}`
|
||||
: '편성과 별개 · 전투 능력 보너스 없음';
|
||||
this.trackSortie(this.add.text(x + 126, y + 18, this.compactText(orderBrowserHint, 48), this.textStyle(10, '#9fb0bf', true)))
|
||||
.setDepth(depth + 1);
|
||||
|
||||
const closeButton = this.trackSortie(this.add.rectangle(x + width - 96, y + 9, 78, 30, 0x18232e, 0.96));
|
||||
@@ -14655,17 +14770,19 @@ export class CampScene extends Phaser.Scene {
|
||||
sortieOrderDefinitions.forEach((definition, index) => {
|
||||
const cardY = y + 50 + index * (cardHeight + cardGap);
|
||||
const selected = selectedOrderId === definition.id;
|
||||
const recommended = firstBattleFollowup?.recommendedNextOrderId === definition.id;
|
||||
const summary = summaries.get(definition.id);
|
||||
const currentResult = currentBattleResults?.[definition.id];
|
||||
const accent = this.sortiePresetDefinition(definition.id).accent;
|
||||
const fill = selected ? 0x1d3028 : currentResult?.achieved ? 0x172a22 : 0x151f2a;
|
||||
const fill = selected ? 0x1d3028 : recommended ? 0x2a2419 : currentResult?.achieved ? 0x172a22 : 0x151f2a;
|
||||
const stroke = selected ? palette.gold : recommended ? palette.gold : currentResult?.achieved ? palette.green : accent;
|
||||
const card = this.trackSortie(this.add.rectangle(cardX, cardY, cardWidth, cardHeight, fill, 0.98));
|
||||
card.setOrigin(0);
|
||||
card.setDepth(depth + 1);
|
||||
card.setStrokeStyle(selected ? 2 : 1, selected ? palette.gold : currentResult?.achieved ? palette.green : accent, selected ? 0.96 : 0.52);
|
||||
card.setStrokeStyle(selected || recommended ? 2 : 1, stroke, selected ? 0.96 : recommended ? 0.84 : 0.52);
|
||||
card.setInteractive({ useHandCursor: true });
|
||||
card.on('pointerover', () => card.setFillStyle(selected ? 0x263d32 : 0x22303c, 1).setStrokeStyle(2, palette.gold, 0.96));
|
||||
card.on('pointerout', () => card.setFillStyle(fill, 0.98).setStrokeStyle(selected ? 2 : 1, selected ? palette.gold : currentResult?.achieved ? palette.green : accent, selected ? 0.96 : 0.52));
|
||||
card.on('pointerout', () => card.setFillStyle(fill, 0.98).setStrokeStyle(selected || recommended ? 2 : 1, stroke, selected ? 0.96 : recommended ? 0.84 : 0.52));
|
||||
card.on('pointerdown', () => this.selectSortieOrder(definition.id));
|
||||
cards[definition.id] = card;
|
||||
|
||||
@@ -14693,17 +14810,20 @@ export class CampScene extends Phaser.Scene {
|
||||
this.trackSortie(this.add.text(cardX + 22, cardY + 79, this.compactText(rewardLine, width > 650 ? 82 : 66), this.textStyle(10, '#ffdf7b', true)))
|
||||
.setDepth(depth + 2);
|
||||
|
||||
const badgeLabel = selected ? '선택됨' : currentResult?.achieved ? '달성 기록' : '선택';
|
||||
const badge = this.trackSortie(this.add.rectangle(cardX + cardWidth - 82, cardY + 9, 66, 22, selected ? 0x304333 : 0x18232e, 0.98));
|
||||
const badgeLabel = selected ? '선택됨' : recommended ? '회고 추천' : currentResult?.achieved ? '달성 기록' : '선택';
|
||||
const badge = this.trackSortie(this.add.rectangle(cardX + cardWidth - 82, cardY + 9, 66, 22, selected ? 0x304333 : recommended ? 0x4a371d : 0x18232e, 0.98));
|
||||
badge.setOrigin(0);
|
||||
badge.setDepth(depth + 3);
|
||||
badge.setStrokeStyle(1, selected ? palette.green : accent, selected ? 0.86 : 0.56);
|
||||
this.trackSortie(this.add.text(cardX + cardWidth - 49, cardY + 20, badgeLabel, this.textStyle(9, selected ? '#e7ffd9' : '#d8ecff', true)))
|
||||
badge.setStrokeStyle(1, selected ? palette.green : recommended ? palette.gold : accent, selected ? 0.86 : recommended ? 0.78 : 0.56);
|
||||
this.trackSortie(this.add.text(cardX + cardWidth - 49, cardY + 20, badgeLabel, this.textStyle(9, selected ? '#e7ffd9' : recommended ? '#fff2b8' : '#d8ecff', true)))
|
||||
.setOrigin(0.5)
|
||||
.setDepth(depth + 4);
|
||||
});
|
||||
|
||||
this.trackSortie(this.add.text(x + 18, y + height - 24, '명령 선택은 도전 목표·전적·최초 보상만 바꾸며 편성책과 보급을 유지합니다.', this.textStyle(10, '#9fb0bf', true)))
|
||||
const footer = firstBattleFollowup
|
||||
? `회고 추천 · ${firstBattleFollowup.recommendationReason} · 선택 전에는 저장되지 않습니다.`
|
||||
: '명령 선택은 도전 목표·전적·최초 보상만 바꾸며 편성책과 보급을 유지합니다.';
|
||||
this.trackSortie(this.add.text(x + 18, y + height - 24, this.compactText(footer, width > 650 ? 92 : 72), this.textStyle(10, '#9fb0bf', true)))
|
||||
.setDepth(depth + 1);
|
||||
this.sortieOrderBrowserView = { closeButton, cards };
|
||||
}
|
||||
@@ -20173,6 +20293,9 @@ export class CampScene extends Phaser.Scene {
|
||||
this.sortiePrimaryActionButton = undefined;
|
||||
this.sortieNextActionGuideBackground = undefined;
|
||||
this.sortieNextActionGuideText = undefined;
|
||||
this.firstBattleFollowupCtaButton = undefined;
|
||||
this.firstBattleFollowupCard = undefined;
|
||||
this.firstBattleFollowupSummaryText = undefined;
|
||||
this.sortiePortraitRosterLayout = undefined;
|
||||
this.sortieRosterToggleBounds = [];
|
||||
this.sortieHoveredUnitId = undefined;
|
||||
@@ -22408,6 +22531,7 @@ export class CampScene extends Phaser.Scene {
|
||||
this.track(this.add.text(x + 24, y + 56, '출진 전 대화에서 선택지를 고르면 해당 장수들의 공명 경험치가 오릅니다.', this.textStyle(14, '#d4dce6')));
|
||||
|
||||
const dialogues = this.availableCampDialogues();
|
||||
const firstBattleFollowup = this.firstBattleCampFollowup();
|
||||
const compactDialogueList = dialogues.length > 3;
|
||||
const dialogueRowGap = compactDialogueList ? 35 : 64;
|
||||
const dialogueRowHeight = compactDialogueList ? 30 : 48;
|
||||
@@ -22423,12 +22547,31 @@ export class CampScene extends Phaser.Scene {
|
||||
row.setOrigin(0);
|
||||
row.setStrokeStyle(1, completed ? palette.green : selected ? palette.gold : palette.blue, selected ? 0.72 : 0.46);
|
||||
row.setInteractive({ useHandCursor: true });
|
||||
this.campDialogueRowButtons[dialogue.id] = row;
|
||||
row.on('pointerdown', () => {
|
||||
soundDirector.playSelect();
|
||||
this.selectedDialogueId = dialogue.id;
|
||||
this.render();
|
||||
});
|
||||
this.track(this.add.text(x + 38, rowY + (compactDialogueList ? 3 : 8), dialogue.title, this.textStyle(compactDialogueList ? 11 : 15, completed ? '#a8ffd0' : '#f2e3bf', true)));
|
||||
const isFirstBattleFollowup = firstBattleFollowup?.targetDialogueId === dialogue.id;
|
||||
const title = isFirstBattleFollowup
|
||||
? this.compactText(dialogue.title, compactDialogueList ? 20 : 14)
|
||||
: dialogue.title;
|
||||
this.track(this.add.text(x + 38, rowY + (compactDialogueList ? 3 : 8), title, this.textStyle(compactDialogueList ? 11 : 15, completed ? '#a8ffd0' : '#f2e3bf', true)));
|
||||
if (isFirstBattleFollowup) {
|
||||
this.track(
|
||||
this.add.text(
|
||||
x + 320,
|
||||
rowY + (compactDialogueList ? 4 : 9),
|
||||
completed ? '완료' : '회고',
|
||||
{
|
||||
...this.textStyle(compactDialogueList ? 8 : 9, completed ? '#a8ffd0' : '#fff2b8', true),
|
||||
backgroundColor: completed ? '#21402d' : '#8a3f25',
|
||||
padding: { x: 4, y: 2 }
|
||||
}
|
||||
)
|
||||
).setOrigin(1, 0);
|
||||
}
|
||||
const maxReward = dialogue.rewardExp + Math.max(...dialogue.choices.map((choice) => choice.rewardExp));
|
||||
this.track(this.add.text(x + 38, rowY + (compactDialogueList ? 17 : 29), `${this.unitName(dialogue.unitIds[0])} · ${this.unitName(dialogue.unitIds[1])} 공명 +${dialogue.rewardExp}~${maxReward}`, this.textStyle(compactDialogueList ? 9 : 12, '#9fb0bf')));
|
||||
});
|
||||
@@ -22453,13 +22596,14 @@ export class CampScene extends Phaser.Scene {
|
||||
bg.setOrigin(0);
|
||||
bg.setStrokeStyle(1, completed ? palette.green : palette.gold, 0.5);
|
||||
this.track(this.add.text(x + 18, y + 16, dialogue.title, this.textStyle(20, '#f2e3bf', true)));
|
||||
this.track(
|
||||
this.add.text(x + 18, y + 52, dialogue.lines.join('\n\n'), {
|
||||
...this.textStyle(15, '#d4dce6'),
|
||||
const dialogueBody = this.track(
|
||||
this.add.text(x + 18, y + 52, dialogue.lines.join('\n'), {
|
||||
...this.textStyle(14, '#d4dce6'),
|
||||
wordWrap: { width: width - 36, useAdvancedWrap: true },
|
||||
lineSpacing: 5
|
||||
lineSpacing: 3
|
||||
})
|
||||
);
|
||||
this.campDialogueBodyText = dialogueBody;
|
||||
|
||||
if (completed) {
|
||||
const chosen = this.recordedDialogueChoice(dialogue);
|
||||
@@ -22487,6 +22631,7 @@ export class CampScene extends Phaser.Scene {
|
||||
const button = this.track(this.add.rectangle(x + width / 2, choiceY, width - 36, 34, 0x1a2630, 0.96));
|
||||
button.setStrokeStyle(1, palette.gold, 0.76);
|
||||
button.setInteractive({ useHandCursor: true });
|
||||
this.campDialogueChoiceButtons[`${dialogue.id}:${choice.id}`] = button;
|
||||
button.on('pointerover', () => button.setFillStyle(0x283947, 0.98));
|
||||
button.on('pointerout', () => button.setFillStyle(0x1a2630, 0.96));
|
||||
button.on('pointerdown', () => this.completeDialogue(dialogue, choice));
|
||||
@@ -23730,7 +23875,11 @@ export class CampScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private showDialogueReward(dialogue: CampDialogue, choice: CampDialogueChoice, rewardExp: number) {
|
||||
this.showCampNotice(`획득 내역 · ${choice.label} · 공명 +${rewardExp}\n응답 · ${choice.response}`);
|
||||
const followup = this.firstBattleCampFollowup();
|
||||
const preparationLine = followup?.targetDialogueId === dialogue.id
|
||||
? `\n다음 준비 · ${followup.recommendationTitle}`
|
||||
: '';
|
||||
this.showCampNotice(`획득 내역 · ${choice.label} · 공명 +${rewardExp}\n응답 · ${choice.response}${preparationLine}`);
|
||||
}
|
||||
|
||||
private showCampNotice(message: string) {
|
||||
@@ -24563,6 +24712,9 @@ export class CampScene extends Phaser.Scene {
|
||||
private clearContent() {
|
||||
this.contentObjects.forEach((object) => object.destroy());
|
||||
this.contentObjects = [];
|
||||
this.campDialogueRowButtons = {};
|
||||
this.campDialogueChoiceButtons = {};
|
||||
this.campDialogueBodyText = undefined;
|
||||
this.campRosterLayout = undefined;
|
||||
this.cityPanelBackground = undefined;
|
||||
this.cityExploreButton = undefined;
|
||||
@@ -24716,6 +24868,11 @@ export class CampScene extends Phaser.Scene {
|
||||
const cityDialogueComplete = cityStay
|
||||
? this.completedCampDialogues().includes(cityStay.dialogue.id)
|
||||
: false;
|
||||
const firstBattleCampFollowup = this.firstBattleCampFollowup();
|
||||
const availableCampDialogues = this.availableCampDialogues();
|
||||
const selectedCampDialogue = availableCampDialogues.find(
|
||||
(dialogue) => dialogue.id === this.selectedDialogueId
|
||||
) ?? availableCampDialogues[0];
|
||||
return {
|
||||
scene: this.scene.key,
|
||||
victoryRewardAcknowledgement: {
|
||||
@@ -24772,6 +24929,60 @@ export class CampScene extends Phaser.Scene {
|
||||
strokeColor: button.bg.strokeColor,
|
||||
lineWidth: button.bg.lineWidth
|
||||
})),
|
||||
firstVictoryFollowup: firstBattleCampFollowup
|
||||
? {
|
||||
available: true,
|
||||
sourceBattleId: this.report?.battleId ?? null,
|
||||
originalOrderId: firstBattleCampFollowup.originalOrderId,
|
||||
originalOrderLabel: firstBattleCampFollowup.originalOrderLabel,
|
||||
achieved: firstBattleCampFollowup.achieved,
|
||||
focusCriterionId: firstBattleCampFollowup.focusCriterionId,
|
||||
focusCriterionLabel: firstBattleCampFollowup.focusCriterionLabel,
|
||||
statusLabel: firstBattleCampFollowup.statusLabel,
|
||||
mentorUnitId: firstBattleCampFollowup.mentorUnitId,
|
||||
mentorName: firstBattleCampFollowup.mentorName,
|
||||
targetDialogueId: firstBattleCampFollowup.targetDialogueId,
|
||||
dialogueTitle: firstBattleCampFollowup.dialogueTitle,
|
||||
dialogueLines: [...firstBattleCampFollowup.dialogueLines],
|
||||
dialogueCompleted: this.completedCampDialogues().includes(firstBattleCampFollowup.targetDialogueId),
|
||||
dialogueRowBounds: this.sortieObjectBoundsDebug(
|
||||
this.campDialogueRowButtons[firstBattleCampFollowup.targetDialogueId]
|
||||
),
|
||||
recommendedOrderId: firstBattleCampFollowup.recommendedNextOrderId,
|
||||
recommendedOrderLabel: firstBattleCampFollowup.recommendedNextOrderLabel,
|
||||
recommendationTitle: firstBattleCampFollowup.recommendationTitle,
|
||||
recommendationReason: firstBattleCampFollowup.recommendationReason,
|
||||
handoffCardBounds: this.sortieObjectBoundsDebug(this.firstBattleFollowupCard),
|
||||
handoffSummaryBounds: this.sortieTextBoundsDebug(this.firstBattleFollowupSummaryText),
|
||||
ctaBounds: this.sortieInteractiveObjectBoundsDebug(this.firstBattleFollowupCtaButton),
|
||||
ctaInteractive: Boolean(this.firstBattleFollowupCtaButton?.input?.enabled),
|
||||
recommendedOrderSelected: this.currentSortieOrderId() === firstBattleCampFollowup.recommendedNextOrderId,
|
||||
recommendedOrderCardBounds: this.sortieObjectBoundsDebug(
|
||||
this.sortieOrderBrowserView?.cards[firstBattleCampFollowup.recommendedNextOrderId]
|
||||
)
|
||||
}
|
||||
: null,
|
||||
selectedDialogue: selectedCampDialogue
|
||||
? {
|
||||
id: selectedCampDialogue.id,
|
||||
title: selectedCampDialogue.title,
|
||||
unitIds: [...selectedCampDialogue.unitIds],
|
||||
lines: [...selectedCampDialogue.lines],
|
||||
completed: this.completedCampDialogues().includes(selectedCampDialogue.id),
|
||||
firstVictoryFollowup: firstBattleCampFollowup?.targetDialogueId === selectedCampDialogue.id,
|
||||
rowBounds: this.sortieObjectBoundsDebug(this.campDialogueRowButtons[selectedCampDialogue.id]),
|
||||
bodyBounds: this.sortieTextBoundsDebug(this.campDialogueBodyText),
|
||||
choices: selectedCampDialogue.choices.map((choice) => ({
|
||||
id: choice.id,
|
||||
label: choice.label,
|
||||
response: choice.response,
|
||||
rewardExp: selectedCampDialogue.rewardExp + choice.rewardExp,
|
||||
bounds: this.sortieInteractiveObjectBoundsDebug(
|
||||
this.campDialogueChoiceButtons[`${selectedCampDialogue.id}:${choice.id}`]
|
||||
)
|
||||
}))
|
||||
}
|
||||
: null,
|
||||
cityStay: cityStay
|
||||
? {
|
||||
available: true,
|
||||
@@ -24871,6 +25082,7 @@ export class CampScene extends Phaser.Scene {
|
||||
formationPanelMode: this.sortieFormationPanelMode,
|
||||
selectionBattleId: this.campaign?.sortieOrderSelection?.battleId ?? null,
|
||||
selectedId: sortieOrderId ?? null,
|
||||
recommendedId: firstBattleCampFollowup?.recommendedNextOrderId ?? null,
|
||||
complete: this.hasCurrentSortieOrderSelection(),
|
||||
toggleButtonBounds: this.sortieObjectBoundsDebug(this.sortieOrderToggleButton),
|
||||
closeButtonBounds: this.sortieObjectBoundsDebug(this.sortieOrderBrowserView?.closeButton),
|
||||
@@ -24884,6 +25096,7 @@ export class CampScene extends Phaser.Scene {
|
||||
summary: definition.summary,
|
||||
condition: definition.condition,
|
||||
selected: sortieOrderId === definition.id,
|
||||
recommended: firstBattleCampFollowup?.recommendedNextOrderId === definition.id,
|
||||
attempts: summary?.attempts ?? 0,
|
||||
successes: summary?.successes ?? 0,
|
||||
successRate: summary?.successRate ?? 0,
|
||||
|
||||
Reference in New Issue
Block a user