feat: add missing wood opportunities
This commit is contained in:
+130
-11
@@ -1,4 +1,4 @@
|
||||
class_name FoodShortageOpportunitySystem
|
||||
class_name VillageOpportunitySystem
|
||||
extends RefCounted
|
||||
|
||||
const CARE_HUNGER_THRESHOLD := 80.0
|
||||
@@ -13,17 +13,64 @@ func consider_event(
|
||||
pantry: StorageStateRecord,
|
||||
npcs: Array[SimNPC],
|
||||
knowledge_system: EventKnowledgeSystem,
|
||||
resource_states: Dictionary
|
||||
resource_states: Dictionary,
|
||||
woodpile: StorageStateRecord = null
|
||||
) -> OpportunityStateRecord:
|
||||
if event == null or pantry == null or current_tick < 0:
|
||||
return null
|
||||
var event_tick := int(event.data["tick"])
|
||||
if event_tick < 0 or event_tick > current_tick:
|
||||
return null
|
||||
var resolved := _try_resolve(event, pantry, npcs, resource_states)
|
||||
var resolved := _try_resolve(event, pantry, woodpile, npcs, resource_states)
|
||||
if resolved != null:
|
||||
return resolved
|
||||
return _try_open(event, current_tick, pantry, npcs, knowledge_system)
|
||||
var opened := _try_open_food(event, current_tick, pantry, npcs, knowledge_system)
|
||||
if opened != null:
|
||||
return opened
|
||||
if woodpile == null:
|
||||
return null
|
||||
return _try_open_wood(event, current_tick, woodpile, npcs, knowledge_system)
|
||||
|
||||
|
||||
func maintain_open_opportunity(
|
||||
current_tick: int,
|
||||
max_age: int,
|
||||
npcs: Array[SimNPC],
|
||||
pantry: StorageStateRecord,
|
||||
woodpile: StorageStateRecord
|
||||
) -> OpportunityStateRecord:
|
||||
var opportunity := get_open_opportunity()
|
||||
if opportunity == null or current_tick < opportunity.get_created_tick():
|
||||
return null
|
||||
if opportunity.get_opportunity_type() != SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD:
|
||||
return null
|
||||
var interested := _find_npc(opportunity.get_interested_npc_id(), npcs)
|
||||
if interested == null or interested.is_dead:
|
||||
return (
|
||||
opportunity
|
||||
if opportunity.invalidate(
|
||||
SimulationIds.OPPORTUNITY_INVALIDATED_INTERESTED_DIED, current_tick
|
||||
)
|
||||
else null
|
||||
)
|
||||
var target_storage := _get_target_storage(opportunity, pantry, woodpile)
|
||||
var condition_is_stale := (
|
||||
target_storage == null
|
||||
or (
|
||||
target_storage.get_amount(opportunity.get_resource_id())
|
||||
>= opportunity.get_target_amount()
|
||||
)
|
||||
or current_tick - opportunity.get_created_tick() >= maxi(max_age, 1)
|
||||
)
|
||||
if not condition_is_stale:
|
||||
return null
|
||||
return (
|
||||
opportunity
|
||||
if opportunity.invalidate(
|
||||
SimulationIds.OPPORTUNITY_INVALIDATED_EVIDENCE_STALE, current_tick
|
||||
)
|
||||
else null
|
||||
)
|
||||
|
||||
|
||||
func restore(records: Array[OpportunityStateRecord], restored_next_id: int) -> void:
|
||||
@@ -65,7 +112,7 @@ func get_latest_for_npc(npc_id: int) -> OpportunityStateRecord:
|
||||
return null
|
||||
|
||||
|
||||
func _try_open(
|
||||
func _try_open_food(
|
||||
event: EconomicEventRecord,
|
||||
current_tick: int,
|
||||
pantry: StorageStateRecord,
|
||||
@@ -91,18 +138,62 @@ func _try_open(
|
||||
return opportunity
|
||||
|
||||
|
||||
func _try_open_wood(
|
||||
event: EconomicEventRecord,
|
||||
current_tick: int,
|
||||
woodpile: StorageStateRecord,
|
||||
npcs: Array[SimNPC],
|
||||
knowledge_system: EventKnowledgeSystem
|
||||
) -> OpportunityStateRecord:
|
||||
if knowledge_system == null or get_open_opportunity() != null:
|
||||
return null
|
||||
if not _is_missing_wood_block(event):
|
||||
return null
|
||||
var target_amount := float(event.data.get("required_amount", 0.0))
|
||||
if woodpile.get_amount(SimulationIds.RESOURCE_WOOD) >= target_amount:
|
||||
return null
|
||||
var actor := _find_npc(int(event.data["actor_id"]), npcs)
|
||||
if (
|
||||
actor == null
|
||||
or actor.is_dead
|
||||
or not knowledge_system.knows_event(actor.id, int(event.data["event_id"]))
|
||||
):
|
||||
return null
|
||||
var opportunity := OpportunityStateRecord.create(
|
||||
next_opportunity_id,
|
||||
current_tick,
|
||||
int(event.data["event_id"]),
|
||||
actor.id,
|
||||
target_amount,
|
||||
SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD,
|
||||
SimulationIds.STORAGE_VILLAGE_WOODPILE,
|
||||
SimulationIds.RESOURCE_WOOD
|
||||
)
|
||||
next_opportunity_id += 1
|
||||
opportunities.append(opportunity)
|
||||
return opportunity
|
||||
|
||||
|
||||
func _try_resolve(
|
||||
event: EconomicEventRecord,
|
||||
pantry: StorageStateRecord,
|
||||
woodpile: StorageStateRecord,
|
||||
npcs: Array[SimNPC],
|
||||
resource_states: Dictionary
|
||||
) -> OpportunityStateRecord:
|
||||
var opportunity := get_open_opportunity()
|
||||
if opportunity == null:
|
||||
return null
|
||||
if pantry.get_amount(SimulationIds.RESOURCE_FOOD) < opportunity.get_target_amount():
|
||||
var target_storage := _get_target_storage(opportunity, pantry, woodpile)
|
||||
if (
|
||||
target_storage == null
|
||||
or (
|
||||
target_storage.get_amount(opportunity.get_resource_id())
|
||||
< opportunity.get_target_amount()
|
||||
)
|
||||
):
|
||||
return null
|
||||
if not _is_valid_supply(event, npcs, resource_states):
|
||||
if not _is_valid_supply(event, opportunity, npcs, resource_states):
|
||||
return null
|
||||
if int(event.data["tick"]) < opportunity.get_created_tick():
|
||||
return null
|
||||
@@ -139,12 +230,29 @@ static func _is_food_withdrawal(event: EconomicEventRecord) -> bool:
|
||||
)
|
||||
|
||||
|
||||
static func _is_missing_wood_block(event: EconomicEventRecord) -> bool:
|
||||
return (
|
||||
StringName(event.data["event_type"]) == SimulationIds.EVENT_TASK_BLOCKED
|
||||
and int(event.data["actor_id"]) >= 0
|
||||
and StringName(event.data["source_id"]) == SimulationIds.STORAGE_VILLAGE_WOODPILE
|
||||
and StringName(event.data["item_id"]) == SimulationIds.RESOURCE_WOOD
|
||||
and (
|
||||
StringName(event.data.get("action_id", &""))
|
||||
in [SimulationIds.ACTION_PATROL, SimulationIds.ACTION_STUDY]
|
||||
)
|
||||
and float(event.data.get("required_amount", 0.0)) > 0.0
|
||||
)
|
||||
|
||||
|
||||
static func _is_valid_supply(
|
||||
event: EconomicEventRecord, npcs: Array[SimNPC], resource_states: Dictionary
|
||||
event: EconomicEventRecord,
|
||||
opportunity: OpportunityStateRecord,
|
||||
npcs: Array[SimNPC],
|
||||
resource_states: Dictionary
|
||||
) -> bool:
|
||||
if (
|
||||
StringName(event.data["item_id"]) != SimulationIds.RESOURCE_FOOD
|
||||
or StringName(event.data["destination_id"]) != SimulationIds.STORAGE_VILLAGE_PANTRY
|
||||
StringName(event.data["item_id"]) != opportunity.get_resource_id()
|
||||
or StringName(event.data["destination_id"]) != opportunity.get_target_id()
|
||||
or float(event.data["amount"]) <= 0.0
|
||||
):
|
||||
return false
|
||||
@@ -162,11 +270,22 @@ static func _is_valid_supply(
|
||||
)
|
||||
return (
|
||||
resource_state != null
|
||||
and resource_state.get_resource_id() == SimulationIds.RESOURCE_FOOD
|
||||
and resource_state.get_resource_id() == opportunity.get_resource_id()
|
||||
and resource_state.can_player_use_resource()
|
||||
)
|
||||
|
||||
|
||||
static func _get_target_storage(
|
||||
opportunity: OpportunityStateRecord, pantry: StorageStateRecord, woodpile: StorageStateRecord
|
||||
) -> StorageStateRecord:
|
||||
match opportunity.get_target_id():
|
||||
SimulationIds.STORAGE_VILLAGE_PANTRY:
|
||||
return pantry
|
||||
SimulationIds.STORAGE_VILLAGE_WOODPILE:
|
||||
return woodpile
|
||||
return null
|
||||
|
||||
|
||||
static func _sort_by_care(first: SimNPC, second: SimNPC) -> bool:
|
||||
if first.hunger != second.hunger:
|
||||
return first.hunger > second.hunger
|
||||
Reference in New Issue
Block a user