From a8d745408a85c916520ea469d3d7f450cb9cb342 Mon Sep 17 00:00:00 2001 From: tekki mariani Date: Tue, 24 Mar 2026 20:28:20 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20show=20forester=20planting=20radius?= =?UTF-8?q?=20preview=20while=20placing=20hut=20(Issue=20#47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Semi-transparent green 11x11 tile overlay follows the ghost cursor when forester_hut is selected. Disappears on deactivate/cancel. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 1 + src/systems/BuildingSystem.ts | 44 +++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 927fcf6..e5022f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Added +- **Forester Radius Preview** (Issue #47): When placing a Forester Hut, a semi-transparent green overlay shows the full planting zone radius (Chebyshev 5 = 11×11 tiles) following the ghost cursor; disappears on cancel - **Demolish Mode** (Issue #50): New 💥 Demolish button in the action bar; hover shows a red ghost over any building with a refund percentage; buildings demolished within 3 minutes return 100% of costs (linear decay to 0%); mine footprint tiles are unblocked on teardown; Nisse working inside a demolished building are rescued and resume idle; tile types are restored where applicable (floor/wall/chest → grass) - **Mine Building** (Issue #42): 3×2 building placeable only on resource-free ROCK tiles (costs: 200 wood + 50 stone); Nisse with mine priority walk to the entrance, disappear inside for 15 s, then reappear carrying 2 stone; up to 3 Nisse work simultaneously; ⛏ X/3 status label shown directly on the building in world space; surface rock harvesting remains functional alongside the building diff --git a/src/systems/BuildingSystem.ts b/src/systems/BuildingSystem.ts index 908ed5f..00b926c 100644 --- a/src/systems/BuildingSystem.ts +++ b/src/systems/BuildingSystem.ts @@ -1,5 +1,5 @@ import Phaser from 'phaser' -import { TILE_SIZE, BUILDING_COSTS, DEMOLISH_REFUND_MS } from '../config' +import { TILE_SIZE, BUILDING_COSTS, DEMOLISH_REFUND_MS, FORESTER_ZONE_RADIUS } from '../config' import { TileType, IMPASSABLE } from '../types' import type { BuildingType, BuildingState, ItemId } from '../types' import { stateManager } from '../StateManager' @@ -27,6 +27,7 @@ export class BuildingSystem { private selectedBuilding: BuildingType = 'floor' private ghost!: Phaser.GameObjects.Rectangle private ghostLabel!: Phaser.GameObjects.Text + private foresterRadiusOverlay!: Phaser.GameObjects.Graphics private buildKey!: Phaser.Input.Keyboard.Key private cancelKey!: Phaser.Input.Keyboard.Key @@ -63,6 +64,10 @@ export class BuildingSystem { this.ghostLabel.setVisible(false) this.ghostLabel.setOrigin(0.5, 1) + this.foresterRadiusOverlay = this.scene.add.graphics() + this.foresterRadiusOverlay.setDepth(999) + this.foresterRadiusOverlay.setVisible(false) + this.buildKey = this.scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.B) this.cancelKey = this.scene.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.ESC) @@ -138,6 +143,7 @@ export class BuildingSystem { this.active = false this.ghost.setVisible(false) this.ghostLabel.setVisible(false) + this.foresterRadiusOverlay.setVisible(false) this.onModeChange?.(false, this.selectedBuilding) } @@ -193,6 +199,7 @@ export class BuildingSystem { /** * Updates the green/red build-mode ghost to follow the mouse, snapped to the tile grid. + * For forester_hut, also draws a semi-transparent radius preview overlay. */ private updateBuildGhost(): void { const ptr = this.scene.input.activePointer @@ -213,6 +220,38 @@ export class BuildingSystem { const costs = BUILDING_COSTS[this.selectedBuilding] ?? {} const costStr = Object.entries(costs).map(([k, v]) => `${v}${k[0].toUpperCase()}`).join(' ') this.ghostLabel.setText(`${this.selectedBuilding} [${costStr}]`) + + if (this.selectedBuilding === 'forester_hut') { + this.updateForesterRadiusOverlay(tileX, tileY) + } else { + this.foresterRadiusOverlay.setVisible(false) + } + } + + /** + * Redraws the forester radius preview overlay centered on the given tile. + * Shows the Chebyshev-radius planting zone as a semi-transparent green fill + * with a dotted border. + * @param centerTileX - Tile column of the hut + * @param centerTileY - Tile row of the hut + */ + private updateForesterRadiusOverlay(centerTileX: number, centerTileY: number): void { + const r = FORESTER_ZONE_RADIUS + const px = (centerTileX - r) * TILE_SIZE + const py = (centerTileY - r) * TILE_SIZE + const pw = (r * 2 + 1) * TILE_SIZE + const ph = (r * 2 + 1) * TILE_SIZE + + this.foresterRadiusOverlay.clear() + this.foresterRadiusOverlay.setVisible(true) + + // Semi-transparent green fill + this.foresterRadiusOverlay.fillStyle(0x44ff44, 0.08) + this.foresterRadiusOverlay.fillRect(px, py, pw, ph) + + // Solid border + this.foresterRadiusOverlay.lineStyle(2, 0x44ff44, 0.5) + this.foresterRadiusOverlay.strokeRect(px, py, pw, ph) } /** @@ -421,10 +460,11 @@ export class BuildingSystem { } /** - * Cleans up ghost sprites on scene shutdown. + * Cleans up ghost sprites and overlays on scene shutdown. */ destroy(): void { this.ghost.destroy() this.ghostLabel.destroy() + this.foresterRadiusOverlay.destroy() } } -- 2.49.1