Three-agent fan-out (gdscript-refactor x3) closing deferred polish: - Stockpile chip filter UI: new StockpilePanel (layer 18, right-anchored, mirrors WorkbenchPanel). 5-priority segmented control + 21-chip 4-col filter grid using Item.ALL_TYPES; wildcard (empty accepted_types) shows all chips checked with 'All' hint, first explicit pick switches to explicit-list mode. Selection chain extended to pawn → workbench → stockpile with mutual exclusion. 12 ui.stockpile.* + 13 item.* keys. - DaySummaryCard: layer-19 modal auto-opens at dusk→night via day_ended, auto-pauses sim, shows day+season header, weather row, stats grid with green/yellow/red tension bar, Continue dismiss + backdrop tap. Settings 'Show end-of-day summary' toggle persists via GameState. - Atmospheric audio: rain ambient loop (Cozy Melodies Pack 6) on weather_changed rain/storm with 0.5s fade-out on clear; thunder sting (Magic and Spells 6) on rain→storm transition; raid warning sting (Sword Pack 1, 'blades drawn') on EventBus.wolf_spawned. All on SFX bus — inherits existing slider + suspend mute. Contracts pre-written before fan-out: EventBus.stockpile_selected / stockpile_deselected / wolf_spawned signals; WolfSpawner._trigger_raid + _on_request_wolf_spawn now emit wolf_spawned with the spawned array. MCP runtime verified: StockpilePanel opens with 21 chips, DaySummaryCard renders weather row + tension bar + auto-pause, rain_player.playing=true on weather_changed(rain), all three new SFX keys in Audio.SFX_FILES. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
2.2 KiB
GDScript
66 lines
2.2 KiB
GDScript
extends Node
|
|
## Top-level mutable game state. SaveSystem serializes via save_dict() / apply_dict().
|
|
##
|
|
## Holds session-wide flags and the "what map are we on" pointer. Per-entity state
|
|
## lives on the entities themselves; per-tile state on the TileMap or World.
|
|
## See docs/architecture.md.
|
|
|
|
var current_map_id: StringName = &"slice_temperate_forest"
|
|
var session_started_at_unix: int = 0 # for "you've been away X minutes" toast
|
|
|
|
# Phase 17 — player settings persisted across sessions.
|
|
# Auto-pause booleans mirror the SettingsMenu checkboxes.
|
|
# Audio floats are 0.0..1.0; default 1.0 (full volume).
|
|
# Accessibility stubs wired in a later phase.
|
|
var settings: Dictionary = {
|
|
"pause_on_threat": true,
|
|
"pause_on_wanderer": true,
|
|
"pause_on_pawn_down": true,
|
|
"pause_on_modal": true,
|
|
"show_day_summary": true,
|
|
"audio_master": 1.0,
|
|
"audio_music": 1.0,
|
|
"audio_sfx": 1.0,
|
|
"audio_ambient": 1.0,
|
|
"accessibility_large_text": false,
|
|
"accessibility_reduce_motion": false,
|
|
}
|
|
|
|
|
|
func _ready() -> void:
|
|
session_started_at_unix = int(Time.get_unix_time_from_system())
|
|
|
|
|
|
## Apply a dictionary of setting values. Unknown keys are silently ignored so
|
|
## callers can pass partial dicts (e.g. only the audio block). Each recognised
|
|
## key is type-coerced to match the default type in `settings`.
|
|
func apply_settings(d: Dictionary) -> void:
|
|
for key in d:
|
|
if not settings.has(key):
|
|
continue
|
|
var default_val = settings[key]
|
|
if default_val is bool:
|
|
settings[key] = bool(d[key])
|
|
elif default_val is float:
|
|
settings[key] = clampf(float(d[key]), 0.0, 1.0)
|
|
else:
|
|
settings[key] = d[key]
|
|
|
|
|
|
# Phase 16 expands these into real save round-trip.
|
|
func save_dict() -> Dictionary:
|
|
return {
|
|
"current_map_id": String(current_map_id),
|
|
"session_started_at_unix": session_started_at_unix,
|
|
"settings": settings.duplicate(),
|
|
}
|
|
|
|
|
|
func apply_dict(d: Dictionary) -> void:
|
|
if d.has("current_map_id"):
|
|
current_map_id = StringName(d["current_map_id"])
|
|
if d.has("session_started_at_unix"):
|
|
session_started_at_unix = int(d["session_started_at_unix"])
|
|
# Phase 17 — restore settings block; partial saves are fine.
|
|
if d.has("settings") and d["settings"] is Dictionary:
|
|
apply_settings(d["settings"])
|