class_name ConstructionProvider extends WorkProvider ## WorkProvider for the "construction" work category. ## ## Scans World.build_queue for the nearest buildable site (Wall, Floor, Door — ## anything exposing is_buildable() / on_build_tick() / tile / label()) and ## returns a two-toil Job: ## walk_to(site.tile) → build_at(site.get_path()) ## ## The BUILD toil calls on_build_tick() once per sim tick; the entity internally ## tracks build_progress and calls _complete() when BUILD_TICKS is reached. The ## toil finishes automatically when is_buildable() returns false. ## ## Phase 5 simplification: materials are infinite — no haul-materials step. ## Phase 6+ will prepend walk_to(material_pile) + pickup() toils before walk_to(site). ## ## Duck-typing note: build-site entities are referenced without class_name to ## avoid registration-order issues. We rely only on: ## site.tile: Vector2i ## site.is_buildable() -> bool ## site.label() -> String ## site.get_path() -> NodePath func _init() -> void: category = &"construction" # Higher than chop (5), mine (4), haul (3), rest (0). Players expect their # build orders to be serviced before the pawn goes off to chop trees. priority = 6 ## Returns a Job targeting the nearest buildable site, or null if none exists. ## `pawn` is duck-typed: must expose .tile (Vector2i). func find_best_for(pawn) -> Job: var best = null var best_dist: int = 999999 for site in World.build_queue: if not site.is_buildable(): 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 best = site if best == null: return null var j := Job.new() j.label = "Build %s at %s" % [best.label(), best.tile] j.toils.append(Toil.walk_to(best.tile)) j.toils.append(Toil.build_at(best.get_path())) return j