extends Node class_name CitizenManager @export var task_assignment_rate: float = 100 var task_assignment_budget: float = 0 #signal task_queue_updated(task_queue: Array[Task]) var task_queue: Array[Task] = [] const FLOAT64_MAX: float = 2.0**1023 * (2 - 2.0**-52) func _process(delta: float) -> void: task_assignment_budget += task_assignment_rate * delta if task_assignment_budget >= task_assignment_rate: task_assignment_budget = task_assignment_rate var idle_workers: Array[Citizen] = [] for worker in get_tree().get_nodes_in_group("Citizens"): if worker.is_idle(): idle_workers.append(worker) #idle_workers.shuffle() while !idle_workers.is_empty() and !task_queue.is_empty() and task_assignment_budget > 0: var task: Task = task_queue.pop_front() task_assignment_budget -= 1 if task.is_ready(): # TODO: this currently assigns to the first worker found var worker: Citizen = idle_workers.pop_front() worker.assign_task(task) else: add_task(task) func remove_task(task: Task): var idx: int = task_queue.find(task) if idx >= 0: task_queue.remove_at(idx) func add_task(task: Task): var idx: int = task_queue.bsearch_custom(task, sort_tasks, false) task_queue.insert(idx, task) func sort_tasks(a: Task,b: Task) -> bool: return a.priority > b.priority const TASK_PRIORITY_ANYTIME = 0 const TASK_PRIORITY_BY_WAVE_START = 10 const TASK_PRIORITY_ASAP = 20 class Task: var priority: int = TASK_PRIORITY_ANYTIME func get_task_name() -> String: return "Task" func is_ready() -> bool: return true func get_location() -> Vector2: return Vector2() func execute(worker: Citizen) -> bool: return false func interrupt(worker: Citizen) -> void: pass func cancel(worker: Citizen) -> void: pass class BuildTask extends Task: var building: Building func _init() -> void: priority = 1 func get_task_name() -> String: return "Build " + building.name func is_ready() -> bool: return super() and building.can_build() func get_location() -> Vector2: return building.global_position func execute(worker: Citizen) -> bool: var ok: bool = true ok = await worker.go_to_destination(building.position) if !ok: return false building.build() return true class FetchItemTask extends Task: var building: Building var item: Item func get_task_name() -> String: return "Transfer " + item.name + " to " + building.name func execute(worker: Citizen) -> bool: # find the item from nearby buildings # TODO: also look for items on the floor? var storage_building: Machine = null var closest: float = FLOAT64_MAX for machine in worker.get_tree().get_nodes_in_group("Buildings"): if machine is Machine: if machine.stored_items.has(item): var distance_sqr: float = machine.position.distance_squared_to(worker.position) if distance_sqr < closest: storage_building = machine closest = distance_sqr if storage_building == null: return false # go to the storage if !await worker.go_to_destination(storage_building.global_position): return false # pick up the item if !await worker.pickup_item_from_building(item, storage_building): return false # carry the item to the construction site if !await worker.go_to_destination(building.global_position): return false # store the item in the construction site if !await worker.store_item_in_contruction_site(building): return false return true