224 lines
6.3 KiB
GDScript
224 lines
6.3 KiB
GDScript
extends RefCounted
|
|
|
|
signal inventory_changed(npc: SimNPC, item_id: StringName, amount: float)
|
|
signal economic_event_requested(
|
|
event_type: StringName,
|
|
actor_id: int,
|
|
source_id: StringName,
|
|
destination_id: StringName,
|
|
item_id: StringName,
|
|
amount: float
|
|
)
|
|
signal narrative_event_requested(
|
|
event_type: StringName, actor_id: int, source_id: StringName, action_display: String
|
|
)
|
|
|
|
var village: SimVillage
|
|
var storage_states: Dictionary = {}
|
|
var debug_logs := false
|
|
|
|
|
|
func configure(village_state: SimVillage, should_debug: bool) -> void:
|
|
village = village_state
|
|
debug_logs = should_debug
|
|
|
|
|
|
func initialize_storage() -> void:
|
|
if village == null:
|
|
return
|
|
if not storage_states.has(SimulationIds.STORAGE_VILLAGE_PANTRY):
|
|
storage_states[SimulationIds.STORAGE_VILLAGE_PANTRY] = StorageStateRecord.create(
|
|
SimulationIds.STORAGE_VILLAGE_PANTRY,
|
|
{String(SimulationIds.RESOURCE_FOOD): village.food}
|
|
)
|
|
if not storage_states.has(SimulationIds.STORAGE_VILLAGE_WOODPILE):
|
|
storage_states[SimulationIds.STORAGE_VILLAGE_WOODPILE] = StorageStateRecord.create(
|
|
SimulationIds.STORAGE_VILLAGE_WOODPILE,
|
|
{String(SimulationIds.RESOURCE_WOOD): village.wood}
|
|
)
|
|
sync_all()
|
|
|
|
|
|
func restore_storage(records: Array[StorageStateRecord]) -> void:
|
|
storage_states.clear()
|
|
for storage_record in records:
|
|
storage_states[storage_record.get_storage_id()] = storage_record
|
|
# Older saves may not contain every authored storage. Preserve their village
|
|
# aggregates by creating only the missing records before synchronizing.
|
|
initialize_storage()
|
|
|
|
|
|
func get_storage(storage_id: StringName) -> StorageStateRecord:
|
|
return storage_states.get(storage_id) as StorageStateRecord
|
|
|
|
|
|
func get_pantry() -> StorageStateRecord:
|
|
return get_storage(SimulationIds.STORAGE_VILLAGE_PANTRY)
|
|
|
|
|
|
func get_woodpile() -> StorageStateRecord:
|
|
return get_storage(SimulationIds.STORAGE_VILLAGE_WOODPILE)
|
|
|
|
|
|
func get_storage_for_resource(resource_id: StringName) -> StorageStateRecord:
|
|
match resource_id:
|
|
SimulationIds.RESOURCE_FOOD:
|
|
return get_pantry()
|
|
SimulationIds.RESOURCE_WOOD:
|
|
return get_woodpile()
|
|
return null
|
|
|
|
|
|
func sync_all() -> void:
|
|
if village == null:
|
|
return
|
|
var pantry := get_pantry()
|
|
var woodpile := get_woodpile()
|
|
if pantry != null:
|
|
village.food = pantry.get_amount(SimulationIds.RESOURCE_FOOD)
|
|
if woodpile != null:
|
|
village.wood = woodpile.get_amount(SimulationIds.RESOURCE_WOOD)
|
|
_refresh_village_scores()
|
|
|
|
|
|
func sync_resource(resource_id: StringName) -> void:
|
|
if village == null:
|
|
return
|
|
var storage := get_storage_for_resource(resource_id)
|
|
if storage == null:
|
|
return
|
|
match resource_id:
|
|
SimulationIds.RESOURCE_FOOD:
|
|
village.food = storage.get_amount(resource_id)
|
|
SimulationIds.RESOURCE_WOOD:
|
|
village.wood = storage.get_amount(resource_id)
|
|
_refresh_village_scores()
|
|
|
|
|
|
func deposit_inventory(npc: SimNPC, item_id: StringName) -> float:
|
|
var storage := get_storage_for_resource(item_id)
|
|
if storage == null:
|
|
return 0.0
|
|
var deposited := storage.deposit(item_id, npc.get_inventory_amount(item_id))
|
|
npc.remove_inventory(item_id, deposited)
|
|
sync_resource(item_id)
|
|
if deposited > 0.0:
|
|
inventory_changed.emit(npc, item_id, npc.get_inventory_amount(item_id))
|
|
economic_event_requested.emit(
|
|
SimulationIds.EVENT_STORAGE_DEPOSITED,
|
|
npc.id,
|
|
SimulationIds.npc_inventory_id(npc.id),
|
|
storage.get_storage_id(),
|
|
item_id,
|
|
deposited
|
|
)
|
|
return deposited
|
|
|
|
|
|
func withdraw_to_inventory(npc: SimNPC, item_id: StringName, amount: float) -> float:
|
|
var storage := get_storage_for_resource(item_id)
|
|
if storage == null:
|
|
return 0.0
|
|
var withdrawn := storage.withdraw(item_id, amount)
|
|
npc.add_inventory(item_id, withdrawn)
|
|
sync_resource(item_id)
|
|
if withdrawn > 0.0:
|
|
inventory_changed.emit(npc, item_id, npc.get_inventory_amount(item_id))
|
|
economic_event_requested.emit(
|
|
SimulationIds.EVENT_STORAGE_WITHDRAWN,
|
|
npc.id,
|
|
storage.get_storage_id(),
|
|
SimulationIds.npc_inventory_id(npc.id),
|
|
item_id,
|
|
withdrawn
|
|
)
|
|
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
|
|
inventory_changed.emit(
|
|
npc,
|
|
SimulationIds.RESOURCE_FOOD,
|
|
npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD)
|
|
)
|
|
economic_event_requested.emit(
|
|
SimulationIds.EVENT_ITEM_CONSUMED,
|
|
npc.id,
|
|
SimulationIds.npc_inventory_id(npc.id),
|
|
&"consumed",
|
|
SimulationIds.RESOURCE_FOOD,
|
|
1.0
|
|
)
|
|
return true
|
|
|
|
|
|
func consume_completion_cost(npc: SimNPC, definition: ActionDefinition) -> bool:
|
|
if definition == null or not definition.has_completion_cost():
|
|
return true
|
|
var resource_id := definition.completion_cost_resource_id
|
|
var required_amount := definition.completion_cost_amount
|
|
var storage := get_storage_for_resource(resource_id)
|
|
var available := storage.get_amount(resource_id) if storage != null else 0.0
|
|
if storage == null or available < required_amount:
|
|
var reason := "%s: needs %.0f %s (%.1f available)" % [
|
|
definition.display_name,
|
|
required_amount,
|
|
String(resource_id).capitalize(),
|
|
available,
|
|
]
|
|
narrative_event_requested.emit(
|
|
SimulationIds.EVENT_TASK_BLOCKED,
|
|
npc.id,
|
|
storage.get_storage_id() if storage != null else &"",
|
|
reason
|
|
)
|
|
return false
|
|
var consumed := storage.withdraw(resource_id, required_amount)
|
|
sync_resource(resource_id)
|
|
if consumed < required_amount:
|
|
return false
|
|
economic_event_requested.emit(
|
|
SimulationIds.EVENT_ITEM_CONSUMED,
|
|
npc.id,
|
|
storage.get_storage_id(),
|
|
&"consumed",
|
|
resource_id,
|
|
consumed
|
|
)
|
|
if debug_logs:
|
|
print(
|
|
"[VillageEconomy] %s consumed %.1f %s for %s"
|
|
% [npc.npc_name, consumed, resource_id, definition.action_id]
|
|
)
|
|
return true
|
|
|
|
|
|
func deposit_resource(resource_id: StringName, amount: float) -> float:
|
|
var storage := get_storage_for_resource(resource_id)
|
|
if storage == null:
|
|
return 0.0
|
|
var deposited := storage.deposit(resource_id, amount)
|
|
sync_resource(resource_id)
|
|
return deposited
|
|
|
|
|
|
func withdraw_resource(resource_id: StringName, amount: float) -> float:
|
|
var storage := get_storage_for_resource(resource_id)
|
|
if storage == null:
|
|
return 0.0
|
|
var withdrawn := storage.withdraw(resource_id, amount)
|
|
sync_resource(resource_id)
|
|
return withdrawn
|
|
|
|
|
|
func _refresh_village_scores() -> void:
|
|
village.update_modifiers()
|
|
village.update_priorities()
|