feat: add simulation action definitions

This commit is contained in:
2026-07-05 13:35:33 +02:00
parent 12f9ba616f
commit f816f3976a
32 changed files with 608 additions and 113 deletions
+54 -56
View File
@@ -1,20 +1,20 @@
class_name SimNPC
extends RefCounted
const TASK_STATE_IDLE := "idle"
const TASK_STATE_TRAVELING := "traveling"
const TASK_STATE_WORKING := "working"
const TASK_STATE_COMPLETE := "complete"
const TASK_STATE_IDLE := &"idle"
const TASK_STATE_TRAVELING := &"traveling"
const TASK_STATE_WORKING := &"working"
const TASK_STATE_COMPLETE := &"complete"
var id: int
var npc_name: String
var profession: String
var profession: StringName
var hunger: float
var energy: float
var strength: float
var intelligence: float
var current_task: String = "idle"
var task_state: String = TASK_STATE_IDLE
var current_task: StringName = SimulationIds.ACTION_IDLE
var task_state: StringName = TASK_STATE_IDLE
var position: Vector3
var is_starving := false
@@ -26,14 +26,14 @@ var task_duration := 0.0
var task_progress := 0.0
var task_complete := true
var target_id: StringName = &""
var last_task := ""
var last_task: StringName
var random_source: RandomNumberGenerator
var debug_logs := true
func _init(
_id: int,
_npc_name: String,
_profession: String,
_profession: StringName,
_strength: float,
_intelligence: float,
_random_source: RandomNumberGenerator = null
@@ -87,7 +87,7 @@ func update_needs(village: SimVillage) -> void:
TASK_STATE_TRAVELING:
energy -= 2.0
TASK_STATE_WORKING:
if current_task != "rest":
if current_task != SimulationIds.ACTION_REST:
energy -= 3.0
TASK_STATE_COMPLETE:
energy -= 0.25
@@ -107,7 +107,7 @@ func update_needs(village: SimVillage) -> void:
func die_from_starvation() -> void:
is_dead = true
current_task = "dead"
current_task = SimulationIds.ACTION_DEAD
task_state = TASK_STATE_IDLE
task_progress = 0.0
task_duration = 0.0
@@ -122,110 +122,97 @@ func choose_new_task(village: SimVillage) -> void:
if is_starving:
if village.food > 0:
set_task("eat", 1.0)
set_task(SimulationIds.ACTION_EAT, 1.0)
else:
set_task("gather_food", 4.0)
set_task(SimulationIds.ACTION_GATHER_FOOD, 4.0)
return
if hunger > 75.0:
if village.food > 0:
set_task("eat", 2.0)
set_task(SimulationIds.ACTION_EAT)
else:
set_task("gather_food", 5.0)
set_task(SimulationIds.ACTION_GATHER_FOOD)
return
if energy < 25.0:
set_task("rest", 4.0)
set_task(SimulationIds.ACTION_REST)
return
var best_task := choose_best_work_task(village)
match best_task:
"gather_food":
set_task("gather_food", 5.0)
"gather_wood":
set_task("gather_wood", 5.0)
"patrol":
set_task("patrol", 6.0)
"study":
set_task("study", 6.0)
_:
set_task("wander", 4.0)
set_task(choose_best_work_task(village))
func should_eat_immediately_after_task() -> bool:
return current_task == "gather_food" and is_starving and not is_dead
return (
current_task == SimulationIds.ACTION_GATHER_FOOD
and is_starving
and not is_dead
)
func choose_best_work_task(village: SimVillage) -> String:
func choose_best_work_task(village: SimVillage) -> StringName:
var food_score := calculate_task_score(
"gather_food",
SimulationIds.ACTION_GATHER_FOOD,
village.food_priority,
village.food,
15.0,
30.0,
3.0,
1.5,
"farmer"
1.5
)
var wood_score := calculate_task_score(
"gather_wood",
SimulationIds.ACTION_GATHER_WOOD,
village.wood_priority,
village.wood,
10.0,
20.0,
2.5,
1.0,
"woodcutter"
1.0
)
var safety_score := calculate_task_score(
"patrol",
SimulationIds.ACTION_PATROL,
village.safety_priority,
village.safety,
30.0,
50.0,
3.0,
1.5,
"guard"
1.5
)
var knowledge_score := calculate_task_score(
"study",
SimulationIds.ACTION_STUDY,
village.knowledge_priority,
village.knowledge,
10.0,
25.0,
1.5,
0.75,
"scholar"
0.75
)
var best_task := "gather_food"
var best_task := SimulationIds.ACTION_GATHER_FOOD
var best_score := food_score
if wood_score > best_score:
best_task = "gather_wood"
best_task = SimulationIds.ACTION_GATHER_WOOD
best_score = wood_score
if safety_score > best_score:
best_task = "patrol"
best_task = SimulationIds.ACTION_PATROL
best_score = safety_score
if knowledge_score > best_score:
best_task = "study"
best_task = SimulationIds.ACTION_STUDY
best_score = knowledge_score
return best_task
func calculate_task_score(
task_name: String,
action_id: StringName,
base_priority: float,
resource_amount: float,
critical_threshold: float,
low_threshold: float,
critical_bonus: float,
low_bonus: float,
preferred_profession: String
low_bonus: float
) -> float:
var score := base_priority
@@ -234,10 +221,15 @@ func calculate_task_score(
elif resource_amount < low_threshold:
score += low_bonus
if profession == preferred_profession:
var definition := SimulationDefinitions.get_action(action_id)
if (
definition != null
and not definition.preferred_profession_id.is_empty()
and profession == definition.preferred_profession_id
):
score += 2.0
if task_name == last_task:
if action_id == last_task:
score -= 1.5
score += random_source.randf_range(0.0, 0.5)
@@ -247,16 +239,22 @@ func calculate_task_score(
"[SimNPC] ",
npc_name,
" score ",
task_name,
action_id,
" = ",
score
)
return score
func set_task(task: String, duration: float) -> void:
current_task = task
task_duration = duration
func set_task(action_id: StringName, duration: float = -1.0) -> void:
var definition := SimulationDefinitions.get_action(action_id)
if definition == null:
push_error("SimNPC: unknown action_id '%s'" % action_id)
return
current_task = action_id
task_duration = (
duration if duration >= 0.0 else definition.default_duration
)
task_progress = 0.0
task_complete = false
task_state = TASK_STATE_TRAVELING