Files
gamedev-the-steward/simulation/animals/AnimalDefinition.gd
T
2026-08-12 20:50:52 +02:00

95 lines
3.1 KiB
GDScript

class_name AnimalDefinition
extends Resource
const BEHAVIOR_GRAZER_ROUTINE := &"grazer_routine"
@export var animal_definition_id: StringName
@export var species_id: StringName
@export var display_name: String
@export var behavior_id: StringName = BEHAVIOR_GRAZER_ROUTINE
@export var supported_action_ids: Array[StringName] = []
@export_file("*.tscn") var presentation_scene_path: String
@export_range(0.1, 10.0, 0.1) var movement_speed := 1.6
@export var visual_scale := Vector3.ONE
@export var body_scale := Vector3.ONE
@export var fluff_scale := Vector3.ONE
@export var show_horns := true
@export var show_beard := true
func validate() -> Array[String]:
var errors: Array[String] = []
if not is_valid_stable_id(animal_definition_id):
errors.append("animal_definition_id is invalid")
if not is_valid_stable_id(species_id):
errors.append("species_id is invalid for '%s'" % animal_definition_id)
if display_name.strip_edges().is_empty():
errors.append("display_name is empty for '%s'" % animal_definition_id)
if behavior_id != BEHAVIOR_GRAZER_ROUTINE:
errors.append(
"behavior_id '%s' is unsupported for '%s'" % [behavior_id, animal_definition_id]
)
if (
presentation_scene_path.is_empty()
or not presentation_scene_path.begins_with("res://")
or presentation_scene_path.get_extension() != "tscn"
or not ResourceLoader.exists(presentation_scene_path, "PackedScene")
):
errors.append("presentation_scene_path is invalid for '%s'" % animal_definition_id)
if not is_finite(movement_speed) or movement_speed <= 0.0:
errors.append("movement_speed must be positive for '%s'" % animal_definition_id)
if (
not visual_scale.is_finite()
or visual_scale.x <= 0.0
or visual_scale.y <= 0.0
or visual_scale.z <= 0.0
):
errors.append("visual_scale must be finite and positive for '%s'" % animal_definition_id)
if (
not body_scale.is_finite()
or body_scale.x <= 0.0
or body_scale.y <= 0.0
or body_scale.z <= 0.0
):
errors.append("body_scale must be finite and positive for '%s'" % animal_definition_id)
if (
not fluff_scale.is_finite()
or fluff_scale.x <= 0.0
or fluff_scale.y <= 0.0
or fluff_scale.z <= 0.0
):
errors.append("fluff_scale must be finite and positive for '%s'" % animal_definition_id)
var seen: Dictionary = {}
for action_id in supported_action_ids:
if not is_valid_stable_id(action_id):
errors.append("supported action ID is invalid for '%s'" % animal_definition_id)
elif seen.has(action_id):
errors.append(
"duplicate supported action '%s' for '%s'" % [action_id, animal_definition_id]
)
else:
seen[action_id] = true
return errors
func supports_action(action_id: StringName) -> bool:
return action_id in supported_action_ids
static func is_valid_stable_id(value: Variant) -> bool:
if value is not String and value is not StringName:
return false
var text := String(value)
if text.is_empty() or text.length() > 96:
return false
for character in text:
var code := character.unicode_at(0)
if not (
(code >= 48 and code <= 57)
or (code >= 65 and code <= 90)
or (code >= 97 and code <= 122)
or character in ["_", "-", ".", ":"]
):
return false
return true