From 302d0e5f2de67784b4b7c45f968ea3a730a543e2 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Fri, 3 Jul 2026 04:25:46 +0900 Subject: [PATCH] Improve battle status effect visibility --- src/game/scenes/BattleScene.ts | 384 ++++++++++++++++++++++----------- 1 file changed, 262 insertions(+), 122 deletions(-) diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index 6352fe8..0337aa6 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -1398,6 +1398,14 @@ type UnitEffectSummary = { label: string; value: string; tone: number; + turns?: number; +}; + +type PreviewModifierSummary = { + icon: BattleUiIconKey; + label: string; + value: string; + tone: number; }; type SavedUnitState = Pick & { @@ -5691,67 +5699,101 @@ export class BattleScene extends Phaser.Scene { return parts.join(' / ') || '보정 없음'; } - private battleBuffBonusText(buff: BattleBuffState) { + private battleBuffShortText(buff: BattleBuffState) { const parts = [ - buff.attackBonus > 0 ? `공격 +${buff.attackBonus}` : '', - buff.hitBonus > 0 ? `명중 +${buff.hitBonus}` : '', - buff.criticalBonus > 0 ? `치명 +${buff.criticalBonus}` : '' + buff.attackBonus > 0 ? `공+${buff.attackBonus}` : '', + buff.hitBonus > 0 ? `명+${buff.hitBonus}` : '', + buff.criticalBonus > 0 ? `치+${buff.criticalBonus}` : '' ].filter(Boolean); - return `${parts.join(' / ') || '효과 유지'} · ${buff.turns}턴`; + return `${parts.join(' ') || '유지'} · ${buff.turns}턴`; } - private previewModifierLabels(preview: CombatPreview) { - const labels: string[] = []; + private previewModifierSummaries(preview: CombatPreview): PreviewModifierSummary[] { + const summaries: PreviewModifierSummary[] = []; const buff = this.battleBuffs.get(preview.attacker.id); - const equipmentBonusCount = [ - preview.equipmentDamageBonus, - preview.equipmentDamageReduction, - preview.equipmentHitBonus, - preview.equipmentCriticalBonus - ].filter((bonus) => bonus > 0).length; + const equipmentText = this.equipmentPreviewBonusText(preview); + const terrainParts = [ + preview.terrainDefenseBonus > 0 ? `방+${preview.terrainDefenseBonus}` : '', + preview.terrainHitPenalty > 0 ? `명-${preview.terrainHitPenalty}` : '' + ].filter(Boolean); if (buff) { - labels.push(`${buff.label} ${this.battleBuffBonusText(buff)}`); + summaries.push({ + icon: 'focus', + label: buff.label, + value: this.battleBuffShortText(buff), + tone: palette.gold + }); } if (preview.bondDamageBonus > 0 && preview.bondLabel) { - labels.push(`공명 피해 +${preview.bondDamageBonus}%`); + summaries.push({ + icon: 'leadership', + label: '공명', + value: `피해 +${preview.bondDamageBonus}%`, + tone: 0x83d6ff + }); } - if (equipmentBonusCount > 0) { - labels.push(`장비 보정 ${equipmentBonusCount}개`); + if (equipmentText !== '보정 없음') { + summaries.push({ + icon: 'mastery', + label: '장비', + value: equipmentText, + tone: 0xd8b15f + }); } - if (preview.terrainDefenseBonus > 0) { - labels.push(`${preview.terrainLabel} 방어 +${preview.terrainDefenseBonus}`); - } - if (preview.terrainHitPenalty > 0) { - labels.push(`지형 명중 -${preview.terrainHitPenalty}`); + if (terrainParts.length > 0) { + summaries.push({ + icon: 'terrain', + label: preview.terrainLabel, + value: terrainParts.join(' / '), + tone: 0x59d18c + }); } - return labels.length > 0 ? labels : ['추가 보정 없음']; + return summaries; } - private supportPreviewModifierLabels(preview: SupportPreview) { + private supportPreviewModifierSummaries(preview: SupportPreview): PreviewModifierSummary[] { if (preview.usable.effect === 'heal') { const baseBonus = preview.healAmount - preview.usable.power; return [ - `${this.usableChannelLabel(preview.usable)} 회복 ${preview.healAmount}`, - baseBonus > 0 ? `능력/장비 +${baseBonus}` : '추가 보정 없음' + { + icon: this.usablePowerIcon(preview.usable), + label: this.usableChannelLabel(preview.usable), + value: `회복 +${preview.healAmount}`, + tone: 0x59d18c + }, + { + icon: preview.usable.command === 'strategy' ? 'intelligence' : 'accessory', + label: baseBonus > 0 ? '보정' : '기본', + value: baseBonus > 0 ? `+${baseBonus}` : '추가 없음', + tone: baseBonus > 0 ? palette.gold : 0x647485 + } ]; } return [ - `공격 +${preview.attackBonus}`, - `명중 +${preview.hitBonus}`, - `치명 +${preview.criticalBonus}`, - `${preview.duration}턴 유지` + { + icon: 'focus', + label: preview.usable.name, + value: `공+${preview.attackBonus} 명+${preview.hitBonus}`, + tone: palette.gold + }, + { + icon: 'critical', + label: '치명', + value: `+${preview.criticalBonus}`, + tone: 0xd8732c + }, + { + icon: 'leadership', + label: '지속', + value: `${preview.duration}턴`, + tone: 0x83d6ff + } ]; } - private compactModifierText(labels: string[], limit = 2, maxLength = 34) { - const text = labels.slice(0, limit).join(' · '); - const suffix = labels.length > limit ? ` · 외 ${labels.length - limit}` : ''; - return this.truncateUiText(`${text}${suffix}`, maxLength); - } - private truncateUiText(text: string, maxLength: number) { return text.length > maxLength ? `${text.slice(0, Math.max(0, maxLength - 3))}...` : text; } @@ -5798,7 +5840,7 @@ export class BattleScene extends Phaser.Scene { const { panelX, panelWidth } = this.layout; const left = panelX + 24; const width = panelWidth - 48; - const height = locked ? 396 : 360; + const height = locked ? 438 : 402; const y = Math.max(this.sideContentTop(), Math.min(this.sideContentTop() + 328, this.sideContentBottom(10) - height)); const accent = this.previewAccentColor(preview); const defenderClass = getUnitClass(preview.defender.classKey); @@ -5809,7 +5851,7 @@ export class BattleScene extends Phaser.Scene { const sourceLabel = preview.usable ? this.usableChannelLabel(preview.usable) : attackerEquipmentLabel; const sourceName = preview.usable?.name ?? attackerWeapon.name; - const bg = this.trackSideObject(this.add.rectangle(left, y, width, height, 0x121a22, 0.98)); + const bg = this.trackSideObject(this.add.rectangle(left, y, width, height, 0x121a22, 1)); bg.setOrigin(0); bg.setStrokeStyle(2, accent, 0.78); @@ -5859,16 +5901,9 @@ export class BattleScene extends Phaser.Scene { ); this.renderPreviewForecastRow(preview, left + 10, y + 264, width - 20, accent); - this.renderPreviewModifierStrip( - left + 10, - y + 300, - width - 20, - 'mastery', - this.compactModifierText(this.previewModifierLabels(preview), 2, 36), - accent - ); + this.renderPreviewModifierCards(left + 10, y + 300, width - 20, this.previewModifierSummaries(preview), accent); - const badgeY = y + 328; + const badgeY = y + 370; const maxBadgeRight = left + width - 10; let badgeX = left + 10; badgeX = this.renderPreviewBadge(badgeX, badgeY, this.actionIcon(preview), this.previewActionTypeLabel(preview), maxBadgeRight); @@ -5881,7 +5916,7 @@ export class BattleScene extends Phaser.Scene { this.renderPreviewBadge(detailBadgeX, badgeY, 'mastery', '장비 보정', maxBadgeRight); } if (locked) { - this.renderPreviewConfirmBar(left + 10, y + 360, width - 20, accent, `${preview.defender.name} 선택됨`); + this.renderPreviewConfirmBar(left + 10, y + 402, width - 20, accent, `${preview.defender.name} 선택됨`); } } @@ -5889,11 +5924,11 @@ export class BattleScene extends Phaser.Scene { const { panelX, panelWidth } = this.layout; const left = panelX + 24; const width = panelWidth - 48; - const height = locked ? 394 : 360; + const height = locked ? 438 : 402; const y = Math.max(this.sideContentTop(), Math.min(this.sideContentTop() + 344, this.sideContentBottom(10) - height)); const accent = this.usableAccentColor(preview.usable); - const bg = this.trackSideObject(this.add.rectangle(left, y, width, height, 0x121a22, 0.98)); + const bg = this.trackSideObject(this.add.rectangle(left, y, width, height, 0x121a22, 1)); bg.setOrigin(0); bg.setStrokeStyle(2, accent, 0.78); @@ -5966,16 +6001,9 @@ export class BattleScene extends Phaser.Scene { } this.renderSupportForecastRow(preview, left + 10, y + 264, width - 20, accent); - this.renderPreviewModifierStrip( - left + 10, - y + 300, - width - 20, - preview.usable.effect === 'heal' ? this.usablePowerIcon(preview.usable) : 'leadership', - this.compactModifierText(this.supportPreviewModifierLabels(preview)), - accent - ); + this.renderPreviewModifierCards(left + 10, y + 300, width - 20, this.supportPreviewModifierSummaries(preview), accent); - const badgeY = y + 328; + const badgeY = y + 370; const maxBadgeRight = left + width - 10; let badgeX = left + 10; badgeX = this.renderPreviewBadge(badgeX, badgeY, this.usableIcon(preview.usable), this.usableEffectLabel(preview.usable), maxBadgeRight); @@ -5985,7 +6013,72 @@ export class BattleScene extends Phaser.Scene { this.renderPreviewBadge(detailBadgeX, badgeY, 'leadership', `${preview.duration}턴`, maxBadgeRight); } if (locked) { - this.renderPreviewConfirmBar(left + 10, y + 360, width - 20, accent, `${preview.target.name} 선택됨`); + this.renderPreviewConfirmBar(left + 10, y + 402, width - 20, accent, `${preview.target.name} 선택됨`); + } + } + + private renderPreviewModifierCards( + x: number, + y: number, + width: number, + summaries: PreviewModifierSummary[], + accent: number + ) { + const visible = summaries.slice(0, 3); + if (visible.length === 0) { + const row = this.trackSideObject(this.add.rectangle(x, y, width, 58, 0x0b1118, 0.94)); + row.setOrigin(0); + row.setStrokeStyle(1, accent, 0.44); + this.trackSideIcon(x + 24, y + 29, 'success', 34); + this.trackSideObject(this.add.text(x + 50, y + 10, '보정 출처', { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '12px', + color: '#9fb0bf', + fontStyle: '700' + })); + this.trackSideObject(this.add.text(x + 50, y + 30, '추가 보정 없음', { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '14px', + color: '#d4dce6', + fontStyle: '700' + })); + return; + } + + const gap = 6; + const cardWidth = (width - gap * 2) / 3; + visible.forEach((summary, index) => { + const cardX = x + index * (cardWidth + gap); + const card = this.trackSideObject(this.add.rectangle(cardX, y, cardWidth, 58, 0x0b1118, 0.96)); + card.setOrigin(0); + card.setStrokeStyle(1, summary.tone, 0.62); + const iconFrame = this.trackSideObject(this.add.rectangle(cardX + 21, y + 29, 38, 38, 0x16212d, 0.92)); + iconFrame.setStrokeStyle(1, summary.tone, 0.5); + this.trackSideIcon(cardX + 21, y + 29, summary.icon, 34); + this.trackSideObject(this.add.text(cardX + 44, y + 7, summary.label, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '10px', + color: '#9fb0bf', + fontStyle: '700', + fixedWidth: cardWidth - 52 + })); + this.trackSideObject(this.add.text(cardX + 44, y + 24, this.truncateUiText(summary.value, 14), { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '12px', + color: '#f2e3bf', + fontStyle: '700', + fixedWidth: cardWidth - 52 + })); + }); + + if (summaries.length > visible.length) { + const extraText = this.trackSideObject(this.add.text(x + width - 8, y + 4, `+${summaries.length - visible.length}`, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '11px', + color: '#f4dfad', + fontStyle: '700' + })); + extraText.setOrigin(1, 0); } } @@ -6239,26 +6332,6 @@ export class BattleScene extends Phaser.Scene { buffText.setOrigin(1, 0); } - private renderPreviewModifierStrip(x: number, y: number, width: number, icon: BattleUiIconKey, text: string, accent: number) { - const row = this.trackSideObject(this.add.rectangle(x, y, width, 24, 0x101820, 0.96)); - row.setOrigin(0); - row.setStrokeStyle(1, accent, 0.42); - this.trackSideIcon(x + 15, y + 12, icon, 20); - this.trackSideObject(this.add.text(x + 32, y + 6, '보정', { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '11px', - color: '#9fb0bf', - fontStyle: '700' - })); - this.trackSideObject(this.add.text(x + 68, y + 5, text, { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '12px', - color: text === '추가 보정 없음' ? '#aeb7c2' : '#f2e3bf', - fontStyle: '700', - fixedWidth: width - 76 - })); - } - private renderPreviewBadge(x: number, y: number, icon: BattleUiIconKey, label: string, maxRight?: number) { const width = Phaser.Math.Clamp(label.length * 7 + 48, 76, 146); if (maxRight && x + width > maxRight) { @@ -10822,7 +10895,7 @@ export class BattleScene extends Phaser.Scene { } this.turnNumber += 1; - this.tickBattleBuffs(); + const expiredBuffMessage = this.tickBattleBuffs(); this.activeFaction = 'ally'; this.fastForwardHeld = false; this.actedUnitIds.clear(); @@ -10834,13 +10907,16 @@ export class BattleScene extends Phaser.Scene { this.updateObjectiveTracker(); this.checkBattleEvents(); this.centerCameraOnAllyLine(); - const turnMessage = [`${this.turnNumber}턴 아군 차례입니다.`, recoveryMessage, '행동할 장수를 선택하세요.'].filter(Boolean).join('\n'); + const turnMessage = [`${this.turnNumber}턴 아군 차례입니다.`, expiredBuffMessage, recoveryMessage, '행동할 장수를 선택하세요.'].filter(Boolean).join('\n'); this.renderRosterPanel('ally', turnMessage); const firstUnit = this.firstActionableAlly(); if (firstUnit) { - this.renderSituationPanel(`${this.turnNumber}턴 아군 차례입니다.\n다음 행동: ${firstUnit.name}`); - this.focusActionableAlly(firstUnit, [`${this.turnNumber}턴 아군 차례입니다.`, recoveryMessage, '이동할 파란 칸을 선택하세요.'].filter(Boolean).join('\n')); + this.renderSituationPanel([`${this.turnNumber}턴 아군 차례입니다.`, expiredBuffMessage, recoveryMessage, `다음 행동: ${firstUnit.name}`].filter(Boolean).join('\n')); + this.focusActionableAlly( + firstUnit, + [`${this.turnNumber}턴 아군 차례입니다.`, expiredBuffMessage, recoveryMessage, '이동할 파란 칸을 선택하세요.'].filter(Boolean).join('\n') + ); } } @@ -11326,12 +11402,22 @@ export class BattleScene extends Phaser.Scene { } private tickBattleBuffs() { + const expired: string[] = []; this.battleBuffs.forEach((buff, unitId) => { buff.turns -= 1; if (buff.turns <= 0) { this.battleBuffs.delete(unitId); + expired.push(`${this.unitName(unitId)} ${buff.label}`); } }); + + if (expired.length === 0) { + return undefined; + } + + const message = `상태효과 만료\n${expired.slice(0, 3).join('\n')}${expired.length > 3 ? `\n외 ${expired.length - 3}명` : ''}`; + this.pushBattleLog(message); + return message; } private cancelAttackTargeting() { @@ -12629,19 +12715,21 @@ export class BattleScene extends Phaser.Scene { `${this.directionSymbol(direction)} ${this.unitDirectionLabel(direction)}` ); - const statTop = top + 164; + const effects = this.unitEffectSummaries(unit); + const hasEffects = effects.length > 0; + const statTop = top + (hasEffects ? 154 : 164); + const statGap = hasEffects ? 21 : 24; statLabels.forEach((stat, index) => { - this.renderStatRow(stat.key, stat.label, unit.stats[stat.key], left, statTop + index * 24, width); + this.renderStatRow(stat.key, stat.label, unit.stats[stat.key], left, statTop + index * statGap, width); }); - const effects = this.unitEffectSummaries(unit); - const effectText = effects.length > 0 ? ` / 효과 ${this.compactUnitEffectText(effects)}` : ''; - const positionText = `위치 ${unit.x + 1}, ${unit.y + 1} · ${terrainRule.label} ${terrainRating}% · 이동 ${unit.move}${acted ? ' · 행동완료' : ''}${effectText}`; - const statusPanel = this.trackSideObject(this.add.rectangle(left, top + 288, width, 32, 0x101820, 0.9)); + const positionText = `위치 ${unit.x + 1}, ${unit.y + 1} · ${terrainRule.label} ${terrainRating}% · 이동 ${unit.move}${acted ? ' · 행동완료' : ''}`; + const statusTop = top + (hasEffects ? 264 : 288); + const statusPanel = this.trackSideObject(this.add.rectangle(left, statusTop, width, 32, 0x101820, 0.9)); statusPanel.setOrigin(0); statusPanel.setStrokeStyle(1, 0x40515e, 0.5); - this.trackSideIcon(left + 17, top + 304, effects[0]?.icon ?? (acted ? 'counter' : this.unitMoveIcon(unit)), 25); - this.trackSideObject(this.add.text(left + 36, top + 294, positionText, { + this.trackSideIcon(left + 17, statusTop + 16, acted ? 'counter' : this.unitMoveIcon(unit), 25); + this.trackSideObject(this.add.text(left + 36, statusTop + 6, positionText, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '12px', color: acted ? '#bdbdbd' : '#9fb0bf', @@ -12649,8 +12737,12 @@ export class BattleScene extends Phaser.Scene { lineSpacing: 2 })); - const equipmentTop = top + 326; - this.renderEquipmentSummary(unit, left, equipmentTop, width); + const effectTop = top + (hasEffects ? 302 : 326); + const equipmentTop = hasEffects ? top + 350 : effectTop; + if (hasEffects) { + this.renderUnitEffectCards(effects, left, effectTop, width); + } + this.renderEquipmentSummary(unit, left, equipmentTop, width, hasEffects); if (message) { this.renderPanelMessage(message, left, equipmentTop + 156, width, 42); } @@ -12668,10 +12760,11 @@ export class BattleScene extends Phaser.Scene { if (buff) { effects.push({ - icon: 'leadership', + icon: 'focus', label: buff.label, - value: this.battleBuffBonusText(buff), - tone: palette.gold + value: this.battleBuffShortText(buff), + tone: palette.gold, + turns: buff.turns }); } if (turnStartParts.length > 0) { @@ -12686,80 +12779,127 @@ export class BattleScene extends Phaser.Scene { return effects; } - private compactUnitEffectText(effects: UnitEffectSummary[]) { - return this.compactModifierText( - effects.map((effect) => `${effect.label}: ${effect.value}`), - 2 - ); + private renderUnitEffectCards(effects: UnitEffectSummary[], x: number, y: number, width: number) { + const visible = effects.slice(0, 2); + const gap = 6; + const cardWidth = (width - gap) / 2; + visible.forEach((effect, index) => { + const cardX = x + index * (cardWidth + gap); + const bg = this.trackSideObject(this.add.rectangle(cardX, y, cardWidth, 42, 0x101820, 0.97)); + bg.setOrigin(0); + bg.setStrokeStyle(1, effect.tone, 0.62); + const iconFrame = this.trackSideObject(this.add.rectangle(cardX + 20, y + 21, 32, 32, 0x0a0f14, 0.92)); + iconFrame.setStrokeStyle(1, effect.tone, 0.56); + this.trackSideIcon(cardX + 20, y + 21, effect.icon, 30); + this.trackSideObject(this.add.text(cardX + 42, y + 4, effect.label, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '10px', + color: '#9fb0bf', + fontStyle: '700', + fixedWidth: cardWidth - 52 + })); + this.trackSideObject(this.add.text(cardX + 42, y + 20, this.truncateUiText(effect.value, 15), { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '12px', + color: '#f2e3bf', + fontStyle: '700', + fixedWidth: cardWidth - 52 + })); + + if (effect.turns) { + const badge = this.trackSideObject(this.add.rectangle(cardX + cardWidth - 18, y + 14, 26, 18, 0x211624, 0.96)); + badge.setStrokeStyle(1, effect.tone, 0.78); + const turnText = this.trackSideObject(this.add.text(cardX + cardWidth - 18, y + 14, `${effect.turns}`, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '11px', + color: '#fff2b8', + fontStyle: '700' + })); + turnText.setOrigin(0.5); + } + }); + + if (effects.length > visible.length) { + const extraText = this.trackSideObject(this.add.text(x + width - 8, y + 4, `+${effects.length - visible.length}`, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '11px', + color: '#f4dfad', + fontStyle: '700' + })); + extraText.setOrigin(1, 0); + } } - private renderEquipmentSummary(unit: UnitData, x: number, y: number, width: number) { - this.trackSideIcon(x + 15, y + 12, 'mastery', 30); + private renderEquipmentSummary(unit: UnitData, x: number, y: number, width: number, compact = false) { + this.trackSideIcon(x + 15, y + 12, 'mastery', compact ? 25 : 30); this.trackSideObject(this.add.text(x + 32, y, '장비 / 숙련도', { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '17px', + fontSize: compact ? '14px' : '17px', color: '#f2e3bf', fontStyle: '700' })); equipmentSlots.forEach((slot, index) => { - this.renderEquipmentRow(unit, slot, x, y + 28 + index * 40, width); + const rowTop = y + (compact ? 20 : 28) + index * (compact ? 30 : 40); + this.renderEquipmentRow(unit, slot, x, rowTop, width, compact); }); } - private renderEquipmentRow(unit: UnitData, slot: EquipmentSlot, x: number, y: number, width: number) { + private renderEquipmentRow(unit: UnitData, slot: EquipmentSlot, x: number, y: number, width: number, compact = false) { const state = unit.equipment[slot]; const item = getItem(state.itemId); const next = equipmentExpToNext(state.level); const isTreasure = item.rank === 'treasure'; - const bg = this.trackSideObject(this.add.rectangle(x, y, width, 38, isTreasure ? 0x1f2430 : 0x101820, isTreasure ? 0.98 : 0.95)); + const rowHeight = compact ? 28 : 38; + const bg = this.trackSideObject(this.add.rectangle(x, y, width, rowHeight, isTreasure ? 0x1f2430 : 0x101820, isTreasure ? 0.98 : 0.95)); bg.setOrigin(0); bg.setStrokeStyle(1, isTreasure ? palette.gold : 0x53606c, isTreasure ? 0.66 : 0.5); - const iconFrame = this.trackSideObject(this.add.rectangle(x + 23, y + 19, 36, 36, 0x0a0f14, 0.92)); + const iconSize = compact ? 26 : 36; + const iconFrame = this.trackSideObject(this.add.rectangle(x + (compact ? 19 : 21), y + rowHeight / 2, iconSize, iconSize, 0x0a0f14, 0.92)); iconFrame.setStrokeStyle(1, isTreasure ? palette.gold : 0x53606c, isTreasure ? 0.78 : 0.54); - this.trackSideIcon(x + 23, y + 19, this.itemIcon(item, slot), 34); + this.trackSideIcon(x + (compact ? 19 : 21), y + rowHeight / 2, this.itemIcon(item, slot), compact ? 24 : 34); - this.trackSideObject(this.add.text(x + 48, y + 3, equipmentSlotLabels[slot], { + this.trackSideObject(this.add.text(x + 40, y + (compact ? 1 : 3), equipmentSlotLabels[slot], { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '11px', + fontSize: compact ? '10px' : '11px', color: '#9fb0bf', fontStyle: '700' })); const bonusText = this.itemBonusText(item); - this.trackSideObject(this.add.text(x + 86, y + 3, bonusText, { + this.trackSideObject(this.add.text(x + 78, y + (compact ? 1 : 3), bonusText, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '11px', + fontSize: compact ? '10px' : '11px', color: '#aeb7c2', fixedWidth: width - 170 })); - this.trackSideObject(this.add.text(x + 48, y + 17, item.name, { + this.trackSideObject(this.add.text(x + 40, y + (compact ? 12 : 17), item.name, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '15px', + fontSize: compact ? '12px' : '15px', color: isTreasure ? '#f4dfad' : '#d4dce6', fontStyle: '700', fixedWidth: width - 150 })); - const levelText = this.trackSideObject(this.add.text(x + width - 10, y + 5, `Lv ${state.level}`, { + const levelText = this.trackSideObject(this.add.text(x + width - 10, y + (compact ? 2 : 5), `Lv ${state.level}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '15px', + fontSize: compact ? '12px' : '15px', color: isTreasure ? '#f2e3bf' : '#d4dce6', fontStyle: '700' })); levelText.setOrigin(1, 0); - this.trackSideIcon(x + width - 76, y + 27, 'mastery', 20); - const expText = this.trackSideObject(this.add.text(x + width - 10, y + 24, `${state.exp}/${next}`, { + this.trackSideIcon(x + width - 76, y + (compact ? 20 : 27), 'mastery', compact ? 16 : 20); + const expText = this.trackSideObject(this.add.text(x + width - 10, y + (compact ? 17 : 24), `${state.exp}/${next}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '11px', + fontSize: compact ? '10px' : '11px', color: '#c8d2dd', fontStyle: '700' })); expText.setOrigin(1, 0); - this.drawGauge(x + 48, y + 32, width - 132, 5, state.exp / next, isTreasure ? 0xd8b15f : 0x58aee0); + this.drawGauge(x + 40, y + (compact ? 24 : 32), width - 124, compact ? 4 : 5, state.exp / next, isTreasure ? 0xd8b15f : 0x58aee0); } private createBattleUiIcon(x: number, y: number, icon: BattleUiIconKey, size = 22) {