feat: enforce activity site capacity

This commit is contained in:
2026-07-07 16:12:13 +02:00
parent 9d87372a15
commit 1c389ec23d
7 changed files with 87 additions and 26 deletions
+12
View File
@@ -395,6 +395,18 @@ func synchronize_npc_position(npc_id: int, active_position: Vector3) -> bool:
return false
func get_activity_target_claim_count(target_id: StringName, except_npc_id: int = -1) -> int:
var count := 0
for npc in npcs:
if npc.id == except_npc_id or npc.is_dead:
continue
if npc.target_id != target_id:
continue
if npc.task_state in [SimNPC.TASK_STATE_TRAVELING, SimNPC.TASK_STATE_WORKING]:
count += 1
return count
func _npc_inventory_id(npc_id: int) -> StringName:
return StringName("npc_%d_inventory" % npc_id)
+31 -1
View File
@@ -14,7 +14,7 @@ func resolve(
npc, origin, definition, simulation_manager, active_world_adapter
)
SimulationIds.TARGET_ACTIVITY:
return active_world_adapter.get_activity_target(npc.current_task, origin)
return _resolve_activity(npc, origin, simulation_manager, active_world_adapter)
SimulationIds.TARGET_FREE:
return {
"target_id": "", "position": origin + simulation_manager.get_wander_offset(npc.id)
@@ -49,6 +49,36 @@ func _resolve_resource(
return best
func _resolve_activity(
npc: SimNPC, origin: Vector3, simulation_manager: Node, active_world_adapter: Node
) -> Dictionary:
if not active_world_adapter.has_method("get_activity_candidates"):
return active_world_adapter.get_activity_target(npc.current_task, origin)
var best: Dictionary = {}
var best_distance := INF
var candidates: Array[Dictionary] = active_world_adapter.get_activity_candidates(npc.current_task)
for candidate in candidates:
var target_id := StringName(candidate["target_id"])
var capacity := maxi(int(candidate.get("capacity", 1)), 1)
if (
simulation_manager.has_method("get_activity_target_claim_count")
and simulation_manager.get_activity_target_claim_count(target_id, npc.id) >= capacity
):
continue
var position: Vector3 = candidate["position"]
var distance := origin.distance_squared_to(position)
if distance < best_distance:
best_distance = distance
best = candidate
if not best.is_empty():
return best
if not candidates.is_empty():
return {}
return active_world_adapter.get_activity_target(npc.current_task, origin)
func score_resource_candidate(
npc: SimNPC, origin: Vector3, position: Vector3, state: ResourceStateRecord
) -> float: