class_name SimNPC extends RefCounted const TASK_STATE_IDLE := &"idle" const TASK_STATE_TRAVELING := &"traveling" const TASK_STATE_WORKING := &"working" const TASK_STATE_COMPLETE := &"complete" var id: int var npc_name: String var profession: StringName var hunger: float var energy: float var strength: float var intelligence: float var current_task: StringName = SimulationIds.ACTION_IDLE var task_state: StringName = TASK_STATE_IDLE var position: Vector3 var is_starving := false var starvation_ticks := 0 var starvation_death_threshold := 20 var is_dead := false var task_duration := 0.0 var task_progress := 0.0 var task_complete := true var target_id: StringName = &"" var travel_target_position: Vector3 var has_travel_target := false var inventory: Dictionary = {} var last_task: StringName var random_source: RandomNumberGenerator var debug_logs := true func _init( _id: int, _npc_name: String, _profession: StringName, _strength: float, _intelligence: float, _random_source: RandomNumberGenerator = null ) -> void: id = _id npc_name = _npc_name profession = _profession strength = _strength intelligence = _intelligence random_source = _random_source if random_source == null: random_source = RandomNumberGenerator.new() random_source.seed = id + 1 hunger = random_source.randf_range(20.0, 80.0) energy = random_source.randf_range(40.0, 100.0) position = Vector3( random_source.randf_range(-8.0, 8.0), 0.0, random_source.randf_range(-8.0, 8.0) ) func die_from_starvation() -> void: is_dead = true current_task = SimulationIds.ACTION_DEAD task_state = TASK_STATE_IDLE task_progress = 0.0 task_duration = 0.0 task_complete = true has_travel_target = false if debug_logs: print("[SimNPC] ", npc_name, " died from starvation.") func get_inventory_amount(item_id: StringName) -> float: return float(inventory.get(String(item_id), 0.0)) func add_inventory(item_id: StringName, amount: float) -> void: inventory[String(item_id)] = get_inventory_amount(item_id) + maxf(amount, 0.0) func remove_inventory(item_id: StringName, requested_amount: float) -> float: var removed := minf( maxf(requested_amount, 0.0), get_inventory_amount(item_id) ) inventory[String(item_id)] = get_inventory_amount(item_id) - removed return removed func set_task(action_id: StringName, duration: float = -1.0) -> void: var definition := SimulationDefinitions.get_action(action_id) if definition == null: push_error("SimNPC: unknown action_id '%s'" % action_id) return current_task = action_id task_duration = ( duration if duration >= 0.0 else definition.default_duration ) task_progress = 0.0 task_complete = false task_state = TASK_STATE_TRAVELING has_travel_target = false func start_working() -> void: if task_state != TASK_STATE_TRAVELING: return task_state = TASK_STATE_WORKING task_progress = 0.0 task_complete = false