fce5c533fe
NPCs whose home positions are within 4m of each other gain mutual familiarity at baseline 0.5. Stored per NPC as a Dictionary keyed by other npc_id, serialized through NPCStateRecord with backward-compatible fallback for old saves. Household pairs form naturally from the home_positions configuration in main.tscn. Includes save/load round-trip test verifying familiarity persists.
111 lines
2.9 KiB
GDScript
111 lines
2.9 KiB
GDScript
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"
|
|
|
|
var id: int
|
|
var npc_name: String
|
|
var profession: StringName
|
|
var hunger: float
|
|
var energy: float
|
|
var strength: float
|
|
var intelligence: float
|
|
var current_task: StringName = SimulationIds.ACTION_IDLE
|
|
var task_state: StringName = TASK_STATE_IDLE
|
|
var position: Vector3
|
|
var home_position: Vector3
|
|
|
|
var is_starving := false
|
|
var starvation_ticks := 0
|
|
var starvation_death_threshold := 600
|
|
var is_dead := false
|
|
|
|
var task_duration := 0.0
|
|
var task_progress := 0.0
|
|
var task_complete := true
|
|
var target_id: StringName = &""
|
|
var travel_target_position: Vector3
|
|
var has_travel_target := false
|
|
var inventory: Dictionary = {}
|
|
var last_task: StringName
|
|
var random_source: RandomNumberGenerator
|
|
var familiarity: Dictionary = {}
|
|
var debug_logs := true
|
|
|
|
|
|
func _init(
|
|
_id: int,
|
|
_npc_name: String,
|
|
_profession: StringName,
|
|
_strength: float,
|
|
_intelligence: float,
|
|
_random_source: RandomNumberGenerator = null
|
|
) -> void:
|
|
id = _id
|
|
npc_name = _npc_name
|
|
profession = _profession
|
|
strength = _strength
|
|
intelligence = _intelligence
|
|
random_source = _random_source
|
|
if random_source == null:
|
|
random_source = RandomNumberGenerator.new()
|
|
random_source.seed = id + 1
|
|
hunger = random_source.randf_range(20.0, 80.0)
|
|
energy = random_source.randf_range(40.0, 100.0)
|
|
position = Vector3(
|
|
random_source.randf_range(-8.0, 8.0), 0.0, random_source.randf_range(-8.0, 8.0)
|
|
)
|
|
home_position = position
|
|
|
|
|
|
func die_from_starvation() -> void:
|
|
is_dead = true
|
|
current_task = SimulationIds.ACTION_DEAD
|
|
task_state = TASK_STATE_IDLE
|
|
task_progress = 0.0
|
|
task_duration = 0.0
|
|
task_complete = true
|
|
has_travel_target = false
|
|
|
|
if debug_logs:
|
|
print("[SimNPC] ", npc_name, " died from starvation.")
|
|
|
|
|
|
func get_inventory_amount(item_id: StringName) -> float:
|
|
return float(inventory.get(String(item_id), 0.0))
|
|
|
|
|
|
func add_inventory(item_id: StringName, amount: float) -> void:
|
|
inventory[String(item_id)] = get_inventory_amount(item_id) + maxf(amount, 0.0)
|
|
|
|
|
|
func remove_inventory(item_id: StringName, requested_amount: float) -> float:
|
|
var removed := minf(maxf(requested_amount, 0.0), get_inventory_amount(item_id))
|
|
inventory[String(item_id)] = get_inventory_amount(item_id) - removed
|
|
return removed
|
|
|
|
|
|
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
|
|
has_travel_target = false
|
|
|
|
|
|
func start_working() -> void:
|
|
if task_state != TASK_STATE_TRAVELING:
|
|
return
|
|
|
|
task_state = TASK_STATE_WORKING
|
|
task_progress = 0.0
|
|
task_complete = false
|