diff --git a/src/game/engine/scenes/tests/auto_play.gd b/src/game/engine/scenes/tests/auto_play.gd index a267d4ee..b8aaabc2 100644 --- a/src/game/engine/scenes/tests/auto_play.gd +++ b/src/game/engine/scenes/tests/auto_play.gd @@ -1424,6 +1424,64 @@ func _next_building(city: Variant, player: Variant, city_count: int, has_founder best_wonder = bid if not best_wonder.is_empty(): return best_wonder + # p0-39: upgrade `warrior` to the highest-tier buildable melee unit for + # this player. Makes tier progression emergent — pikeman replaces warrior + # once bronze_working unlocks; cavalry replaces pikeman once steelworking + # AND iron_ore both land; berserker/ironwarden/forge_titan/mithril_vanguard + # for dwarf clans as their tech chain progresses. + if best_id == "warrior": + var upgrade: String = _best_melee_for_player(player, city) + if not upgrade.is_empty() and upgrade != "warrior": + best_id = upgrade + return best_id + + +func _best_melee_for_player(player: RefCounted, city: Variant) -> String: + # Highest-tier buildable melee unit per p0-39 rules: + # - unit_type == "military" AND not in the ranged-specialist set + # - tech_required satisfied (player.has_tech) if set + # - requires_resource satisfied (BuildableHelper) if set + # - race_required matches player.race_id if set + # Returns "warrior" when no higher-tier candidate qualifies. + var best_id: String = "warrior" + var best_tier: int = 1 + var ranged_keywords: Array[String] = [ + "archer", "ranger", "arbalest", "crossbow", "flying", "catapult", "ballista", + ] + for u: Dictionary in DataLoader.get_all_units(): + var uid: String = str(u.get("id", "")) + if uid.is_empty(): + continue + var unit_type: String = str(u.get("unit_type", "")) + if unit_type != "military": + continue + var is_ranged: bool = false + for kw: String in ranged_keywords: + if uid.contains(kw): + is_ranged = true + break + if is_ranged: + continue + var tier: int = int(u.get("tier", 1)) + if tier <= best_tier: + continue + var tech_req: String = str(u.get("tech_required", "")) + if not tech_req.is_empty() and tech_req != "" and not player.has_tech(tech_req): + continue + var race_req: String = str(u.get("race_required", "")) + if not race_req.is_empty() and race_req != "": + var player_race: String = str(player.race_id) if "race_id" in player else "" + if race_req != player_race: + continue + var res_req: String = str(u.get("requires_resource", "")) + if not res_req.is_empty() and res_req != "": + if not BuildableHelperScript.player_owns_resource(player, res_req): + continue + # Also require the engine agrees this city can build it. + if not city.can_build(uid, player): + continue + best_tier = tier + best_id = uid return best_id