7 Commits

Author SHA1 Message Date
0ed3bfaea6 Merge pull request '🐛 Stockpile opacity + layout overlap + ESC menu padding' (#21) from fix/stockpile-layout-esc-margin into master 2026-03-23 11:28:28 +00:00
1d46446012 📝 update CHANGELOG for Issue #20 2026-03-23 10:48:52 +00:00
a5c37f20f6 🐛 fix stockpile opacity, popText overlap, ESC menu padding (Issue #20)
- Stockpile panel: use uiOpacity instead of hardcoded 0.72
- updateStaticPanelOpacity() replaces updateDebugPanelBackground() and also
  updates stockpilePanel.setAlpha() when opacity changes in Settings
- Stockpile panel height 187→210; popText y 167→192 (8px gap after carrot row)
- ESC menu menuH formula: 16+…+8 → 32+…+8 so last button has 16px bottom
  padding instead of 0px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 10:48:04 +00:00
174db14c7a 📝 update CHANGELOG for Issue #16 overlay opacity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 09:38:09 +00:00
c7ebf49bf2 overlay opacity: global setting + settings screen (Issue #16)
- Add UI_SETTINGS_KEY to config.ts for separate localStorage entry
- Add uiOpacity field (default 0.8, range 0.4–1.0, 10 % steps) to UIScene
- loadUISettings / saveUISettings persist opacity independently of game save
- Replace all hardcoded panel BG alphas with this.uiOpacity:
  build menu, villager panel, context menu, ESC menu, confirm dialog,
  nisse info panel
- Debug panel (F3) background synced via updateDebugPanelBackground()
- Replace Settings toast with real Settings overlay:
  title, opacity − / value / + buttons, Close button
- ESC key priority stack now includes settingsVisible
- repositionUI closes settings panel on window resize

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 09:36:42 +00:00
b259d966ee Merge pull request '🐛 Nisse info panel no longer pauses the game' (#18) from fix/nisse-info-panel-no-pause into master
Reviewed-on: #18
Reviewed-by: tekki <tekki.mariani@googlemail.com>
2026-03-22 09:21:37 +00:00
9b22f708a5 🐛 fix nisse info panel no longer pauses the game
Removes uiMenuOpen/uiMenuClose calls from openNisseInfoPanel() and
closeNisseInfoPanel() — the info panel is an observational overlay and
should not interrupt the game loop. Closes #15.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 06:55:11 +00:00
3 changed files with 182 additions and 14 deletions

View File

@@ -7,6 +7,14 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Fixed
- **Stockpile panel** (Issue #20): panel background now uses `uiOpacity` and updates live when Settings opacity changes; panel height increased so the Nisse count row no longer overlaps the carrot row
- **ESC menu** (Issue #20): internal bottom padding corrected — last button now has 16px gap to panel edge instead of 0px
### Added
- **Overlay Opacity Setting** (Issue #16): all UI overlay backgrounds (build menu, villager panel, context menu, ESC menu, confirm dialog, Nisse info panel, debug panel) now use a central `uiOpacity` value instead of hardcoded alphas
- **Settings Screen**: ESC menu → Settings now opens a real overlay with an overlay-opacity row ( / value% / + step buttons, range 40 %100 %, default 80 %); setting persisted in `localStorage` under `tg_ui_settings`, separate from game save so New Game does not wipe it
### Added ### Added
- **Unified Tile System** (Issue #14): - **Unified Tile System** (Issue #14):
- Tree seedlings: player plants `tree_seed` on grass/dark-grass via the F-key farming tool; seedling grows through two stages (sprout → sapling → young tree, ~1 min each); on maturity it becomes a FOREST tile with a harvestable tree resource - Tree seedlings: player plants `tree_seed` on grass/dark-grass via the F-key farming tool; seedling grows through two stages (sprout → sapling → young tree, ~1 min each); on maturity it becomes a FOREST tile with a harvestable tree resource

View File

@@ -49,6 +49,9 @@ export const VILLAGER_NAMES = [
export const SAVE_KEY = 'tg_save_v5' export const SAVE_KEY = 'tg_save_v5'
export const AUTOSAVE_INTERVAL = 30_000 export const AUTOSAVE_INTERVAL = 30_000
/** localStorage key for UI settings (opacity etc.) — separate from the game save. */
export const UI_SETTINGS_KEY = 'tg_ui_settings'
/** Milliseconds for one tree-seedling stage to advance (two stages = full tree). */ /** Milliseconds for one tree-seedling stage to advance (two stages = full tree). */
export const TREE_SEEDLING_STAGE_MS = 60_000 // 1 min per stage → 2 min total export const TREE_SEEDLING_STAGE_MS = 60_000 // 1 min per stage → 2 min total

View File

@@ -3,6 +3,7 @@ import type { BuildingType, JobPriorities } from '../types'
import type { FarmingTool } from '../systems/FarmingSystem' import type { FarmingTool } from '../systems/FarmingSystem'
import type { DebugData } from '../systems/DebugSystem' import type { DebugData } from '../systems/DebugSystem'
import { stateManager } from '../StateManager' import { stateManager } from '../StateManager'
import { UI_SETTINGS_KEY } from '../config'
const ITEM_ICONS: Record<string, string> = { const ITEM_ICONS: Record<string, string> = {
wood: '🪵', stone: '🪨', wheat_seed: '🌱', carrot_seed: '🥕', wood: '🪵', stone: '🪨', wheat_seed: '🌱', carrot_seed: '🥕',
@@ -46,6 +47,11 @@ export class UIScene extends Phaser.Scene {
logTexts: Phaser.GameObjects.Text[] logTexts: Phaser.GameObjects.Text[]
} | null = null } | null = null
/** Current overlay background opacity (0.41.0, default 0.8). Persisted in localStorage. */
private uiOpacity = 0.8
private settingsGroup!: Phaser.GameObjects.Group
private settingsVisible = false
constructor() { super({ key: 'UI' }) } constructor() { super({ key: 'UI' }) }
/** /**
@@ -53,6 +59,7 @@ export class UIScene extends Phaser.Scene {
* keyboard shortcuts (B, V, F3, ESC). * keyboard shortcuts (B, V, F3, ESC).
*/ */
create(): void { create(): void {
this.loadUISettings()
this.createStockpilePanel() this.createStockpilePanel()
this.createHintText() this.createHintText()
this.createToast() this.createToast()
@@ -85,6 +92,7 @@ export class UIScene extends Phaser.Scene {
this.escMenuGroup = this.add.group() this.escMenuGroup = this.add.group()
this.confirmGroup = this.add.group() this.confirmGroup = this.add.group()
this.nisseInfoGroup = this.add.group() this.nisseInfoGroup = this.add.group()
this.settingsGroup = this.add.group()
this.input.on('pointerdown', (ptr: Phaser.Input.Pointer) => { this.input.on('pointerdown', (ptr: Phaser.Input.Pointer) => {
if (ptr.rightButtonDown()) { if (ptr.rightButtonDown()) {
@@ -119,14 +127,16 @@ export class UIScene extends Phaser.Scene {
/** Creates the stockpile panel in the top-right corner with item rows and population count. */ /** Creates the stockpile panel in the top-right corner with item rows and population count. */
private createStockpilePanel(): void { private createStockpilePanel(): void {
const x = this.scale.width - 178, y = 10 const x = this.scale.width - 178, y = 10
this.stockpilePanel = this.add.rectangle(x, y, 168, 187, 0x000000, 0.72).setOrigin(0, 0).setScrollFactor(0).setDepth(100) // 7 items × 22px + 26px header + 12px gap + 18px popText row + 10px bottom = 210px
this.stockpilePanel = this.add.rectangle(x, y, 168, 210, 0x000000, this.uiOpacity).setOrigin(0, 0).setScrollFactor(0).setDepth(100)
this.stockpileTitleText = this.add.text(x + 10, y + 7, '⚡ STOCKPILE', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) this.stockpileTitleText = this.add.text(x + 10, y + 7, '⚡ STOCKPILE', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101)
const items = ['wood','stone','wheat_seed','carrot_seed','tree_seed','wheat','carrot'] as const const items = ['wood','stone','wheat_seed','carrot_seed','tree_seed','wheat','carrot'] as const
items.forEach((item, i) => { items.forEach((item, i) => {
const t = this.add.text(x + 10, y + 26 + i * 22, `${ITEM_ICONS[item]} ${item}: 0`, { fontSize: '13px', color: '#88dd88', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) const t = this.add.text(x + 10, y + 26 + i * 22, `${ITEM_ICONS[item]} ${item}: 0`, { fontSize: '13px', color: '#88dd88', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101)
this.stockpileTexts.set(item, t) this.stockpileTexts.set(item, t)
}) })
this.popText = this.add.text(x + 10, y + 167, '👥 Nisse: 0 / 0', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) // last item (i=6) bottom edge ≈ y+190 → popText starts at y+192 with 8px gap
this.popText = this.add.text(x + 10, y + 192, '👥 Nisse: 0 / 0', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101)
} }
/** Refreshes all item quantities and colors in the stockpile panel. */ /** Refreshes all item quantities and colors in the stockpile panel. */
@@ -196,7 +206,7 @@ export class UIScene extends Phaser.Scene {
{ kind: 'stockpile_zone', label: '📦 Stockpile', cost: 'free (workers deliver here)' }, { kind: 'stockpile_zone', label: '📦 Stockpile', cost: 'free (workers deliver here)' },
] ]
const menuX = this.scale.width / 2 - 150, menuY = this.scale.height / 2 - 140 const menuX = this.scale.width / 2 - 150, menuY = this.scale.height / 2 - 140
const bg = this.add.rectangle(menuX, menuY, 300, 280, 0x000000, 0.88).setOrigin(0,0).setScrollFactor(0).setDepth(200) const bg = this.add.rectangle(menuX, menuY, 300, 280, 0x000000, this.uiOpacity).setOrigin(0,0).setScrollFactor(0).setDepth(200)
this.buildMenuGroup.add(bg) this.buildMenuGroup.add(bg)
this.buildMenuGroup.add(this.add.text(menuX + 150, menuY + 14, 'BUILD MENU [B/ESC]', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setOrigin(0.5,0).setScrollFactor(0).setDepth(201)) this.buildMenuGroup.add(this.add.text(menuX + 150, menuY + 14, 'BUILD MENU [B/ESC]', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setOrigin(0.5,0).setScrollFactor(0).setDepth(201))
@@ -263,7 +273,7 @@ export class UIScene extends Phaser.Scene {
const px = this.scale.width / 2 - panelW / 2 const px = this.scale.width / 2 - panelW / 2
const py = this.scale.height / 2 - panelH / 2 const py = this.scale.height / 2 - panelH / 2
const bg = this.add.rectangle(px, py, panelW, panelH, 0x0a0a0a, 0.92).setOrigin(0,0).setScrollFactor(0).setDepth(210) const bg = this.add.rectangle(px, py, panelW, panelH, 0x0a0a0a, this.uiOpacity).setOrigin(0,0).setScrollFactor(0).setDepth(210)
this.villagerPanelGroup.add(bg) this.villagerPanelGroup.add(bg)
this.villagerPanelGroup.add( this.villagerPanelGroup.add(
@@ -383,10 +393,11 @@ export class UIScene extends Phaser.Scene {
/** Creates the debug panel text object (initially hidden). */ /** Creates the debug panel text object (initially hidden). */
private createDebugPanel(): void { private createDebugPanel(): void {
const hexAlpha = Math.round(this.uiOpacity * 255).toString(16).padStart(2, '0')
this.debugPanelText = this.add.text(10, 80, '', { this.debugPanelText = this.add.text(10, 80, '', {
fontSize: '12px', fontSize: '12px',
color: '#cccccc', color: '#cccccc',
backgroundColor: '#000000cc', backgroundColor: `#000000${hexAlpha}`,
padding: { x: 8, y: 6 }, padding: { x: 8, y: 6 },
lineSpacing: 2, lineSpacing: 2,
fontFamily: 'monospace', fontFamily: 'monospace',
@@ -463,7 +474,7 @@ export class UIScene extends Phaser.Scene {
const mx = Math.min(x, this.scale.width - menuW - 4) const mx = Math.min(x, this.scale.width - menuW - 4)
const my = Math.min(y, this.scale.height - menuH - 4) const my = Math.min(y, this.scale.height - menuH - 4)
const bg = this.add.rectangle(mx, my, menuW, menuH, 0x000000, 0.88) const bg = this.add.rectangle(mx, my, menuW, menuH, 0x000000, this.uiOpacity)
.setOrigin(0, 0).setScrollFactor(0).setDepth(300) .setOrigin(0, 0).setScrollFactor(0).setDepth(300)
this.contextMenuGroup.add(bg) this.contextMenuGroup.add(bg)
@@ -521,6 +532,7 @@ export class UIScene extends Phaser.Scene {
if (this.buildMenuVisible) { this.closeBuildMenu(); return } if (this.buildMenuVisible) { this.closeBuildMenu(); return }
if (this.villagerPanelVisible){ this.closeVillagerPanel(); return } if (this.villagerPanelVisible){ this.closeVillagerPanel(); return }
if (this.nisseInfoVisible) { this.closeNisseInfoPanel(); return } if (this.nisseInfoVisible) { this.closeNisseInfoPanel(); return }
if (this.settingsVisible) { this.closeSettings(); return }
if (this.escMenuVisible) { this.closeEscMenu(); return } if (this.escMenuVisible) { this.closeEscMenu(); return }
// Build/farm mode: let BuildingSystem / FarmingSystem handle their own ESC key. // Build/farm mode: let BuildingSystem / FarmingSystem handle their own ESC key.
// We only skip opening the ESC menu while those modes are active. // We only skip opening the ESC menu while those modes are active.
@@ -560,11 +572,12 @@ export class UIScene extends Phaser.Scene {
{ label: '⚙️ Settings', action: () => this.doSettings() }, { label: '⚙️ Settings', action: () => this.doSettings() },
{ label: '🆕 New Game', action: () => this.doNewGame() }, { label: '🆕 New Game', action: () => this.doNewGame() },
] ]
const menuH = 16 + entries.length * (btnH + 8) + 8 // 32px header + entries × (btnH + 8px gap) + 8px bottom padding
const menuH = 32 + entries.length * (btnH + 8) + 8
const mx = this.scale.width / 2 - menuW / 2 const mx = this.scale.width / 2 - menuW / 2
const my = this.scale.height / 2 - menuH / 2 const my = this.scale.height / 2 - menuH / 2
const bg = this.add.rectangle(mx, my, menuW, menuH, 0x0a0a0a, 0.95) const bg = this.add.rectangle(mx, my, menuW, menuH, 0x0a0a0a, this.uiOpacity)
.setOrigin(0, 0).setScrollFactor(0).setDepth(400) .setOrigin(0, 0).setScrollFactor(0).setDepth(400)
this.escMenuGroup.add(bg) this.escMenuGroup.add(bg)
this.escMenuGroup.add( this.escMenuGroup.add(
@@ -602,10 +615,155 @@ export class UIScene extends Phaser.Scene {
window.location.reload() window.location.reload()
} }
/** Opens an empty Settings panel (placeholder). */ /** Opens the Settings overlay. */
private doSettings(): void { private doSettings(): void {
this.closeEscMenu() this.closeEscMenu()
this.showToast('Settings — coming soon') this.openSettings()
}
// ─── Settings overlay ─────────────────────────────────────────────────────
/** Opens the settings overlay if it is not already open. */
private openSettings(): void {
if (this.settingsVisible) return
this.settingsVisible = true
this.scene.get('Game').events.emit('uiMenuOpen')
this.buildSettings()
}
/** Closes and destroys the settings overlay. */
private closeSettings(): void {
if (!this.settingsVisible) return
this.settingsVisible = false
this.settingsGroup.destroy(true)
this.settingsGroup = this.add.group()
this.scene.get('Game').events.emit('uiMenuClose')
}
/**
* Builds the settings overlay with an overlay-opacity row (step buttons).
* Destroying and recreating this method is used to refresh the displayed value.
*/
private buildSettings(): void {
if (this.settingsGroup) this.settingsGroup.destroy(true)
this.settingsGroup = this.add.group()
const panelW = 280
const panelH = 130
const px = this.scale.width / 2 - panelW / 2
const py = this.scale.height / 2 - panelH / 2
// Background
const bg = this.add.rectangle(px, py, panelW, panelH, 0x0a0a0a, this.uiOpacity)
.setOrigin(0, 0).setScrollFactor(0).setDepth(450)
this.settingsGroup.add(bg)
// Title
this.settingsGroup.add(
this.add.text(px + panelW / 2, py + 14, '⚙️ SETTINGS [ESC close]', {
fontSize: '11px', color: '#666666', fontFamily: 'monospace',
}).setOrigin(0.5, 0).setScrollFactor(0).setDepth(451)
)
// Opacity label
this.settingsGroup.add(
this.add.text(px + 16, py + 58, 'Overlay opacity:', {
fontSize: '13px', color: '#cccccc', fontFamily: 'monospace',
}).setOrigin(0, 0.5).setScrollFactor(0).setDepth(451)
)
// Minus button
const minusBtn = this.add.rectangle(px + 170, py + 47, 26, 22, 0x1a1a2e, 0.9)
.setOrigin(0, 0).setScrollFactor(0).setDepth(451).setInteractive()
minusBtn.on('pointerover', () => minusBtn.setFillStyle(0x2a2a4e, 0.9))
minusBtn.on('pointerout', () => minusBtn.setFillStyle(0x1a1a2e, 0.9))
minusBtn.on('pointerdown', () => {
this.uiOpacity = Math.max(0.4, Math.round((this.uiOpacity - 0.1) * 10) / 10)
this.saveUISettings()
this.updateStaticPanelOpacity()
this.buildSettings()
})
this.settingsGroup.add(minusBtn)
this.settingsGroup.add(
this.add.text(px + 183, py + 58, '', {
fontSize: '15px', color: '#ffffff', fontFamily: 'monospace',
}).setOrigin(0.5, 0.5).setScrollFactor(0).setDepth(452)
)
// Value display
this.settingsGroup.add(
this.add.text(px + 215, py + 58, `${Math.round(this.uiOpacity * 100)}%`, {
fontSize: '13px', color: '#aaaaaa', fontFamily: 'monospace',
}).setOrigin(0.5, 0.5).setScrollFactor(0).setDepth(451)
)
// Plus button
const plusBtn = this.add.rectangle(px + 242, py + 47, 26, 22, 0x1a1a2e, 0.9)
.setOrigin(0, 0).setScrollFactor(0).setDepth(451).setInteractive()
plusBtn.on('pointerover', () => plusBtn.setFillStyle(0x2a2a4e, 0.9))
plusBtn.on('pointerout', () => plusBtn.setFillStyle(0x1a1a2e, 0.9))
plusBtn.on('pointerdown', () => {
this.uiOpacity = Math.min(1.0, Math.round((this.uiOpacity + 0.1) * 10) / 10)
this.saveUISettings()
this.updateStaticPanelOpacity()
this.buildSettings()
})
this.settingsGroup.add(plusBtn)
this.settingsGroup.add(
this.add.text(px + 255, py + 58, '+', {
fontSize: '15px', color: '#ffffff', fontFamily: 'monospace',
}).setOrigin(0.5, 0.5).setScrollFactor(0).setDepth(452)
)
// Close button
const closeBtnRect = this.add.rectangle(px + panelW / 2 - 50, py + 92, 100, 28, 0x1a1a2e, 0.9)
.setOrigin(0, 0).setScrollFactor(0).setDepth(451).setInteractive()
closeBtnRect.on('pointerover', () => closeBtnRect.setFillStyle(0x2a2a4e, 0.9))
closeBtnRect.on('pointerout', () => closeBtnRect.setFillStyle(0x1a1a2e, 0.9))
closeBtnRect.on('pointerdown', () => this.closeSettings())
this.settingsGroup.add(closeBtnRect)
this.settingsGroup.add(
this.add.text(px + panelW / 2, py + 106, 'Close', {
fontSize: '13px', color: '#dddddd', fontFamily: 'monospace',
}).setOrigin(0.5, 0.5).setScrollFactor(0).setDepth(452)
)
}
/**
* Loads UI settings from localStorage and applies the stored opacity value.
* Falls back to the default (0.8) if no setting is found.
*/
private loadUISettings(): void {
try {
const raw = localStorage.getItem(UI_SETTINGS_KEY)
if (raw) {
const parsed = JSON.parse(raw) as { opacity?: number }
if (typeof parsed.opacity === 'number') {
this.uiOpacity = Math.max(0.4, Math.min(1.0, parsed.opacity))
}
}
} catch (_) {}
}
/**
* Persists the current UI settings (opacity) to localStorage.
* Stored separately from the game save so New Game does not wipe it.
*/
private saveUISettings(): void {
try {
localStorage.setItem(UI_SETTINGS_KEY, JSON.stringify({ opacity: this.uiOpacity }))
} catch (_) {}
}
/**
* Applies the current uiOpacity to all static UI elements that are not
* rebuilt on open (stockpile panel, debug panel background).
* Called whenever uiOpacity changes.
*/
private updateStaticPanelOpacity(): void {
this.stockpilePanel.setAlpha(this.uiOpacity)
const hexAlpha = Math.round(this.uiOpacity * 255).toString(16).padStart(2, '0')
this.debugPanelText.setStyle({ backgroundColor: `#000000${hexAlpha}` })
} }
/** Shows a confirmation dialog before starting a new game. */ /** Shows a confirmation dialog before starting a new game. */
@@ -634,7 +792,7 @@ export class UIScene extends Phaser.Scene {
const dx = this.scale.width / 2 - dialogW / 2 const dx = this.scale.width / 2 - dialogW / 2
const dy = this.scale.height / 2 - dialogH / 2 const dy = this.scale.height / 2 - dialogH / 2
const bg = this.add.rectangle(dx, dy, dialogW, dialogH, 0x0a0a0a, 0.97) const bg = this.add.rectangle(dx, dy, dialogW, dialogH, 0x0a0a0a, this.uiOpacity)
.setOrigin(0, 0).setScrollFactor(0).setDepth(500) .setOrigin(0, 0).setScrollFactor(0).setDepth(500)
this.confirmGroup.add(bg) this.confirmGroup.add(bg)
@@ -692,7 +850,6 @@ export class UIScene extends Phaser.Scene {
private openNisseInfoPanel(villagerId: string): void { private openNisseInfoPanel(villagerId: string): void {
this.nisseInfoId = villagerId this.nisseInfoId = villagerId
this.nisseInfoVisible = true this.nisseInfoVisible = true
this.scene.get('Game').events.emit('uiMenuOpen')
this.buildNisseInfoPanel() this.buildNisseInfoPanel()
} }
@@ -703,7 +860,6 @@ export class UIScene extends Phaser.Scene {
this.nisseInfoId = null this.nisseInfoId = null
this.nisseInfoGroup.destroy(true) this.nisseInfoGroup.destroy(true)
this.nisseInfoGroup = this.add.group() this.nisseInfoGroup = this.add.group()
this.scene.get('Game').events.emit('uiMenuClose')
} }
/** /**
@@ -730,7 +886,7 @@ export class UIScene extends Phaser.Scene {
// Background // Background
this.nisseInfoGroup.add( this.nisseInfoGroup.add(
this.add.rectangle(px, py, panelW, panelH, 0x050510, 0.93) this.add.rectangle(px, py, panelW, panelH, 0x050510, this.uiOpacity)
.setOrigin(0, 0).setScrollFactor(0).setDepth(250) .setOrigin(0, 0).setScrollFactor(0).setDepth(250)
) )
@@ -883,6 +1039,7 @@ export class UIScene extends Phaser.Scene {
if (this.villagerPanelVisible) this.closeVillagerPanel() if (this.villagerPanelVisible) this.closeVillagerPanel()
if (this.contextMenuVisible) this.hideContextMenu() if (this.contextMenuVisible) this.hideContextMenu()
if (this.escMenuVisible) this.closeEscMenu() if (this.escMenuVisible) this.closeEscMenu()
if (this.settingsVisible) this.closeSettings()
if (this.confirmVisible) this.hideConfirm() if (this.confirmVisible) this.hideConfirm()
if (this.nisseInfoVisible) this.closeNisseInfoPanel() if (this.nisseInfoVisible) this.closeNisseInfoPanel()
} }