feat(@projects/@magic-civilization): add melee unit upgrade logic

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-18 18:31:44 -07:00
parent c9424f1a09
commit 0dae7341fc

View file

@ -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 != "<null>" 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 != "<null>":
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 != "<null>":
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