diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index 48fe11f..d03efcb 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -12416,99 +12416,119 @@ export class BattleScene extends Phaser.Scene { const terrainRating = unitClass.terrainRatings[terrain]; const direction = this.currentUnitDirection(unit); - const header = this.trackSideObject(this.add.rectangle(left, top, width, 60, 0x101820, 0.94)); + const header = this.trackSideObject(this.add.rectangle(left, top, width, 64, 0x101820, 0.96)); header.setOrigin(0); header.setStrokeStyle(1, factionColor, 0.76); - const classIcon = this.trackSideIcon(left + 26, top + 31, this.unitMoveIcon(unit), 38); + const classIcon = this.trackSideIcon(left + 28, top + 32, this.unitMoveIcon(unit), 42); classIcon.setAlpha(acted ? 0.86 : 0.96); const headerTextX = left + 58; - this.trackSideObject(this.add.text(headerTextX, top + 9, `${rosterLabels[unit.faction]} / ${unitClass.family}`, { + this.trackSideObject(this.add.text(headerTextX, top + 7, `${rosterLabels[unit.faction]} / ${unitClass.family}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '14px', + fontSize: '13px', color: unit.faction === 'ally' ? '#9fd0ff' : '#ffb2a4', fontStyle: '700' })); - this.trackSideObject(this.add.text(headerTextX, top + 29, `${unit.name} ${unitClass.name}`, { + this.trackSideObject(this.add.text(headerTextX, top + 27, `${unit.name} ${unitClass.name}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '22px', + fontSize: '21px', color: acted ? '#bdbdbd' : '#f2e3bf', - fontStyle: '700' + fontStyle: '700', + fixedWidth: width - 154 })); - const growthText = this.trackSideObject(this.add.text(left + width - 14, top + 42, `Lv ${unit.level} EXP ${unit.exp}/100`, { + + const levelBadge = this.trackSideObject(this.add.rectangle(left + width - 84, top + 8, 70, 26, 0x1b2834, 0.94)); + levelBadge.setOrigin(0); + levelBadge.setStrokeStyle(1, factionColor, 0.6); + const levelText = this.trackSideObject(this.add.text(left + width - 49, top + 21, `Lv ${unit.level}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '13px', + fontSize: '16px', color: acted ? '#d8cfb5' : '#f4dfad', fontStyle: '700' })); - growthText.setOrigin(1, 0); + levelText.setOrigin(0.5); if (this.phase !== 'command') { - const backBg = this.trackSideObject(this.add.rectangle(left + width - 66, top + 10, 52, 28, 0x1b2834, 0.9)); + const backBg = this.trackSideObject(this.add.rectangle(left + width - 72, top + 38, 58, 22, 0x223142, 0.95)); backBg.setOrigin(0); backBg.setStrokeStyle(1, palette.gold, 0.72); backBg.setInteractive({ useHandCursor: true }); backBg.on('pointerdown', () => this.returnToRosterPanel(unit.faction)); - const backText = this.trackSideObject(this.add.text(left + width - 40, top + 24, '목록', { + const backText = this.trackSideObject(this.add.text(left + width - 43, top + 49, '목록', { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '14px', + fontSize: '13px', color: '#f4dfad', fontStyle: '700' })); backText.setOrigin(0.5); + } else { + const actionText = this.trackSideObject(this.add.text(left + width - 49, top + 48, acted ? '행동완료' : `EXP ${unit.exp}/100`, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '12px', + color: acted ? '#bdbdbd' : '#c8d2dd', + fontStyle: '700' + })); + actionText.setOrigin(0.5); } - this.trackSideIcon(left + 13, top + 88, 'hp', 26); - this.trackSideObject(this.add.text(left + 26, top + 78, '병력', { + const hpPanel = this.trackSideObject(this.add.rectangle(left, top + 72, width, 34, 0x101820, 0.92)); + hpPanel.setOrigin(0); + hpPanel.setStrokeStyle(1, 0x40515e, 0.58); + this.trackSideIcon(left + 18, top + 89, 'hp', 29); + this.trackSideObject(this.add.text(left + 40, top + 79, '병력', { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '17px', color: '#d4dce6', fontStyle: '700' })); - const hpValue = this.trackSideObject(this.add.text(left + width, top + 76, `${unit.hp} / ${unit.maxHp}`, { + const hpValue = this.trackSideObject(this.add.text(left + width - 12, top + 79, `${unit.hp} / ${unit.maxHp}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '18px', color: '#f0e4c8', fontStyle: '700' })); hpValue.setOrigin(1, 0); - this.drawGauge(left + 102, top + 84, width - 186, 10, unit.hp / unit.maxHp, 0x59d18c); + this.drawGauge(left + 104, top + 93, width - 168, 10, unit.hp / unit.maxHp, 0x59d18c); const attackBonus = this.equipmentAttackBonus(unit); const summaryGap = 6; const summaryBoxWidth = (width - summaryGap * 2) / 3; - this.renderCompactValueBox(left, top + 112, summaryBoxWidth, 'attack', '공격', `${unit.attack + attackBonus}`); - this.renderCompactValueBox(left + summaryBoxWidth + summaryGap, top + 112, summaryBoxWidth, 'defense', '방어+', `${this.equipmentDefenseBonus(unit)}`); + this.renderCompactValueBox(left, top + 114, summaryBoxWidth, 'attack', '공격', `${unit.attack + attackBonus}`); + this.renderCompactValueBox(left + summaryBoxWidth + summaryGap, top + 114, summaryBoxWidth, 'defense', '방어+', `${this.equipmentDefenseBonus(unit)}`); this.renderCompactValueBox( left + (summaryBoxWidth + summaryGap) * 2, - top + 112, + top + 114, summaryBoxWidth, this.unitMoveIcon(unit), '방향', `${this.directionSymbol(direction)} ${this.unitDirectionLabel(direction)}` ); - const statTop = top + 158; + const statTop = top + 164; statLabels.forEach((stat, index) => { - this.renderStatRow(stat.key, stat.label, unit.stats[stat.key], left, statTop + index * 28, width); + this.renderStatRow(stat.key, stat.label, unit.stats[stat.key], left, statTop + index * 24, width); }); const effects = this.unitEffectSummaries(unit); - const effectText = effects.length > 0 ? `\n효과 ${this.compactUnitEffectText(effects)}` : ''; - const positionText = `위치 ${unit.x + 1}, ${unit.y + 1} / ${terrainRule.label} ${terrainRating}% / 이동 ${unit.move}${acted ? ' / 행동완료' : ''}${effectText}`; - this.trackSideIcon(left + 13, top + 294, effects[0]?.icon ?? (acted ? 'counter' : this.unitMoveIcon(unit)), 24); - this.trackSideObject(this.add.text(left + 28, effects.length > 0 ? top + 280 : top + 285, positionText, { + 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)); + 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, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '14px', + fontSize: '12px', color: acted ? '#bdbdbd' : '#9fb0bf', - wordWrap: { width: width - 24, useAdvancedWrap: true } + wordWrap: { width: width - 48, useAdvancedWrap: true }, + lineSpacing: 2 })); - const equipmentTop = effects.length > 0 ? top + 318 : top + 302; + const equipmentTop = top + 326; this.renderEquipmentSummary(unit, left, equipmentTop, width); if (message) { - this.renderPanelMessage(message, left, equipmentTop + 154, width, 40); + this.renderPanelMessage(message, left, equipmentTop + 156, width, 42); } this.showFacingIndicator(unit); } @@ -12551,7 +12571,7 @@ export class BattleScene extends Phaser.Scene { private renderEquipmentSummary(unit: UnitData, x: number, y: number, width: number) { this.trackSideIcon(x + 15, y + 12, 'mastery', 30); - this.trackSideObject(this.add.text(x + 31, y, '장비 / 숙련도', { + this.trackSideObject(this.add.text(x + 32, y, '장비 / 숙련도', { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '17px', color: '#f2e3bf', @@ -12559,7 +12579,7 @@ export class BattleScene extends Phaser.Scene { })); equipmentSlots.forEach((slot, index) => { - this.renderEquipmentRow(unit, slot, x, y + 26 + index * 42, width); + this.renderEquipmentRow(unit, slot, x, y + 28 + index * 40, width); }); } @@ -12568,47 +12588,37 @@ export class BattleScene extends Phaser.Scene { 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, 40, isTreasure ? 0x1f2430 : 0x101820, isTreasure ? 0.97 : 0.94)); + const bg = this.trackSideObject(this.add.rectangle(x, y, width, 38, 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 + 20, 38, 38, 0x0a0f14, 0.9)); + const iconFrame = this.trackSideObject(this.add.rectangle(x + 23, y + 19, 36, 36, 0x0a0f14, 0.92)); iconFrame.setStrokeStyle(1, isTreasure ? palette.gold : 0x53606c, isTreasure ? 0.78 : 0.54); - this.trackSideIcon(x + 23, y + 20, this.itemIcon(item, slot), 34); + this.trackSideIcon(x + 23, y + 19, this.itemIcon(item, slot), 34); - this.trackSideObject(this.add.text(x + 50, y + 4, equipmentSlotLabels[slot], { + this.trackSideObject(this.add.text(x + 48, y + 3, equipmentSlotLabels[slot], { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '12px', + fontSize: '11px', color: '#9fb0bf', fontStyle: '700' })); - this.trackSideObject(this.add.text(x + 94, y + 4, item.name, { + const bonusText = this.itemBonusText(item); + this.trackSideObject(this.add.text(x + 86, y + 3, bonusText, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '11px', + color: '#aeb7c2', + fixedWidth: width - 170 + })); + this.trackSideObject(this.add.text(x + 48, y + 17, item.name, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '15px', color: isTreasure ? '#f4dfad' : '#d4dce6', fontStyle: '700', - fixedWidth: width - 148 + fixedWidth: width - 150 })); - const bonusText = this.itemBonusText(item); - this.trackSideObject(this.add.text(x + 50, y + 22, bonusText, { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '11px', - color: '#aeb7c2', - fixedWidth: 72 - })); - - this.trackSideIcon(x + width - 82, y + 20, 'mastery', 21); - const expText = this.trackSideObject(this.add.text(x + width - 58, y + 22, `${state.exp}/${next}`, { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '12px', - color: '#c8d2dd', - fontStyle: '700' - })); - expText.setOrigin(1, 0); - - const levelText = this.trackSideObject(this.add.text(x + width - 8, y + 8, `Lv ${state.level}`, { + const levelText = this.trackSideObject(this.add.text(x + width - 10, y + 5, `Lv ${state.level}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', fontSize: '15px', color: isTreasure ? '#f2e3bf' : '#d4dce6', @@ -12616,7 +12626,16 @@ export class BattleScene extends Phaser.Scene { })); levelText.setOrigin(1, 0); - this.drawGauge(x + 126, y + 31, width - 202, 6, state.exp / next, isTreasure ? 0xd8b15f : 0x58aee0); + this.trackSideIcon(x + width - 76, y + 27, 'mastery', 20); + const expText = this.trackSideObject(this.add.text(x + width - 10, y + 24, `${state.exp}/${next}`, { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '11px', + color: '#c8d2dd', + fontStyle: '700' + })); + expText.setOrigin(1, 0); + + this.drawGauge(x + 48, y + 32, width - 132, 5, state.exp / next, isTreasure ? 0xd8b15f : 0x58aee0); } private createBattleUiIcon(x: number, y: number, icon: BattleUiIconKey, size = 22) { @@ -12741,20 +12760,21 @@ export class BattleScene extends Phaser.Scene { } private renderCompactValueBox(x: number, y: number, width: number, icon: BattleUiIconKey, label: string, value: string) { - const bg = this.trackSideObject(this.add.rectangle(x, y, width, 46, 0x16212d, 0.97)); + const bg = this.trackSideObject(this.add.rectangle(x, y, width, 42, 0x16212d, 0.97)); bg.setOrigin(0); bg.setStrokeStyle(1, 0x647485, 0.72); - const iconFrame = this.trackSideObject(this.add.rectangle(x + 18, y + 23, 32, 32, 0x0a0f14, 0.82)); + const iconFrame = this.trackSideObject(this.add.rectangle(x + 17, y + 21, 30, 30, 0x0a0f14, 0.86)); iconFrame.setStrokeStyle(1, 0x53606c, 0.52); - this.trackSideIcon(x + 18, y + 23, icon, 29); - this.trackSideObject(this.add.text(x + 38, y + 7, label, { + this.trackSideIcon(x + 17, y + 21, icon, 28); + this.trackSideObject(this.add.text(x + 36, y + 5, label, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '12px', - color: '#9fb0bf' + fontSize: '11px', + color: '#9fb0bf', + fixedWidth: Math.max(36, width - 42) })); - const valueText = this.trackSideObject(this.add.text(x + width - 8, y + 25, value, { + const valueText = this.trackSideObject(this.add.text(x + width - 7, y + 29, value, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '15px', + fontSize: '14px', color: '#f2e3bf', fontStyle: '700' })); @@ -12762,19 +12782,21 @@ export class BattleScene extends Phaser.Scene { } private renderStatRow(key: keyof UnitStats, label: string, value: number, x: number, y: number, width: number) { - this.trackSideIcon(x + 13, y + 10, this.statIcon(key), 26); - this.trackSideObject(this.add.text(x + 36, y, label, { + const rowBg = this.trackSideObject(this.add.rectangle(x, y - 1, width, 22, 0x101820, 0.5)); + rowBg.setOrigin(0); + this.trackSideIcon(x + 14, y + 10, this.statIcon(key), 23); + this.trackSideObject(this.add.text(x + 34, y + 1, label, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '16px', + fontSize: '14px', color: '#d4dce6', fontStyle: '700' })); - this.drawGauge(x + 104, y + 8, width - 158, 10, value / 100, value >= 80 ? 0xd8b15f : 0x58aee0); + this.drawGauge(x + 104, y + 7, width - 158, 8, value / 100, value >= 80 ? 0xd8b15f : 0x58aee0); - const valueText = this.trackSideObject(this.add.text(x + width, y - 1, `${value}`, { + const valueText = this.trackSideObject(this.add.text(x + width - 8, y - 1, `${value}`, { fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '17px', + fontSize: '16px', color: '#f2e3bf', fontStyle: '700' }));