feat: add physical animal care delivery
This commit is contained in:
@@ -119,6 +119,61 @@ func can_complete_feed(animal_id: StringName, agent_id: int) -> bool:
|
||||
)
|
||||
|
||||
|
||||
func requires_feed_pickup(npc: SimNPC) -> bool:
|
||||
var definition := SimulationDefinitions.get_action(SimulationIds.ACTION_FEED_ANIMAL)
|
||||
return (
|
||||
npc != null
|
||||
and definition != null
|
||||
and definition.has_completion_cost()
|
||||
and (
|
||||
npc.get_inventory_amount(definition.completion_cost_resource_id)
|
||||
< definition.completion_cost_amount
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func requires_working_feed_recovery(npc: SimNPC) -> bool:
|
||||
return (
|
||||
npc != null
|
||||
and npc.current_task == SimulationIds.ACTION_FEED_ANIMAL
|
||||
and npc.task_state == SimNPC.TASK_STATE_WORKING
|
||||
and requires_feed_pickup(npc)
|
||||
and can_complete_feed(npc.target_id, npc.id)
|
||||
)
|
||||
|
||||
|
||||
func collect_feed_supply(npc: SimNPC) -> bool:
|
||||
var definition := SimulationDefinitions.get_action(SimulationIds.ACTION_FEED_ANIMAL)
|
||||
if (
|
||||
npc == null
|
||||
or npc.current_task != SimulationIds.ACTION_FEED_ANIMAL
|
||||
or npc.target_id.is_empty()
|
||||
or not can_complete_feed(npc.target_id, npc.id)
|
||||
or definition == null
|
||||
or not definition.has_completion_cost()
|
||||
or economy == null
|
||||
):
|
||||
return false
|
||||
var resource_id := definition.completion_cost_resource_id
|
||||
var required_amount := definition.completion_cost_amount
|
||||
var carried_amount := npc.get_inventory_amount(resource_id)
|
||||
var pickup_amount := maxf(required_amount - carried_amount, 0.0)
|
||||
if pickup_amount <= 0.0:
|
||||
return true
|
||||
var pantry: StorageStateRecord = economy.get_storage_for_resource(resource_id)
|
||||
var available := pantry.get_amount(resource_id) if pantry != null else 0.0
|
||||
if pantry == null or available < pickup_amount:
|
||||
_emit_feed_blocked(
|
||||
npc.id, pantry.get_storage_id() if pantry != null else &"", definition, available
|
||||
)
|
||||
return false
|
||||
var withdrawn: float = economy.withdraw_exact_to_inventory(npc, resource_id, pickup_amount)
|
||||
if not is_equal_approx(withdrawn, pickup_amount):
|
||||
_emit_feed_blocked(npc.id, pantry.get_storage_id(), definition, available)
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func has_available_feed_target(npc_id: int) -> bool:
|
||||
if active_world_adapter == null or not active_world_adapter.has_method("get_animal_candidates"):
|
||||
return false
|
||||
@@ -158,11 +213,13 @@ func find_node_for_player(from_position: Vector3, max_distance: float) -> Animal
|
||||
|
||||
func feed(animal_id: StringName, actor_id: int, npcs: Array[SimNPC], current_tick: int) -> bool:
|
||||
var animal_state := get_state(animal_id)
|
||||
if animal_state == null or not animal_state.needs_feed():
|
||||
if animal_state == null or not animal_state.needs_feed() or current_tick < 0:
|
||||
return false
|
||||
var actor_npc: SimNPC
|
||||
if actor_id >= 0:
|
||||
actor_npc = _find_npc(actor_id, npcs)
|
||||
if (
|
||||
_find_npc(actor_id, npcs) == null
|
||||
actor_npc == null
|
||||
or not animal_state.can_npc_feed()
|
||||
or animal_state.get_reserved_by() != actor_id
|
||||
):
|
||||
@@ -176,37 +233,29 @@ func feed(animal_id: StringName, actor_id: int, npcs: Array[SimNPC], current_tic
|
||||
var resource_id := definition.completion_cost_resource_id
|
||||
var required_amount := definition.completion_cost_amount
|
||||
var pantry: StorageStateRecord = economy.get_storage_for_resource(resource_id)
|
||||
var available := pantry.get_amount(resource_id) if pantry != null else 0.0
|
||||
if pantry == null or available < required_amount:
|
||||
if actor_id >= 0:
|
||||
(
|
||||
narrative_event_requested
|
||||
. emit(
|
||||
SimulationIds.EVENT_TASK_BLOCKED,
|
||||
actor_id,
|
||||
pantry.get_storage_id() if pantry != null else &"",
|
||||
(
|
||||
"%s: needs %.0f %s (%.1f available)"
|
||||
% [
|
||||
definition.display_name,
|
||||
required_amount,
|
||||
String(resource_id).capitalize(),
|
||||
available,
|
||||
]
|
||||
),
|
||||
definition.action_id,
|
||||
resource_id,
|
||||
required_amount
|
||||
)
|
||||
var source_id := SimulationIds.STORAGE_VILLAGE_PANTRY
|
||||
var consumed := 0.0
|
||||
if actor_npc != null:
|
||||
var carried_amount := actor_npc.get_inventory_amount(resource_id)
|
||||
if carried_amount < required_amount:
|
||||
_emit_feed_blocked(
|
||||
actor_id, SimulationIds.npc_inventory_id(actor_id), definition, carried_amount
|
||||
)
|
||||
return false
|
||||
|
||||
var consumed: float = economy.withdraw_resource(resource_id, required_amount)
|
||||
if consumed < required_amount:
|
||||
economy.deposit_resource(resource_id, consumed)
|
||||
return false
|
||||
consumed = economy.remove_exact_from_inventory(actor_npc, resource_id, required_amount)
|
||||
source_id = SimulationIds.npc_inventory_id(actor_id)
|
||||
else:
|
||||
var available := pantry.get_amount(resource_id) if pantry != null else 0.0
|
||||
if pantry == null or available < required_amount:
|
||||
return false
|
||||
consumed = economy.withdraw_resource(resource_id, required_amount)
|
||||
if not is_equal_approx(consumed, required_amount):
|
||||
return false
|
||||
if not animal_state.feed(actor_id, current_tick):
|
||||
economy.deposit_resource(resource_id, consumed)
|
||||
if actor_npc != null:
|
||||
economy.restore_to_inventory(actor_npc, resource_id, consumed)
|
||||
else:
|
||||
economy.deposit_resource(resource_id, consumed)
|
||||
return false
|
||||
if animal_state.has_active_travel_target():
|
||||
animal_state.cancel_travel(current_tick + ROUTINE_STAY_TICKS)
|
||||
@@ -216,7 +265,7 @@ func feed(animal_id: StringName, actor_id: int, npcs: Array[SimNPC], current_tic
|
||||
economic_event_requested.emit(
|
||||
SimulationIds.EVENT_ANIMAL_FED,
|
||||
actor_id,
|
||||
pantry.get_storage_id(),
|
||||
source_id,
|
||||
animal_state.get_animal_id(),
|
||||
resource_id,
|
||||
consumed,
|
||||
@@ -225,6 +274,33 @@ func feed(animal_id: StringName, actor_id: int, npcs: Array[SimNPC], current_tic
|
||||
return true
|
||||
|
||||
|
||||
func _emit_feed_blocked(
|
||||
actor_id: int, source_id: StringName, definition: ActionDefinition, available_amount: float
|
||||
) -> void:
|
||||
if actor_id < 0:
|
||||
return
|
||||
(
|
||||
narrative_event_requested
|
||||
. emit(
|
||||
SimulationIds.EVENT_TASK_BLOCKED,
|
||||
actor_id,
|
||||
source_id,
|
||||
(
|
||||
"%s: needs %.0f %s (%.1f available)"
|
||||
% [
|
||||
definition.display_name,
|
||||
definition.completion_cost_amount,
|
||||
String(definition.completion_cost_resource_id).capitalize(),
|
||||
available_amount,
|
||||
]
|
||||
),
|
||||
definition.action_id,
|
||||
definition.completion_cost_resource_id,
|
||||
definition.completion_cost_amount
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func append_state_records(record: SimulationStateRecord) -> void:
|
||||
var animal_ids: Array = states.keys()
|
||||
animal_ids.sort()
|
||||
|
||||
Reference in New Issue
Block a user