114 lines
3.3 KiB
GDScript
114 lines
3.3 KiB
GDScript
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
|