diff --git a/src/game/engine/src/autoloads/turn_manager.gd b/src/game/engine/src/autoloads/turn_manager.gd index 49e1b4be..f19abc81 100644 --- a/src/game/engine/src/autoloads/turn_manager.gd +++ b/src/game/engine/src/autoloads/turn_manager.gd @@ -293,6 +293,14 @@ func next_player() -> void: var fauna_grid: RefCounted = climate_node.get("_grid") as RefCounted if fauna_grid != null: EcologyState.tick(fauna_grid, GameState.map_seed + GameState.turn_number) + # Increment 3b: world-event dispatch (geological / biological / + # anomalous) against the SAME live grid, after climate + ecology + # ticks. Accumulates per-tile eco-damage into WorldsimState's + # eco_map (persisted in the save). Production thresholds make + # events deliberately rare; this is the missing worldsim layer. + WorldsimState.dispatch( + fauna_grid, GameState.turn_number, GameState.map_seed + ) GameState.current_player_index = 0 GameState.turn_number += 1 # Check victory conditions after all players have moved diff --git a/src/game/engine/src/autoloads/worldsim_state.gd b/src/game/engine/src/autoloads/worldsim_state.gd new file mode 100644 index 00000000..03de1979 --- /dev/null +++ b/src/game/engine/src/autoloads/worldsim_state.gd @@ -0,0 +1,76 @@ +extends Node + +## Session-scoped GdWorldSim singleton (Increment 3b). +## +## Owns the continuous-worldsim EVENT layer that runs after the per-turn climate +## + ecology ticks: geological / biological / anomalous event dispatch, which +## accumulates per-tile eco-damage into an owned `eco_map`. This is the layer +## the live `turn_manager.gd::next_player()` was missing — climate and ecology +## (incl. migration) already tick via ClimatePhysics + EcologyState, but no +## world events fired in-game. +## +## Lifecycle: +## _ready() → reset() builds a fresh GdWorldSim + loads thresholds +## dispatch(grid, seed) → one world-event pass against the LIVE grid +## (read-modify-write; see GdWorldSim::dispatch_on_grid) +## to_save_json()/restore_from_save_json() → eco_map save round-trip +## +## Thresholds are loaded from the canonical JSON pack (Rail 2) at production +## rates — events are deliberately rare (~0.003/turn seismic). Proof scenes / +## tests boost thresholds so events fire reliably in a short run. + +const GEO_THRESHOLDS_PATH: String = "res://public/resources/events/geological_thresholds.json" +const BIO_THRESHOLDS_PATH: String = ( + "res://public/games/age-of-dwarves/data/balance/biological_events.json" +) + +var worldsim: RefCounted = null + + +func _ready() -> void: + reset() + + +## Discard the current GdWorldSim and build a fresh one with production +## thresholds loaded. Called on new game / load so eco_map does not carry across +## sessions (the saved eco_map is injected via restore_from_save_json on load). +func reset() -> void: + if not ClassDB.class_exists("GdWorldSim"): + worldsim = null + return + worldsim = ClassDB.instantiate("GdWorldSim") as RefCounted + var geo: String = FileAccess.get_file_as_string(GEO_THRESHOLDS_PATH) + var bio: String = FileAccess.get_file_as_string(BIO_THRESHOLDS_PATH) + # Anomalous has no authored JSON yet — pass "" to keep Rust Default. + worldsim.call("load_thresholds_from_json", geo, bio, "") + + +## Run one world-event dispatch pass against the live shared grid. Caller is +## `turn_manager.gd::next_player()` after the climate + ecology ticks. Returns +## the number of events dispatched this turn. +func dispatch(grid: RefCounted, turn: int, seed: int) -> int: + if worldsim == null or grid == null: + return 0 + return int(worldsim.call("dispatch_on_grid", grid, turn, seed)) + + +## Serialize the eco-damage map for the save envelope. Empty string when no +## worldsim is active. +func to_save_json() -> String: + if worldsim == null: + return "" + return String(worldsim.call("eco_map_to_json")) + + +## Restore the eco-damage map from a save envelope payload. No-op on empty input. +func restore_from_save_json(json: String) -> void: + if worldsim == null or json.is_empty(): + return + worldsim.call("restore_eco_map_from_json", json) + + +## Tiles carrying accumulated eco-damage — cheap probe for HUD / tests. +func eco_damage_tile_count() -> int: + if worldsim == null: + return 0 + return int(worldsim.call("eco_map_len")) diff --git a/src/game/engine/src/autoloads/worldsim_state.gd.uid b/src/game/engine/src/autoloads/worldsim_state.gd.uid new file mode 100644 index 00000000..df590a7a --- /dev/null +++ b/src/game/engine/src/autoloads/worldsim_state.gd.uid @@ -0,0 +1 @@ +uid://b8d8hc2h052uk