feat: add location-based food storage loop

This commit is contained in:
2026-07-05 17:57:24 +02:00
parent 3ea8f02d55
commit 6dbb395bd6
22 changed files with 469 additions and 72 deletions
+107 -19
View File
@@ -22,6 +22,7 @@ var clock: SimulationClock
var tick_count := 0
var wander_random_sources := {}
var resource_states: Dictionary = {}
var storage_states: Dictionary = {}
var action_selector := ActionSelectionSystem.new()
var action_executor := ActionExecutionSystem.new()
var target_resolver := ActionTargetResolver.new()
@@ -40,6 +41,7 @@ func _ready() -> void:
return
clock = SimulationClock.new(tick_interval)
village.debug_logs = debug_logs
_initialize_storage()
village.update_modifiers()
village.update_priorities()
generate_npcs()
@@ -140,9 +142,14 @@ func simulate_tick() -> void:
if not was_complete and npc.task_complete and not npc.is_dead:
var completed_task := npc.current_task
var needs_immediate_food_after_gather := npc.should_eat_immediately_after_task()
if npc.target_id != &"":
var completed_definition := SimulationDefinitions.get_action(
completed_task
)
if (
npc.target_id != &""
and completed_definition != null
and completed_definition.target_type == SimulationIds.TARGET_RESOURCE
):
var resource_state := get_resource_state(npc.target_id)
if (
resource_state != null
@@ -150,10 +157,16 @@ func simulate_tick() -> void:
):
var extracted := resource_state.extract()
if extracted > 0:
village.apply_resource_delta(
resource_state.get_resource_id(),
extracted
)
if resource_state.get_resource_id() == SimulationIds.RESOURCE_FOOD:
npc.add_inventory(
SimulationIds.RESOURCE_FOOD,
extracted
)
else:
village.apply_resource_delta(
resource_state.get_resource_id(),
extracted
)
if debug_logs:
print(
"[SimulationManager] ",
@@ -168,6 +181,12 @@ func simulate_tick() -> void:
elif debug_logs:
print("[SimulationManager] ", npc.npc_name, " could not complete ", completed_task, ": target reservation was invalid")
release_npc_reservation(npc.id)
elif completed_task == SimulationIds.ACTION_DEPOSIT_FOOD:
deposit_npc_inventory(npc, SimulationIds.RESOURCE_FOOD)
elif completed_task == SimulationIds.ACTION_WITHDRAW_FOOD:
withdraw_to_npc(npc, SimulationIds.RESOURCE_FOOD, 1.0)
elif completed_task == SimulationIds.ACTION_EAT:
consume_npc_food(npc)
elif completed_task not in [
SimulationIds.ACTION_GATHER_FOOD,
SimulationIds.ACTION_GATHER_WOOD
@@ -183,14 +202,7 @@ func simulate_tick() -> void:
npc.last_task = completed_task
npc.current_task = SimulationIds.ACTION_IDLE
npc.has_travel_target = false
if needs_immediate_food_after_gather and village.food > 0:
npc.set_task(SimulationIds.ACTION_EAT, 1.0)
npc_task_changed.emit(npc, completed_task, npc.current_task)
npc_target_requested.emit(npc)
if debug_logs:
print("[SimulationManager] ", npc.npc_name, " gathered food while starving and is going to eat immediately.")
npc.target_id = &""
if debug_logs:
print(
@@ -251,7 +263,14 @@ func notify_npc_arrived(npc_id: int) -> void:
return
if npc.task_state == SimNPC.TASK_STATE_TRAVELING:
if npc.target_id != &"":
var definition := SimulationDefinitions.get_action(
npc.current_task
)
if (
npc.target_id != &""
and definition != null
and definition.target_type == SimulationIds.TARGET_RESOURCE
):
var resource_state := get_resource_state(npc.target_id)
if (
resource_state == null
@@ -336,6 +355,57 @@ func synchronize_npc_position(npc_id: int, active_position: Vector3) -> bool:
return true
return false
func _initialize_storage() -> void:
if storage_states.has(SimulationIds.STORAGE_VILLAGE_PANTRY):
_sync_village_food()
return
storage_states[SimulationIds.STORAGE_VILLAGE_PANTRY] = (
StorageStateRecord.create(
SimulationIds.STORAGE_VILLAGE_PANTRY,
{String(SimulationIds.RESOURCE_FOOD): village.food}
)
)
_sync_village_food()
func get_pantry() -> StorageStateRecord:
return storage_states.get(
SimulationIds.STORAGE_VILLAGE_PANTRY
) as StorageStateRecord
func _sync_village_food() -> void:
var pantry := get_pantry()
if pantry != null:
village.food = pantry.get_amount(SimulationIds.RESOURCE_FOOD)
village.update_modifiers()
village.update_priorities()
func deposit_npc_inventory(npc: SimNPC, item_id: StringName) -> float:
var available := npc.get_inventory_amount(item_id)
var deposited := get_pantry().deposit(item_id, available)
npc.remove_inventory(item_id, deposited)
_sync_village_food()
return deposited
func withdraw_to_npc(
npc: SimNPC,
item_id: StringName,
amount: float
) -> float:
var withdrawn := get_pantry().withdraw(item_id, amount)
npc.add_inventory(item_id, withdrawn)
_sync_village_food()
return withdrawn
func consume_npc_food(npc: SimNPC) -> bool:
if npc.remove_inventory(SimulationIds.RESOURCE_FOOD, 1.0) < 1.0:
npc.hunger = minf(npc.hunger + 5.0, 100.0)
npc.is_starving = npc.hunger >= 90.0
return false
npc.hunger = maxf(npc.hunger - 55.0, 0.0)
npc.starvation_ticks = 0
npc.is_starving = npc.hunger >= 90.0
return true
func register_loaded_resource_nodes() -> void:
for node in ResourceNode.get_all():
register_resource_node(node)
@@ -409,7 +479,11 @@ func harvest_resource_node(node: ResourceNode) -> float:
if extracted <= 0.0:
return 0.0
village.apply_resource_delta(resource_state.get_resource_id(), extracted)
if resource_state.get_resource_id() == SimulationIds.RESOURCE_FOOD:
get_pantry().deposit(SimulationIds.RESOURCE_FOOD, extracted)
_sync_village_food()
else:
village.apply_resource_delta(resource_state.get_resource_id(), extracted)
village_changed.emit(village)
if debug_logs:
@@ -425,11 +499,16 @@ func harvest_resource_node(node: ResourceNode) -> float:
return extracted
func eat_food(amount: float) -> void:
village.apply_resource_delta(&"food", -amount)
get_pantry().withdraw(SimulationIds.RESOURCE_FOOD, amount)
_sync_village_food()
village_changed.emit(village)
func add_food(amount: float) -> void:
village.apply_resource_delta(&"food", amount)
if amount >= 0.0:
get_pantry().deposit(SimulationIds.RESOURCE_FOOD, amount)
else:
get_pantry().withdraw(SimulationIds.RESOURCE_FOOD, -amount)
_sync_village_food()
village_changed.emit(village)
func add_wood(amount: float) -> void:
@@ -523,6 +602,11 @@ func create_state_record() -> SimulationStateRecord:
for resource_id in sorted_resource_ids:
var resource_state: ResourceStateRecord = resource_states[resource_id]
record.resources.append(resource_state)
var sorted_storage_ids: Array = storage_states.keys()
sorted_storage_ids.sort()
for storage_id in sorted_storage_ids:
var storage_state: StorageStateRecord = storage_states[storage_id]
record.storages.append(storage_state)
return record
func serialize_state() -> String:
@@ -546,6 +630,10 @@ func restore_state(record: SimulationStateRecord) -> bool:
clock.accumulator = float(record.simulation["clock_accumulator"])
clock.elapsed_ticks = int(record.simulation["clock_elapsed_ticks"])
village = record.village.restore(debug_logs)
storage_states.clear()
for storage_record in record.storages:
storage_states[storage_record.get_storage_id()] = storage_record
_sync_village_food()
npcs.clear()
for npc_record in record.npcs: