feat: authoritative extraction from ResourceNode on task completion

Phase 3 of ResourceNode migration:
- Add apply_resource_delta to SimVillage for clean resource changes
- Extract from reserved ResourceNode on task completion instead of
  hard-coded apply_npc_task for gather_food/gather_wood
- Detect depleted/unavailable targets on arrival and replan
This commit is contained in:
2026-07-03 18:32:34 +02:00
parent 0dfaa06f9c
commit c6033b63fb
2 changed files with 37 additions and 1 deletions
+19
View File
@@ -69,6 +69,25 @@ func update_priorities() -> void:
if DEBUG_LOGS: if DEBUG_LOGS:
print(get_priority_summary()) print(get_priority_summary())
func apply_resource_delta(resource_id: StringName, amount: float) -> void:
match resource_id:
&"food":
food += amount
&"wood":
wood += amount
&"safety":
safety = clamp(safety + amount, 0.0, 100.0)
&"knowledge":
knowledge += amount
food = max(food, 0.0)
wood = max(wood, 0.0)
safety = clamp(safety, 0.0, 100.0)
knowledge = max(knowledge, 0.0)
update_modifiers()
update_priorities()
func apply_npc_task(npc: SimNPC) -> void: func apply_npc_task(npc: SimNPC) -> void:
if npc.is_dead: if npc.is_dead:
return return
+18 -1
View File
@@ -86,9 +86,17 @@ func simulate_tick() -> void:
var needs_immediate_food_after_gather := npc.should_eat_immediately_after_task() var needs_immediate_food_after_gather := npc.should_eat_immediately_after_task()
if npc.target_id != &"": if npc.target_id != &"":
var node := ResourceNode.get_by_id(npc.target_id)
if node != null:
var extracted := node.extract()
if extracted > 0:
village.apply_resource_delta(node.resource_id, extracted)
if DEBUG_LOGS:
print("[SimulationManager] ", npc.npc_name, " extracted ", extracted, " ", node.resource_id, " from ", node.node_id)
release_npc_reservation(npc.id) release_npc_reservation(npc.id)
else:
village.apply_npc_task(npc) village.apply_npc_task(npc)
village_was_changed = true village_was_changed = true
npc.task_complete = true npc.task_complete = true
@@ -161,6 +169,15 @@ func notify_npc_arrived(npc_id: int) -> void:
return return
if npc.task_state == SimNPC.TASK_STATE_TRAVELING: if npc.task_state == SimNPC.TASK_STATE_TRAVELING:
if npc.target_id != &"":
var node := ResourceNode.get_by_id(npc.target_id)
if node == null or not node.can_extract():
if DEBUG_LOGS:
print("[SimulationManager] ", npc.npc_name, " arrived but target ", npc.target_id, " is unavailable, replanning")
release_npc_reservation(npc.id)
npc.task_state = SimNPC.TASK_STATE_IDLE
return
npc.start_working() npc.start_working()
if DEBUG_LOGS: if DEBUG_LOGS: