95 lines
3.1 KiB
GDScript
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
|