feat(@projects/@magic-civilization): ✨ improve city placement scoring
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
be8cb8e7f2
commit
000cb911f8
2 changed files with 22 additions and 46 deletions
|
|
@ -909,7 +909,7 @@ func _pick_research(player: RefCounted) -> void:
|
|||
|
||||
|
||||
func _score_site(pos: Vector2i, game_map: RefCounted) -> float:
|
||||
## Score a hex as a city site. Food*2 + production*1.5 + resources + mixed-yield bonus.
|
||||
## Score a hex as a city site. Food*2 + production*1.5 + resources.
|
||||
var tile: Resource = game_map.get_tile(pos)
|
||||
if tile == null:
|
||||
return 0.0
|
||||
|
|
@ -918,14 +918,7 @@ func _score_site(pos: Vector2i, game_map: RefCounted) -> float:
|
|||
return 0.0
|
||||
var score: float = 0.0
|
||||
var y: Dictionary = tile.get_yields(-1)
|
||||
var center_food: int = int(y.get("food", 0))
|
||||
var center_prod: int = int(y.get("production", 0))
|
||||
score += float(center_food) * 2.0 + float(center_prod) * 1.5
|
||||
# Heavy penalty for food-starved center biomes (mountain/tundra/desert).
|
||||
if tile.biome_id in ["mountains", "tundra", "desert"]:
|
||||
score -= 5.0
|
||||
var neighbor_food: int = 0
|
||||
var neighbor_prod: int = 0
|
||||
score += float(y.get("food", 0)) * 2.0 + float(y.get("production", 0)) * 1.5
|
||||
for n: Vector2i in HexUtilsScript.get_neighbors(pos):
|
||||
var norm: Vector2i = HexUtilsScript.normalize_position(n, game_map.width, game_map.height, game_map.wrap_mode)
|
||||
var nt: Resource = game_map.get_tile(norm)
|
||||
|
|
@ -934,46 +927,14 @@ func _score_site(pos: Vector2i, game_map: RefCounted) -> float:
|
|||
if nt.biome_id in water:
|
||||
score += 0.5
|
||||
continue
|
||||
if nt.biome_id == "river":
|
||||
score += 2.0
|
||||
var ny: Dictionary = nt.get_yields(-1)
|
||||
var nf: int = int(ny.get("food", 0))
|
||||
var np: int = int(ny.get("production", 0))
|
||||
neighbor_food += nf
|
||||
neighbor_prod += np
|
||||
score += float(nf) * 0.5 + float(np) * 0.3
|
||||
score += float(ny.get("food", 0)) * 0.5 + float(ny.get("production", 0)) * 0.3
|
||||
if nt.resource_id != "":
|
||||
score += 3.0
|
||||
# Mixed-yield reward: at least one food + one prod in neighbors.
|
||||
if neighbor_food >= 1 and neighbor_prod >= 1:
|
||||
score += 2.0
|
||||
score += 2.0
|
||||
return score
|
||||
|
||||
|
||||
func _get_enemy_intel() -> Dictionary:
|
||||
## Scan all enemy players and return aggregate intel.
|
||||
var player: RefCounted = GameState.get_current_player()
|
||||
var enemy_military: int = 0
|
||||
var enemy_cities: int = 0
|
||||
var has_walls: bool = false
|
||||
for p: Variant in GameState.players:
|
||||
if p.index == player.index:
|
||||
continue
|
||||
enemy_cities += p.cities.size()
|
||||
for c: Variant in p.cities:
|
||||
if c.has_building("walls") or c.has_building("castle"):
|
||||
has_walls = true
|
||||
for u: Variant in p.units:
|
||||
if u.is_alive() and u.get("can_found_city") != true:
|
||||
enemy_military += 1
|
||||
return {
|
||||
"military": enemy_military,
|
||||
"cities": enemy_cities,
|
||||
"has_walls": has_walls,
|
||||
}
|
||||
|
||||
|
||||
func _has_founder(player: RefCounted) -> bool:
|
||||
func _has_settler(player: RefCounted) -> bool:
|
||||
for u: Variant in player.units:
|
||||
if u.get("can_found_city") == true and u.is_alive():
|
||||
return true
|
||||
|
|
@ -1192,7 +1153,22 @@ func _command_unit(unit: Variant, player: RefCounted, game_map: RefCounted) -> v
|
|||
_command_worker(unit, player, game_map)
|
||||
return
|
||||
if unit.get("can_found_city") == true:
|
||||
_decide_founder(unit, player, game_map)
|
||||
# Check distance from existing cities
|
||||
var too_close: bool = false
|
||||
for c: Variant in player.cities:
|
||||
if HexUtilsScript.hex_distance(unit.position, c.position) < 5:
|
||||
too_close = true
|
||||
break
|
||||
# Score current tile quality
|
||||
var site_quality: float = _score_site(unit.position, game_map)
|
||||
if too_close or site_quality < 3.0:
|
||||
_explore(unit, player, game_map)
|
||||
else:
|
||||
if _world_map != null and _world_map.has_method("_select_unit"):
|
||||
_world_map._select_unit(unit)
|
||||
if _world_map != null and _world_map.has_method("_on_found_city_pressed"):
|
||||
_world_map._on_found_city_pressed()
|
||||
print(" Founded city at %s (quality=%.1f)" % [unit.position, site_quality])
|
||||
return
|
||||
|
||||
var target_pos: Vector2i = _find_attack_target(player)
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ static func _decide_founder_action(
|
|||
if far_enough_from_own and clear_of_enemies:
|
||||
# Check tile quality — only found if the current tile is decent
|
||||
var quality: float = _score_city_site(unit.position)
|
||||
if quality >= 1.0 or dist_own >= FOUND_MIN_DIST_OWN + 3:
|
||||
if quality >= 3.0 or dist_own >= FOUND_MIN_DIST_OWN + 3:
|
||||
# Good site, or we've wandered far enough — settle here
|
||||
return {
|
||||
"type": "found_city",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue