diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index f146c83..4dcd130 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -189,6 +189,16 @@ const factionLabels: Record = { enemy: '적군' }; +const terrainDisplayLabels: Record = { + plain: '평지', + road: '길', + forest: '숲', + hill: '언덕', + village: '마을', + fort: '요새', + camp: '진영' +}; + const mapMenuLabels: Partial> = { endTurn: '턴 종료', roster: '부대 일람', @@ -248,6 +258,11 @@ export class BattleScene extends Phaser.Scene { this.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => { if (pointer.rightButtonDown()) { this.handleRightClick(pointer); + return; + } + + if (pointer.leftButtonDown()) { + this.handleLeftClick(pointer); } }); this.installDebugHotkeys(); @@ -1050,6 +1065,26 @@ export class BattleScene extends Phaser.Scene { this.hideMapMenu(); } + private handleLeftClick(pointer: Phaser.Input.Pointer) { + if (this.phase !== 'idle' || !this.isPointerOnEmptyMapTile(pointer)) { + return; + } + + const tile = this.pointerToTile(pointer); + if (!tile) { + return; + } + + this.selectedUnit = undefined; + this.pendingMove = undefined; + this.targetingAction = undefined; + this.clearMarkers(); + this.hideCommandMenu(); + this.hideTurnEndPrompt(); + this.hideMapMenu(); + this.renderTerrainDetail(tile.x, tile.y); + } + private isPointerOnEmptyMapTile(pointer: Phaser.Input.Pointer) { const tile = this.pointerToTile(pointer); if (!tile) { @@ -2426,6 +2461,47 @@ export class BattleScene extends Phaser.Scene { this.renderPanelMessage(message ?? '빈 맵에서 우클릭하면 전술 메뉴를 다시 열 수 있습니다.', left, top + 286, width); } + private renderTerrainDetail(x: number, y: number) { + this.clearSidePanelContent(); + const terrain = firstBattleMap.terrain[y][x]; + const terrainRule = getTerrainRule(terrain); + const { panelX, panelY, panelWidth } = this.layout; + const left = panelX + 24; + const width = panelWidth - 48; + const top = panelY + 132; + const attackDefense = Math.floor(terrainRule.defenseBonus / 3); + const strategyDefense = Math.floor(terrainRule.defenseBonus / 4); + const itemDefense = Math.floor(terrainRule.defenseBonus / 5); + + this.trackSideObject(this.add.text(left, top, '지형 정보', { + fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', + fontSize: '24px', + color: '#f2e3bf', + fontStyle: '700' + })); + + this.renderSituationLine('좌표', `${x + 1}, ${y + 1}`, left, top + 48, width); + this.renderSituationLine('지형', terrainDisplayLabels[terrain], left, top + 92, width); + this.renderSituationLine('이동 비용', `${terrainRule.moveCost}`, left, top + 136, width); + this.renderSituationLine('방어 보정', this.formatSignedValue(terrainRule.defenseBonus), left, top + 180, width); + this.renderSituationLine('공격 방어', this.formatSignedValue(attackDefense), left, top + 224, width); + this.renderSituationLine('책략 저항', this.formatSignedValue(strategyDefense), left, top + 268, width); + this.renderSituationLine('도구 피해', this.formatSignedValue(itemDefense), left, top + 312, width); + + const message = + terrainRule.defenseBonus > 0 + ? '이 지형에 있는 부대는 방어 보정으로 받는 피해가 줄어듭니다.' + : '이 지형은 기본 방어 보정이 없습니다.'; + this.renderPanelMessage(message, left, top + 370, width, 66); + } + + private formatSignedValue(value: number) { + if (value > 0) { + return `+${value}`; + } + return `${value}`; + } + private renderSituationLine(label: string, value: string, x: number, y: number, width: number) { const bg = this.trackSideObject(this.add.rectangle(x, y, width, 34, 0x101820, 0.86)); bg.setOrigin(0);