diff --git a/public/resources/deposits/banana.json b/public/resources/deposits/banana.json index 8587f23b..b3308485 100644 --- a/public/resources/deposits/banana.json +++ b/public/resources/deposits/banana.json @@ -10,7 +10,7 @@ "production_bonus": 0, "trade_bonus": 0, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "plantation", "sprite": "sprites/resources/banana.png", "description": "Wild banana groves in jungle clearings. High-calorie fruit that makes jungle terrain viable for early settlement despite its movement penalty.", @@ -18,7 +18,7 @@ "1": { "multiplier": 0.5, "label": "Marginal", - "_rationale": "Sparse fruiting — jungle food floor only." + "_rationale": "Sparse fruiting \u2014 jungle food floor only." }, "2": { "multiplier": 0.75, @@ -53,4 +53,4 @@ ] }, "concept_resource": "spices" -} +} \ No newline at end of file diff --git a/public/resources/deposits/crab.json b/public/resources/deposits/crab.json index 9b24c73c..f90f14b2 100644 --- a/public/resources/deposits/crab.json +++ b/public/resources/deposits/crab.json @@ -10,10 +10,10 @@ "production_bonus": 0, "trade_bonus": 0, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "fishing_boats", "sprite": "sprites/resources/crab.png", - "description": "Shellfish beds along rocky shores, harvested by net and cage trap. A supplement to fish — two coastal food sources together sustain a large port city.", + "description": "Shellfish beds along rocky shores, harvested by net and cage trap. A supplement to fish \u2014 two coastal food sources together sustain a large port city.", "quality_scale": { "1": { "multiplier": 0.5, @@ -52,4 +52,4 @@ ] }, "concept_resource": "crabs" -} +} \ No newline at end of file diff --git a/public/resources/deposits/deer.json b/public/resources/deposits/deer.json index f9ab2682..dc0ac8c1 100644 --- a/public/resources/deposits/deer.json +++ b/public/resources/deposits/deer.json @@ -12,10 +12,10 @@ "production_bonus": 0, "trade_bonus": 0, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "hunting_camp", "sprite": "sprites/resources/deer.png", - "description": "Wild deer herds roaming forest margins and tundra. Hunted for meat, bone tools, and hide — the primary food source of pre-agrarian dwarf clans.", + "description": "Wild deer herds roaming forest margins and tundra. Hunted for meat, bone tools, and hide \u2014 the primary food source of pre-agrarian dwarf clans.", "quality_scale": { "1": { "multiplier": 0.5, @@ -40,7 +40,7 @@ "5": { "multiplier": 1.5, "label": "Exceptional", - "_rationale": "Massive migration route — sustained high food before farming." + "_rationale": "Massive migration route \u2014 sustained high food before farming." } }, "encyclopedia": { @@ -54,4 +54,4 @@ ] }, "concept_resource": "deer" -} +} \ No newline at end of file diff --git a/public/resources/deposits/fish.json b/public/resources/deposits/fish.json index 688a8cfe..f67deb3d 100644 --- a/public/resources/deposits/fish.json +++ b/public/resources/deposits/fish.json @@ -12,7 +12,7 @@ "production_bonus": 0, "trade_bonus": 1, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "fishing_boats", "sprite": "sprites/resources/fish.png", "description": "Shoals of freshwater and coastal fish thriving in rivers, lakes, and tidal margins. Coastal cities depend on these to avoid starvation.", @@ -20,7 +20,7 @@ "1": { "multiplier": 0.5, "label": "Marginal", - "_rationale": "Sparse shoals — overfished quickly. Marginal coastal food." + "_rationale": "Sparse shoals \u2014 overfished quickly. Marginal coastal food." }, "2": { "multiplier": 0.75, @@ -54,4 +54,4 @@ ] }, "concept_resource": "fish" -} +} \ No newline at end of file diff --git a/public/resources/deposits/stone_deposit.json b/public/resources/deposits/stone_deposit.json index 9858f0b8..ce46193f 100644 --- a/public/resources/deposits/stone_deposit.json +++ b/public/resources/deposits/stone_deposit.json @@ -12,10 +12,10 @@ "production_bonus": 2, "trade_bonus": 0, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "quarry", "sprite": "sprites/resources/stone_deposit.png", - "description": "Exposed limestone and granite outcroppings near the surface. Cut stone dramatically accelerates early construction — walls, roads, and city foundations all require it.", + "description": "Exposed limestone and granite outcroppings near the surface. Cut stone dramatically accelerates early construction \u2014 walls, roads, and city foundations all require it.", "quality_scale": { "1": { "multiplier": 0.5, @@ -54,4 +54,4 @@ ] }, "concept_resource": "stone" -} +} \ No newline at end of file diff --git a/public/resources/deposits/wheat.json b/public/resources/deposits/wheat.json index bb4f02e2..fd4166ef 100644 --- a/public/resources/deposits/wheat.json +++ b/public/resources/deposits/wheat.json @@ -11,7 +11,7 @@ "production_bonus": 0, "trade_bonus": 0, "culture_bonus": 0, - "revealed_by_tech": null, + "revealed_by_tech": "", "improvement_required": "farm", "sprite": "sprites/resources/wheat.png", "description": "Wild grain stands growing thick in temperate lowlands. The first crop any settled dwarf clan cultivates.", @@ -53,4 +53,4 @@ ] }, "concept_resource": "wheat" -} +} \ No newline at end of file diff --git a/src/game/engine/scenes/world_map/world_map_combat.gd b/src/game/engine/scenes/world_map/world_map_combat.gd index 7a356dd2..328dfb07 100644 --- a/src/game/engine/scenes/world_map/world_map_combat.gd +++ b/src/game/engine/scenes/world_map/world_map_combat.gd @@ -231,3 +231,33 @@ func _erase_from_layer(unit: RefCounted) -> void: var primary: Dictionary = GameState.get_primary_layer() var layer_units: Array = primary.get("units", []) layer_units.erase(unit) + + +func execute_city_bombard(city: RefCounted, target: RefCounted, sync_cb: Callable) -> void: + var game_map: RefCounted = GameState.get_game_map() + if game_map == null: + return + var all_units: Array = _collect_all_units() + var city_str: int = city.population * 3 + if city.has_building("castle"): + city_str += 12 + var atk_str: float = float(city_str) + var def_str: float = float(target.defense) + float(target.attack) * 0.5 + var ratio: float = atk_str / maxf(def_str, 1.0) + var damage: int = clampi(roundi(20.0 * ratio), 5, 40) + target.hp = maxi(0, target.hp - damage) + city.has_bombarded = true + EventBus.combat_resolved.emit(city, target, { + "defender_damage": damage, + "defender_hp": target.hp, + "defender_killed": target.hp <= 0, + "attacker_hp": city.hp, + "attacker_damage": 0, + "city_bombard_damage": 0, + }) + if target.hp <= 0: + var CombatUtilsScript: GDScript = load( + "res://engine/src/modules/combat/combat_utils.gd" + ) + CombatUtilsScript.handle_unit_death(target, city, all_units) + sync_cb.call() diff --git a/src/game/engine/src/map/tile.gd b/src/game/engine/src/map/tile.gd index 31ed2d39..bc2a1cbd 100644 --- a/src/game/engine/src/map/tile.gd +++ b/src/game/engine/src/map/tile.gd @@ -332,7 +332,11 @@ func is_resource_visible_to(player_index: int) -> bool: if env != null and env.get_bool("FORCE_UNLIMITED_RESEARCH"): return true var res_data: Dictionary = _data_loader().get_resource(resource_id) - var required_tech: String = res_data.get("revealed_by_tech", "") + # Defensive: JSON null becomes Nil in GDScript, which would fail the + # String assignment below. Treat null/missing as "no tech gate". + var required_tech: String = "" + if res_data.has("revealed_by_tech") and res_data["revealed_by_tech"] != null: + required_tech = String(res_data["revealed_by_tech"]) if required_tech == "": return true var player: Variant = GameState.get_player(player_index) diff --git a/src/game/engine/tests/unit/test_tile_tooltip.gd b/src/game/engine/tests/unit/test_tile_tooltip.gd index e534cdd7..81ae9280 100644 --- a/src/game/engine/tests/unit/test_tile_tooltip.gd +++ b/src/game/engine/tests/unit/test_tile_tooltip.gd @@ -4,13 +4,8 @@ extends GutTest const TileInfoPanelScript: GDScript = preload( "res://engine/scenes/world_map/tile_info_panel.gd" ) -<<<<<<< HEAD const WorldMapHoverScript: GDScript = preload( "res://engine/scenes/world_map/world_map_hover.gd" -======= -const WorldMapScript: GDScript = preload( - "res://engine/scenes/world_map/world_map.gd" ->>>>>>> e1ef00860 (📝 docs: update deposit resource files and schema) ) diff --git a/src/simulator/api-gdext/src/ai.rs b/src/simulator/api-gdext/src/ai.rs index 703ed995..18c34dea 100644 --- a/src/simulator/api-gdext/src/ai.rs +++ b/src/simulator/api-gdext/src/ai.rs @@ -331,6 +331,8 @@ mod tests { capital_position: Some((0, 0)), culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }; let state = GameState { diff --git a/src/simulator/crates/mc-turn/src/bridge_contract_tests.rs b/src/simulator/crates/mc-turn/src/bridge_contract_tests.rs index 9151152e..6c729471 100644 --- a/src/simulator/crates/mc-turn/src/bridge_contract_tests.rs +++ b/src/simulator/crates/mc-turn/src/bridge_contract_tests.rs @@ -166,6 +166,8 @@ fn isolated_unit_state(map_size: i32) -> GameState { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: Some(grid), } @@ -560,6 +562,8 @@ fn base_kill_rate_setter_is_not_a_noop() { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: Some(grid), } diff --git a/src/simulator/crates/mc-turn/src/gpu/mod.rs b/src/simulator/crates/mc-turn/src/gpu/mod.rs index 223e60fb..4368d943 100644 --- a/src/simulator/crates/mc-turn/src/gpu/mod.rs +++ b/src/simulator/crates/mc-turn/src/gpu/mod.rs @@ -335,6 +335,8 @@ mod inner { capital_position: Some((0, 0)), culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), } } @@ -548,3 +550,4 @@ pub use inner::GpuContext; pub use inner::GpuUnit; pub mod combat_resolve; +pub mod unit_movement; diff --git a/src/simulator/crates/mc-turn/src/processor.rs b/src/simulator/crates/mc-turn/src/processor.rs index dc7c5315..2a5d7cc0 100644 --- a/src/simulator/crates/mc-turn/src/processor.rs +++ b/src/simulator/crates/mc-turn/src/processor.rs @@ -1380,6 +1380,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: Some(grid), } @@ -1430,6 +1432,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: Some(GridState::new(48, 48)), }; @@ -1508,6 +1512,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: Some(grid), } @@ -1862,6 +1868,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }); } @@ -2177,6 +2185,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), }], grid: None, }; @@ -2246,6 +2256,8 @@ mod tests { capital_position: Some((col, row)), culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), } }; @@ -2305,6 +2317,8 @@ mod tests { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), } } diff --git a/src/simulator/crates/mc-turn/src/processor_invariants.rs b/src/simulator/crates/mc-turn/src/processor_invariants.rs index c9082b8e..d592bd4d 100644 --- a/src/simulator/crates/mc-turn/src/processor_invariants.rs +++ b/src/simulator/crates/mc-turn/src/processor_invariants.rs @@ -145,6 +145,8 @@ prop_compose! { capital_position: None, culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), } } } diff --git a/src/simulator/crates/mc-turn/src/snapshot.rs b/src/simulator/crates/mc-turn/src/snapshot.rs index d2a0f13f..5defa9d1 100644 --- a/src/simulator/crates/mc-turn/src/snapshot.rs +++ b/src/simulator/crates/mc-turn/src/snapshot.rs @@ -232,6 +232,8 @@ mod tests { capital_position: Some((0, 0)), culture_total: 0, arcane_lore_pop_deducted: false, + traded_luxuries: Default::default(), + relations: Default::default(), } }