diff --git a/scenes/ai/construction_provider.gd b/scenes/ai/construction_provider.gd index 2143bf5..fd97669 100644 --- a/scenes/ai/construction_provider.gd +++ b/scenes/ai/construction_provider.gd @@ -48,6 +48,19 @@ func find_best_for(pawn) -> Job: continue if Job.is_target_taken_by_other(site, pawn): continue + # Reachability — same pattern as HaulingProvider. Without this gate, an + # unreachable build site (e.g. a door painted on a tile that already has + # a pre-built wall) is offered every tick, Decision picks it over lower- + # priority work like chop, and JobRunner cancels the doomed walk each + # tick — a busy-spin that starves all elective work. For pathing-blocking + # sites (walls) we check from an adjacent tile; for others, from the tile. + var probe_tile: Vector2i = site.tile + if site.has_method("blocks_pathing_when_complete") and site.blocks_pathing_when_complete(): + probe_tile = _find_adjacent_walkable(site.tile, pawn.tile) + if probe_tile == site.tile: + continue # no walkable neighbour at all → boxed-in site, skip silently + if pawn.tile != probe_tile and World.pathfinder.find_path(pawn.tile, probe_tile).is_empty(): + continue var d: int = abs(site.tile.x - pawn.tile.x) + abs(site.tile.y - pawn.tile.y) if d < best_dist: best_dist = d