TowerGameProto/CitizenManager.gd

114 lines
3.3 KiB
GDScript3
Raw Normal View History

2025-04-16 22:56:14 +01:00
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