diff --git a/src/game/scenes/CampScene.ts b/src/game/scenes/CampScene.ts index a62d8fd..1d42608 100644 --- a/src/game/scenes/CampScene.ts +++ b/src/game/scenes/CampScene.ts @@ -1,6 +1,7 @@ import Phaser from 'phaser'; import storyMilitiaUrl from '../../assets/images/story/04-volunteer-militia.png'; import { soundDirector } from '../audio/SoundDirector'; +import { battleUiIconFrames, battleUiIconTextureKey, loadBattleUiIcons, type BattleUiIconKey } from '../data/battleUiIcons'; import { equipmentExpToNext, equipmentSlotLabels, equipmentSlots, getItem, type EquipmentSlot } from '../data/battleItems'; import { getUnitClass, terrainRules, type TerrainType } from '../data/battleRules'; import { defaultBattleScenario, getBattleScenario, type BattleScenarioDefinition, type BattleScenarioId } from '../data/battles'; @@ -10021,7 +10022,7 @@ export class CampScene extends Phaser.Scene { this.selectedDialogueId = this.availableCampDialogues()[0]?.id ?? campDialogues[0].id; this.selectedVisitId = this.availableCampVisits()[0]?.id ?? campVisits[0].id; soundDirector.playMusic('militia-theme'); - this.ensureCampAssets(() => this.drawCampScene()); + loadBattleUiIcons(this, () => this.ensureCampAssets(() => this.drawCampScene())); } private drawCampScene() { @@ -11229,6 +11230,7 @@ export class CampScene extends Phaser.Scene { this.add.text(x + 34, y + 70, prepSubtitle, this.textStyle(15, '#d4dce6')) ); subtitle.setDepth(depth + 2); + this.renderSortieHeaderSummary(x + 690, y + 26, 464, 58, depth + 2); this.renderSortieBriefing(x + 34, y + 104, 520, 168, depth + 2); this.renderSortieChecklist(x + 576, y + 104, 578, 168, depth + 2); @@ -11247,6 +11249,37 @@ export class CampScene extends Phaser.Scene { }, depth + 3); } + private renderSortieHeaderSummary(x: number, y: number, width: number, height: number, depth: number) { + const selectedUnits = this.selectedSortieUnits(); + const selectedIds = new Set(selectedUnits.map((unit) => unit.id)); + const reserveUnits = this.sortieAllies().filter((unit) => !selectedIds.has(unit.id)); + const selectedNames = selectedUnits.map((unit) => unit.name).join(', '); + const reserveNames = reserveUnits.map((unit) => unit.name).join(', '); + const bg = this.trackSortie(this.add.rectangle(x, y, width, height, 0x0d141c, 0.78)); + bg.setOrigin(0); + bg.setDepth(depth); + bg.setStrokeStyle(1, palette.gold, 0.36); + + this.renderSortieBattleUiIcon('leadership', x + 22, y + 20, 24, depth + 1, 0.95); + this.trackSortie( + this.add.text( + x + 44, + y + 10, + this.compactText(`출전 ${selectedUnits.length}명: ${selectedNames || '없음'}`, 35), + this.textStyle(13, '#f2e3bf', true) + ) + ).setDepth(depth + 1); + this.renderSortieBattleUiIcon('focus', x + 22, y + 44, 22, depth + 1, 0.74); + this.trackSortie( + this.add.text( + x + 44, + y + 35, + this.compactText(`대기 ${reserveUnits.length}명: ${reserveNames || '없음'}`, 35), + this.textStyle(12, reserveUnits.length > 0 ? '#c8d2dd' : '#9fb0bf', true) + ) + ).setDepth(depth + 1); + } + private renderSortieBriefing(x: number, y: number, width: number, height: number, depth: number) { const bg = this.trackSortie(this.add.rectangle(x, y, width, height, 0x0d141c, 0.92)); bg.setOrigin(0); @@ -11295,12 +11328,14 @@ export class CampScene extends Phaser.Scene { bg.setDepth(depth); bg.setStrokeStyle(1, palette.blue, 0.48); const allies = this.sortieAllies(); + const displayAllies = this.sortieRosterDisplayUnits(allies); const selectedCount = this.selectedSortieUnitIds.length; const maxUnits = this.sortieMaxUnits(); + const reserveCount = Math.max(0, allies.length - selectedCount); const rosterView = this.sortieRosterViewState(allies.length, height); const { denseRoster, rowGap, rowHeight, listTopOffset, listFooterHeight, maxVisibleRows, maxScroll } = rosterView; this.sortieRosterScroll = Phaser.Math.Clamp(this.sortieRosterScroll, 0, maxScroll); - const visibleAllies = allies.slice(this.sortieRosterScroll, this.sortieRosterScroll + maxVisibleRows); + const visibleAllies = displayAllies.slice(this.sortieRosterScroll, this.sortieRosterScroll + maxVisibleRows); const handleRosterWheel = ( _pointer: Phaser.Input.Pointer, _deltaX: number, @@ -11320,9 +11355,9 @@ export class CampScene extends Phaser.Scene { bg.on('wheel', handleRosterWheel); } this.trackSortie( - this.add.text(x + 18, y + 14, `출전 무장 선택 ${selectedCount}/${maxUnits}`, this.textStyle(18, '#f2e3bf', true)) + this.add.text(x + 18, y + 14, `출전 ${selectedCount}/${maxUnits} · 대기 ${reserveCount}`, this.textStyle(18, '#f2e3bf', true)) ).setDepth(depth + 1); - this.trackSortie(this.add.text(x + width - 18, y + 17, '클릭: 분석/출전 전환', this.textStyle(11, '#9fb0bf'))).setOrigin(1, 0).setDepth(depth + 1); + this.trackSortie(this.add.text(x + width - 18, y + 17, '선택 무장 우선 표시 · 클릭 전환', this.textStyle(11, '#9fb0bf'))).setOrigin(1, 0).setDepth(depth + 1); visibleAllies.forEach((unit, index) => { const rowY = y + listTopOffset + index * rowGap; @@ -11331,10 +11366,11 @@ export class CampScene extends Phaser.Scene { const recruited = !foundingSortieUnitIds.has(unit.id); const recommendation = this.sortieRecommendation(unit.id); const summary = this.sortieUnitTacticalSummary(unit); - const row = this.trackSortie(this.add.rectangle(x + 18, rowY - 5, width - 36, rowHeight, selected ? 0x172a22 : 0x151b24, selected ? 0.96 : 0.82)); + const recommendedReserve = Boolean(recommendation && !selected); + const row = this.trackSortie(this.add.rectangle(x + 18, rowY - 5, width - 36, rowHeight, selected ? 0x172a22 : recommendedReserve ? 0x241f17 : 0x151b24, selected ? 0.96 : 0.84)); row.setOrigin(0); row.setDepth(depth + 1); - row.setStrokeStyle(1, selected ? palette.green : 0x53606c, selected ? 0.62 : 0.38); + row.setStrokeStyle(1, selected ? palette.green : recommendedReserve ? palette.gold : 0x53606c, selected ? 0.7 : recommendedReserve ? 0.54 : 0.36); row.setInteractive({ useHandCursor: true }); row.on('wheel', handleRosterWheel); row.on('pointerover', () => { @@ -11342,22 +11378,25 @@ export class CampScene extends Phaser.Scene { }); row.on('pointerdown', () => this.toggleSortieUnit(unit.id)); - const marker = selected ? '출전' : '대기'; - const markerLabel = required ? '필수' : recommendation ? '추천' : recruited ? '합류' : marker; - this.trackSortie(this.add.text(x + 30, rowY, markerLabel, this.textStyle(denseRoster ? 10 : 12, required || recommendation ? '#ffdf7b' : selected ? '#a8ffd0' : '#9fb0bf', true))).setDepth(depth + 2); - this.trackSortie(this.add.text(x + (denseRoster ? 78 : 84), rowY, `${unit.name} Lv ${unit.level}`, this.textStyle(denseRoster ? 12 : 14, selected ? '#f2e3bf' : '#87919c', true))).setDepth(depth + 2); - this.trackSortie(this.add.text(x + (denseRoster ? 194 : 214), rowY, this.compactText(`${unit.className} · ${getUnitClass(unit.classKey).role}`, denseRoster ? 17 : 19), this.textStyle(denseRoster ? 10 : 12, selected ? '#d4dce6' : '#77818c', true))).setDepth(depth + 2); + const markerLabel = required ? '필수 출전' : selected ? '출전' : recommendation ? '추천 대기' : recruited ? '합류 대기' : '대기'; + this.trackSortie(this.add.text(x + 30, rowY, markerLabel, this.textStyle(denseRoster ? 9 : 11, required || recommendation ? '#ffdf7b' : selected ? '#a8ffd0' : '#9fb0bf', true))).setDepth(depth + 2); + if (!denseRoster) { + this.renderSortieBattleUiIcon(this.unitClassIconKey(unit), x + 90, rowY + 8, 20, depth + 2, selected ? 1 : 0.58); + } + this.trackSortie(this.add.text(x + (denseRoster ? 84 : 112), rowY, `${unit.name} Lv ${unit.level}`, this.textStyle(denseRoster ? 12 : 14, selected ? '#f2e3bf' : recommendedReserve ? '#d8b15f' : '#87919c', true))).setDepth(depth + 2); + this.trackSortie(this.add.text(x + (denseRoster ? 200 : 234), rowY, this.compactText(`${unit.className} · ${getUnitClass(unit.classKey).role}`, denseRoster ? 17 : 17), this.textStyle(denseRoster ? 10 : 12, selected ? '#d4dce6' : '#77818c', true))).setDepth(depth + 2); this.trackSortie(this.add.text(x + 424, rowY, denseRoster ? this.compactText(summary.statLine, 23) : `병력 ${unit.hp}/${unit.maxHp}`, this.textStyle(denseRoster ? 10 : 12, selected ? '#d4dce6' : '#77818c', true))).setDepth(depth + 2); if (!denseRoster) { this.drawSortieBar(x + 514, rowY + 6, 74, 7, unit.hp / unit.maxHp, selected ? palette.green : 0x53606c, depth + 2); } - this.trackSortie(this.add.text(x + 610, rowY, this.compactText(denseRoster ? summary.bondLine : summary.terrainLine, denseRoster ? 15 : 13), this.textStyle(11, selected ? (denseRoster ? '#a8ffd0' : '#d8b15f') : '#77818c', true))).setDepth(depth + 2); + this.trackSortie(this.add.text(x + 610, rowY, this.compactText(denseRoster ? summary.bondLine : summary.terrainLine, denseRoster ? 15 : 13), this.textStyle(11, selected ? (denseRoster ? '#a8ffd0' : '#d8b15f') : recommendedReserve ? '#d8b15f' : '#77818c', true))).setDepth(depth + 2); if (!denseRoster) { - this.renderSortieEquipmentIcons(unit, x + 84, rowY + 19, selected, depth + 2); - this.trackSortie(this.add.text(x + 162, rowY + 18, this.compactText(summary.equipmentLine, 34), this.textStyle(11, selected ? '#c8d2dd' : '#68727e'))).setDepth(depth + 2); + this.renderSortieEquipmentIcons(unit, x + 112, rowY + 19, selected, depth + 2); + this.trackSortie(this.add.text(x + 190, rowY + 18, this.compactText(summary.equipmentLine, 29), this.textStyle(11, selected ? '#c8d2dd' : '#68727e'))).setDepth(depth + 2); this.trackSortie(this.add.text(x + 424, rowY + 18, this.compactText(summary.statLine, 23), this.textStyle(11, selected ? '#c8d2dd' : '#68727e'))).setDepth(depth + 2); - this.trackSortie(this.add.text(x + 610, rowY + 18, this.compactText(summary.bondLine, 15), this.textStyle(11, selected ? '#a8ffd0' : '#68727e', selected))).setDepth(depth + 2); + const secondLine = recommendation && !selected ? `추천: ${recommendation.reason}` : summary.bondLine; + this.trackSortie(this.add.text(x + 610, rowY + 18, this.compactText(secondLine, 17), this.textStyle(11, selected ? '#a8ffd0' : recommendedReserve ? '#ffdf7b' : '#68727e', selected || recommendedReserve))).setDepth(depth + 2); } }); @@ -11388,6 +11427,29 @@ export class CampScene extends Phaser.Scene { } } + private sortieRosterDisplayUnits(allies: UnitData[]) { + const selected = new Set(this.selectedSortieUnitIds); + const order = new Map(allies.map((unit, index) => [unit.id, index])); + return [...allies].sort((a, b) => { + const aSelected = selected.has(a.id); + const bSelected = selected.has(b.id); + if (aSelected !== bSelected) { + return Number(bSelected) - Number(aSelected); + } + const aRecommended = Boolean(this.sortieRecommendation(a.id)); + const bRecommended = Boolean(this.sortieRecommendation(b.id)); + if (aRecommended !== bRecommended) { + return Number(bRecommended) - Number(aRecommended); + } + const aRequired = this.isRequiredSortieUnit(a.id); + const bRequired = this.isRequiredSortieUnit(b.id); + if (aRequired !== bRequired) { + return Number(bRequired) - Number(aRequired); + } + return (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0); + }); + } + private updateSortieRosterScroll(nextScroll: number, maxScroll: number) { const clamped = Phaser.Math.Clamp(Math.round(nextScroll), 0, maxScroll); if (clamped === this.sortieRosterScroll) { @@ -11431,19 +11493,38 @@ export class CampScene extends Phaser.Scene { this.add.text(x + width - 18, y + 17, `${plan.selectedCount}/${plan.maxCount}명 · 지형 ${plan.terrainGrade}`, this.textStyle(12, '#d8b15f', true)) ).setOrigin(1, 0).setDepth(depth + 1); - this.renderSortieDeploymentMap(x + 18, y + 46, width - 36, 92, depth + 1); + this.renderSortieDeploymentMap(x + 18, y + 46, width - 36, 84, depth + 1); + this.renderSortieRoleSlots(x + 18, y + 136, width - 36, 48, plan, depth + 1); + this.trackSortie( + this.add.text( + x + 18, + y + 190, + this.compactText(`${plan.recommendationLine} · 공명 ${plan.activeBondCount}개 · ${plan.objectiveLine}`, 44), + this.textStyle(11, '#d4dce6', true) + ) + ).setDepth(depth + 1); - const summaryLines = [ - plan.deploymentLine, - `${plan.recommendationLine} · 공명 ${plan.activeBondCount}개 · ${plan.reserveTrainingFocusLabel}`, - plan.recruitedLine, - plan.objectiveLine - ]; - summaryLines.forEach((line, index) => { - this.trackSortie(this.add.text(x + 18, y + 142 + index * 15, this.compactText(line, 32), this.textStyle(12, index === 0 ? '#f2e3bf' : '#d4dce6', index === 0))).setDepth(depth + 1); + this.renderSortieFocusPanel(x + 18, y + 204, width - 36, 74, depth + 1); + } + + private renderSortieRoleSlots(x: number, y: number, width: number, height: number, plan: SortiePlanSummary, depth: number) { + const gap = 8; + const slotWidth = Math.floor((width - gap) / 2); + const slotHeight = Math.floor((height - 6) / 2); + plan.formationSlots.forEach((slot, index) => { + const column = index % 2; + const row = Math.floor(index / 2); + const slotX = x + column * (slotWidth + gap); + const slotY = y + row * (slotHeight + 6); + const filled = slot.unitNames.length > 0; + const bg = this.trackSortie(this.add.rectangle(slotX, slotY, slotWidth, slotHeight, filled ? 0x172a22 : 0x111922, filled ? 0.94 : 0.78)); + bg.setOrigin(0); + bg.setDepth(depth); + bg.setStrokeStyle(1, filled ? palette.green : 0x53606c, filled ? 0.58 : 0.34); + this.renderSortieBattleUiIcon(this.formationRoleIconKey(slot.role), slotX + 13, slotY + slotHeight / 2, 18, depth + 1, filled ? 0.95 : 0.5); + this.trackSortie(this.add.text(slotX + 28, slotY + 3, `${slot.label} ${slot.unitNames.length}`, this.textStyle(10, filled ? '#f2e3bf' : '#9fb0bf', true))).setDepth(depth + 1); + this.trackSortie(this.add.text(slotX + 76, slotY + 3, this.compactText(slot.unitNames.join(', ') || slot.description, 12), this.textStyle(10, filled ? '#c8d2dd' : '#68727e'))).setDepth(depth + 1); }); - - this.renderSortieFocusPanel(x + 18, y + 190, width - 36, 86, depth + 1); } private renderSortieFocusPanel(x: number, y: number, width: number, height: number, depth: number) { @@ -11459,7 +11540,6 @@ export class CampScene extends Phaser.Scene { } const status = this.unitRosterStatus(unit); - const summary = this.sortieUnitTacticalSummary(unit); const recommendation = this.sortieRecommendation(unit.id); const roleLabel = sortieFormationSlotDefinitions.find((slot) => slot.role === this.sortieFormationRole(unit))?.label ?? '예비'; const terrainScore = this.sortieTerrainScore(unit, this.nextSortieScenario()); @@ -11475,24 +11555,92 @@ export class CampScene extends Phaser.Scene { .join(' / '); const reason = recommendation?.reason ?? (this.isSortieSelected(unit.id) ? '현재 출전 편성에 포함되어 있습니다.' : '대기 훈련으로 성장시키거나 전장 역할에 맞춰 교체할 수 있습니다.'); - this.trackSortie(this.add.text(x + 12, y + 7, '선택 무장 분석', this.textStyle(11, '#d8b15f', true))).setDepth(depth + 1); - this.trackSortie(this.add.text(x + 104, y + 6, this.compactText(headline, 24), this.textStyle(13, '#f2e3bf', true))).setDepth(depth + 1); + this.renderSortieBattleUiIcon(this.unitClassIconKey(unit), x + 24, y + 25, 32, depth + 1, 0.98); + this.trackSortie(this.add.text(x + 48, y + 6, this.compactText(headline, 24), this.textStyle(13, '#f2e3bf', true))).setDepth(depth + 1); this.trackSortie(this.add.text(x + width - 12, y + 7, status.label, this.textStyle(11, statusColor, true))).setOrigin(1, 0).setDepth(depth + 1); - this.trackSortie(this.add.text(x + 12, y + 24, this.compactText(`${summary.statLine} · 지형 ${terrainGrade}(${terrainScore})`, 44), this.textStyle(10, '#c8d2dd'))).setDepth(depth + 1); - this.trackSortie(this.add.text(x + 12, y + 39, this.compactText(equipLine, 44), this.textStyle(10, '#c8d2dd'))).setDepth(depth + 1); - this.trackSortie(this.add.text(x + 12, y + 54, this.compactText(summary.bondLine, 44), this.textStyle(10, '#a8ffd0', true))).setDepth(depth + 1); - this.trackSortie(this.add.text(x + 12, y + height - 13, this.compactText(reason, 44), this.textStyle(10, recommendation ? '#ffdf7b' : '#9fb0bf', Boolean(recommendation)))).setDepth(depth + 1); + + this.renderSortieStatChip('might', '무', unit.stats.might, x + 48, y + 27, 50, depth + 1); + this.renderSortieStatChip('intelligence', '지', unit.stats.intelligence, x + 104, y + 27, 50, depth + 1); + this.renderSortieStatChip('leadership', '통', unit.stats.leadership, x + 160, y + 27, 50, depth + 1); + this.renderSortieStatChip('move', '이', unit.move, x + 216, y + 27, 50, depth + 1); + this.trackSortie(this.add.text(x + 274, y + 30, `지형 ${terrainGrade} ${terrainScore}`, this.textStyle(10, '#d8b15f', true))).setDepth(depth + 1); + + this.renderSortieEquipmentIcons(unit, x + 26, y + 52, true, depth + 1, 20, 16, 25); + this.trackSortie(this.add.text(x + 94, y + 47, this.compactText(equipLine, 38), this.textStyle(10, '#c8d2dd', true))).setDepth(depth + 1); + this.trackSortie( + this.add.text(x + 94, y + 61, this.compactText(reason, 28), this.textStyle(9, recommendation ? '#ffdf7b' : '#9fb0bf', Boolean(recommendation))) + ).setDepth(depth + 1); } - private renderSortieEquipmentIcons(unit: UnitData, x: number, y: number, selected: boolean, depth: number) { + private renderSortieBattleUiIcon(iconKey: BattleUiIconKey, x: number, y: number, size: number, depth: number, alpha = 1) { + if (!this.textures.exists(battleUiIconTextureKey)) { + const fallback = this.trackSortie(this.add.circle(x, y, size / 2, palette.gold, 0.18)); + fallback.setDepth(depth); + return; + } + + const icon = this.trackSortie(this.add.image(x, y, battleUiIconTextureKey, battleUiIconFrames[iconKey])); + icon.setDisplaySize(size, size); + icon.setAlpha(alpha); + icon.setDepth(depth); + } + + private unitClassIconKey(unit: UnitData): BattleUiIconKey { + switch (unit.classKey) { + case 'lord': + return 'leadership'; + case 'infantry': + return 'armor'; + case 'spearman': + return 'spear'; + case 'cavalry': + return 'horse'; + case 'archer': + return 'bow'; + case 'strategist': + return 'strategy'; + case 'quartermaster': + return 'heal'; + case 'rebelLeader': + return 'axe'; + case 'bandit': + case 'yellowTurban': + default: + return 'sword'; + } + } + + private formationRoleIconKey(role: SortieFormationRole): BattleUiIconKey { + if (role === 'front') { + return 'armor'; + } + if (role === 'flank') { + return 'horse'; + } + if (role === 'support') { + return 'strategy'; + } + return 'focus'; + } + + private renderSortieStatChip(iconKey: BattleUiIconKey, label: string, value: number, x: number, y: number, width: number, depth: number) { + const bg = this.trackSortie(this.add.rectangle(x, y, width, 17, 0x0a1017, 0.84)); + bg.setOrigin(0); + bg.setDepth(depth); + bg.setStrokeStyle(1, 0x53606c, 0.34); + this.renderSortieBattleUiIcon(iconKey, x + 9, y + 8, 14, depth + 1, 0.9); + this.trackSortie(this.add.text(x + 18, y + 3, `${label}${value}`, this.textStyle(9, '#f2e3bf', true))).setDepth(depth + 1); + } + + private renderSortieEquipmentIcons(unit: UnitData, x: number, y: number, selected: boolean, depth: number, frameSize = 18, iconSize = 14, spacing = 23) { equipmentSlots.forEach((slot, index) => { const state = unit.equipment[slot]; const item = getItem(state.itemId); - const iconFrame = this.trackSortie(this.add.rectangle(x + index * 23, y, 18, 18, selected && item.rank === 'treasure' ? 0x2c2630 : 0x0a1017, 0.92)); + const iconFrame = this.trackSortie(this.add.rectangle(x + index * spacing, y, frameSize, frameSize, selected && item.rank === 'treasure' ? 0x2c2630 : 0x0a1017, 0.92)); iconFrame.setStrokeStyle(1, item.rank === 'treasure' ? palette.gold : 0x53606c, selected ? 0.62 : 0.34); iconFrame.setDepth(depth); - const icon = this.trackSortie(this.add.image(x + index * 23, y, `item-${item.id}`)); - icon.setDisplaySize(14, 14); + const icon = this.trackSortie(this.add.image(x + index * spacing, y, `item-${item.id}`)); + icon.setDisplaySize(iconSize, iconSize); icon.setAlpha(selected ? 1 : 0.52); icon.setDepth(depth + 1); }); @@ -11903,11 +12051,14 @@ export class CampScene extends Phaser.Scene { const focus = this.reserveTrainingFocusDefinition(); const reserveCount = this.sortiePlanSummary().reserveCount; this.trackSortie(this.add.text(x + 12, y + 7, '대기 훈련', this.textStyle(12, '#f2e3bf', true))).setDepth(depth + 1); + const focusPreview = reserveCount > 0 + ? `경험 +${focus.expGained} · 장비 +${focus.equipmentExpGained}${focus.bondExpGained ? ` · 공명 +${focus.bondExpGained}` : ''}` + : '대기 없음'; this.trackSortie( this.add.text( x + width - 12, y + 7, - reserveCount > 0 ? `${reserveCount}명 · ${focus.label}` : '대기 없음', + reserveCount > 0 ? `${reserveCount}명 · ${focusPreview}` : focusPreview, this.textStyle(11, reserveCount > 0 ? '#d8b15f' : '#9fb0bf', true) ) ).setOrigin(1, 0).setDepth(depth + 1); @@ -11916,14 +12067,15 @@ export class CampScene extends Phaser.Scene { campaignReserveTrainingFocusDefinitions.forEach((option, index) => { const buttonX = x + 12 + index * (buttonWidth + 8); const selected = option.id === focus.id; - const button = this.trackSortie(this.add.rectangle(buttonX, y + 30, buttonWidth, 16, selected ? 0x263a2d : 0x0e151d, selected ? 0.98 : 0.86)); + const button = this.trackSortie(this.add.rectangle(buttonX, y + 28, buttonWidth, 20, selected ? 0x263a2d : 0x0e151d, selected ? 0.98 : 0.86)); button.setOrigin(0); button.setDepth(depth + 1); button.setStrokeStyle(1, selected ? palette.green : 0x53606c, selected ? 0.78 : 0.42); button.setInteractive({ useHandCursor: true }); button.on('pointerdown', () => this.setReserveTrainingFocus(option.id)); - const label = this.trackSortie(this.add.text(buttonX + buttonWidth / 2, y + 33, option.label, this.textStyle(10, selected ? '#a8ffd0' : '#c8d2dd', true))); + const optionText = `${option.label} ${option.expGained}/${option.equipmentExpGained}${option.bondExpGained ? `/${option.bondExpGained}` : ''}`; + const label = this.trackSortie(this.add.text(buttonX + buttonWidth / 2, y + 33, this.compactText(optionText, 10), this.textStyle(9, selected ? '#a8ffd0' : '#c8d2dd', true))); label.setOrigin(0.5, 0); label.setDepth(depth + 2); label.setInteractive({ useHandCursor: true });