Files
gamedev-the-steward/simulation/actions/ActionSelectionSystem.gd
T

91 lines
2.9 KiB
GDScript

class_name ActionSelectionSystem
extends RefCounted
func select_action(npc: SimNPC, village: SimVillage) -> ActionSelectionResult:
if npc.is_dead:
return null
if npc.is_starving:
if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) >= 1.0:
return ActionSelectionResult.new(SimulationIds.ACTION_EAT, 1.0)
if village.food > 0:
return ActionSelectionResult.new(
SimulationIds.ACTION_WITHDRAW_FOOD,
1.0
)
return ActionSelectionResult.new(SimulationIds.ACTION_GATHER_FOOD, 4.0)
if npc.hunger > 75.0:
if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) >= 1.0:
return ActionSelectionResult.new(SimulationIds.ACTION_EAT)
if village.food > 0:
return ActionSelectionResult.new(SimulationIds.ACTION_WITHDRAW_FOOD)
return ActionSelectionResult.new(SimulationIds.ACTION_GATHER_FOOD)
if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) > 0.0:
return ActionSelectionResult.new(SimulationIds.ACTION_DEPOSIT_FOOD)
if npc.energy < 25.0:
return ActionSelectionResult.new(SimulationIds.ACTION_REST)
return ActionSelectionResult.new(_choose_best_work_action(npc, village))
func _choose_best_work_action(
npc: SimNPC,
village: SimVillage
) -> StringName:
var scores := {
SimulationIds.ACTION_GATHER_FOOD: _calculate_score(
npc, SimulationIds.ACTION_GATHER_FOOD, village.food_priority,
village.food, 15.0, 30.0, 3.0, 1.5
),
SimulationIds.ACTION_GATHER_WOOD: _calculate_score(
npc, SimulationIds.ACTION_GATHER_WOOD, village.wood_priority,
village.wood, 10.0, 20.0, 2.5, 1.0
),
SimulationIds.ACTION_PATROL: _calculate_score(
npc, SimulationIds.ACTION_PATROL, village.safety_priority,
village.safety, 30.0, 50.0, 3.0, 1.5
),
SimulationIds.ACTION_STUDY: _calculate_score(
npc, SimulationIds.ACTION_STUDY, village.knowledge_priority,
village.knowledge, 10.0, 25.0, 1.5, 0.75
)
}
var best_action := SimulationIds.ACTION_GATHER_FOOD
var best_score: float = scores[best_action]
for action_id in [
SimulationIds.ACTION_GATHER_WOOD,
SimulationIds.ACTION_PATROL,
SimulationIds.ACTION_STUDY
]:
var score: float = scores[action_id]
if score > best_score:
best_action = action_id
best_score = score
return best_action
func _calculate_score(
npc: SimNPC,
action_id: StringName,
base_priority: float,
resource_amount: float,
critical_threshold: float,
low_threshold: float,
critical_bonus: float,
low_bonus: float
) -> float:
var score := base_priority
if resource_amount < critical_threshold:
score += critical_bonus
elif resource_amount < low_threshold:
score += low_bonus
var definition := SimulationDefinitions.get_action(action_id)
if (
definition != null
and not definition.preferred_profession_id.is_empty()
and npc.profession == definition.preferred_profession_id
):
score += 2.0
if action_id == npc.last_task:
score -= 1.5
score += npc.random_source.randf_range(0.0, 0.5)
if npc.debug_logs:
print("[ActionSelection] ", npc.npc_name, " score ", action_id, " = ", score)
return score