diff --git a/src/game/engine/src/autoloads/audio_manager.gd b/src/game/engine/src/autoloads/audio_manager.gd index d5c44c10..a003a208 100644 --- a/src/game/engine/src/autoloads/audio_manager.gd +++ b/src/game/engine/src/autoloads/audio_manager.gd @@ -26,6 +26,24 @@ const AUDIO_THEME_DIR_FMT: String = "res://public/games/%s/data/audio" const SILENT_DB: float = -60.0 const UNIT_MOVED_THROTTLE_MSEC: int = 100 +## Maps an EventBus signal name → SFX manifest key. Each entry here turns +## "fire SFX X when signal Y emits" into a single line of data instead of a +## bespoke handler. Signals that need branching (perspective stings, music +## crossfades, owner-aware variants, throttling) get explicit handlers +## below — this table is for the trivial 1:1 cases. +const SIMPLE_ROUTES: Dictionary = { + "turn_started": "turn_started", + "turn_ended": "turn_ended", + "city_founded": "city_founded", + "tech_researched": "tech_researched", + "tech_research_started": "research_start", + "culture_researched": "culture_researched", + "city_grew": "city_grew", + "city_starved": "city_starved", + "city_border_expanded": "border_expanded", + "unit_promoted": "unit_promoted", +} + var _loaded: bool = false var _theme_id: String = "" var _sfx_events: Dictionary = {} @@ -172,25 +190,6 @@ func stop_music() -> void: # --------------------------------------------------------------------------- -## Maps an EventBus signal name → SFX manifest key. Each entry here turns -## "fire SFX X when signal Y emits" into a single line of data instead of a -## bespoke handler. Signals that need branching (perspective stings, music -## crossfades, owner-aware variants, throttling) get explicit handlers -## below — this table is for the trivial 1:1 cases. -const SIMPLE_ROUTES: Dictionary = { - "turn_started": "turn_started", - "turn_ended": "turn_ended", - "city_founded": "city_founded", - "tech_researched": "tech_researched", - "tech_research_started": "research_start", - "culture_researched": "culture_researched", - "city_grew": "city_grew", - "city_starved": "city_starved", - "city_border_expanded": "border_expanded", - "unit_promoted": "unit_promoted", -} - - func _connect_event_bus() -> void: for sig_name: String in SIMPLE_ROUTES.keys(): var sfx_key: String = SIMPLE_ROUTES[sig_name] diff --git a/src/game/engine/src/autoloads/game_state.gd b/src/game/engine/src/autoloads/game_state.gd index 14aa4214..5f6e33ac 100644 --- a/src/game/engine/src/autoloads/game_state.gd +++ b/src/game/engine/src/autoloads/game_state.gd @@ -5,7 +5,7 @@ extends Node const PlayerScript: GDScript = preload("res://engine/src/entities/player.gd") const GameMapScript: GDScript = preload("res://engine/src/map/game_map.gd") const BuildingScript: GDScript = preload("res://engine/src/entities/building.gd") -const _SerializationHelpers: GDScript = preload( +const SerializationHelpers: GDScript = preload( "res://engine/src/autoloads/game_state_serialization_helpers.gd" ) const PersonalityAssignerScript: GDScript = preload( @@ -137,15 +137,6 @@ var ley_edges: Array = [] ## NPC buildings on the world map (lairs, villages, ruins). Array of Building. var npc_buildings: Array = [] -## Spatial index: "col,row" -> Array[Building] for quick tile lookups. -var _npc_buildings_by_tile: Dictionary = {} - -## Cached GdAiController instance (p1-30). Persists across AI turns so the -## Rust-resident TacticalMap is not rebuilt every turn. Reset on new/load game. -## Typed as RefCounted because GdAiController (GDExtension) extends RefCounted. -var _ai_controller: RefCounted = null -## True once set_map() has been called on the cached controller for the current game. -var _ai_map_initialized: bool = false ## Set true by EndGameSummary._on_view_map so world-map input handlers gate out ## player orders. Cleared on new game / load. @@ -160,6 +151,16 @@ var pending_replay_game_id: String = "" ## EndGameSummary._on_watch_replay reads this to seed pending_replay_game_id. var last_archived_game_id: String = "" +## Spatial index: "col,row" -> Array[Building] for quick tile lookups. +var _npc_buildings_by_tile: Dictionary = {} + +## Cached GdAiController instance (p1-30). Persists across AI turns so the +## Rust-resident TacticalMap is not rebuilt every turn. Reset on new/load game. +## Typed as RefCounted because GdAiController (GDExtension) extends RefCounted. +var _ai_controller: RefCounted = null +## True once set_map() has been called on the cached controller for the current game. +var _ai_map_initialized: bool = false + ## Return the process-persistent GdAiController, creating it on first call. ## Returns null when the GDExtension is not loaded (headless/test context). @@ -587,11 +588,11 @@ func deserialize(data: Dictionary) -> void: func _serialize_layer(layer: Dictionary) -> Dictionary: - return _SerializationHelpers.serialize_layer(layer) + return SerializationHelpers.serialize_layer(layer) func _deserialize_layer(layer_data: Dictionary) -> Dictionary: - return _SerializationHelpers.deserialize_layer(layer_data) + return SerializationHelpers.deserialize_layer(layer_data) ## ------------------------------------------------------------------ @@ -626,15 +627,15 @@ func get_player_era(_player_index: int) -> int: func _serialize_ley_anchors() -> Array: - return _SerializationHelpers.serialize_ley_anchors(ley_anchors) + return SerializationHelpers.serialize_ley_anchors(ley_anchors) func _deserialize_ley_anchors(raw: Array) -> void: - ley_anchors = _SerializationHelpers.deserialize_ley_anchors(raw) + ley_anchors = SerializationHelpers.deserialize_ley_anchors(raw) func _serialize_npc_buildings() -> Array: - return _SerializationHelpers.serialize_npc_buildings(npc_buildings) + return SerializationHelpers.serialize_npc_buildings(npc_buildings) func _deserialize_npc_buildings(raw: Array) -> void: diff --git a/src/game/engine/src/modules/empire/culture_web.gd b/src/game/engine/src/modules/empire/culture_web.gd index f6ca5420..b39f22c1 100644 --- a/src/game/engine/src/modules/empire/culture_web.gd +++ b/src/game/engine/src/modules/empire/culture_web.gd @@ -26,11 +26,6 @@ const _CONFIG: Dictionary = { var _web: KnowledgeWebScript = KnowledgeWebScript.new(_CONFIG) - -func build(_traditions: Array) -> void: - _web.build() - - # ── Internal `_nodes` accessor — TurnManager uses it as a "is loaded" probe ─ var _nodes: Dictionary: @@ -38,6 +33,10 @@ var _nodes: Dictionary: return {0: 1} if _web.get_node_count() > 0 else {} +func build(_traditions: Array) -> void: + _web.build() + + # ── Graph queries ─────────────────────────────────────────────────────── func get_pillars() -> Array[String]: diff --git a/src/game/engine/src/rendering/unit_renderer.gd b/src/game/engine/src/rendering/unit_renderer.gd index 74168989..fee4b59a 100644 --- a/src/game/engine/src/rendering/unit_renderer.gd +++ b/src/game/engine/src/rendering/unit_renderer.gd @@ -377,7 +377,7 @@ func _get_unit_sprite(type_id: String, race_id: String, sex: String) -> Texture2 func _build_sprite_key(type_id: String, race_id: String, sex: String) -> String: if race_id != "" and sex != "": return "%s_%s_%s" % [type_id, race_id, sex] - elif race_id != "": + if race_id != "": return "%s_%s" % [type_id, race_id] return type_id diff --git a/src/game/engine/src/world/procedural_renderer.gd b/src/game/engine/src/world/procedural_renderer.gd index a8ff9008..5b23cd98 100644 --- a/src/game/engine/src/world/procedural_renderer.gd +++ b/src/game/engine/src/world/procedural_renderer.gd @@ -322,8 +322,8 @@ static func _fill_triangle( var lx: int = clampi(mini(ax, mini(bx, cx)), 0, w - 1) var rx: int = clampi(maxi(ax, maxi(bx, cx)), 0, w - 1) var ty: int = clampi(mini(ay, mini(by, cy)), 0, h - 1) - var by_: int = clampi(maxi(ay, maxi(by, cy)), 0, h - 1) - for y: int in range(ty, by_ + 1): + var bottom_y: int = clampi(maxi(ay, maxi(by, cy)), 0, h - 1) + for y: int in range(ty, bottom_y + 1): for x: int in range(lx, rx + 1): var s: float = float((bx - ax) * (y - ay) - (by - ay) * (x - ax)) var t: float = float((cx - bx) * (y - by) - (cy - by) * (x - bx))