118 lines
4.2 KiB
GDScript
118 lines
4.2 KiB
GDScript
class_name AnimalFactory
|
|
extends RefCounted
|
|
|
|
const CONFIGURATION_KEYS := [
|
|
"initial_hunger",
|
|
"initial_enabled",
|
|
"can_npcs_feed",
|
|
"can_player_feed",
|
|
"debug_label_enabled",
|
|
"initial_routine_site_id",
|
|
"initial_next_routine_tick",
|
|
]
|
|
|
|
var last_error := ""
|
|
|
|
var _catalog: AnimalCatalog
|
|
|
|
|
|
func _init(catalog: AnimalCatalog = null) -> void:
|
|
_catalog = catalog if catalog != null else AnimalCatalog.create_core()
|
|
if _catalog == null:
|
|
last_error = "Animal catalog could not be loaded"
|
|
elif not _catalog.rebuild().is_empty():
|
|
last_error = "; ".join(_catalog.get_errors())
|
|
|
|
|
|
func get_catalog() -> AnimalCatalog:
|
|
return _catalog
|
|
|
|
|
|
func create_presentation(
|
|
animal_definition_id: StringName,
|
|
animal_id: StringName,
|
|
display_name: String,
|
|
configuration: Dictionary = {}
|
|
) -> AnimalNode:
|
|
last_error = ""
|
|
if _catalog == null or not _catalog.has_definition(animal_definition_id):
|
|
return _fail("Unknown animal definition '%s'" % animal_definition_id)
|
|
if not AnimalDefinition.is_valid_stable_id(animal_id):
|
|
return _fail("animal_id is invalid")
|
|
if display_name.strip_edges().is_empty():
|
|
return _fail("display_name is empty")
|
|
if not _configuration_is_valid(configuration):
|
|
return null
|
|
var definition := _catalog.get_definition(animal_definition_id)
|
|
var presentation_scene := load(definition.presentation_scene_path) as PackedScene
|
|
var node := (
|
|
presentation_scene.instantiate() as AnimalNode if presentation_scene != null else null
|
|
)
|
|
if node == null:
|
|
return _fail(
|
|
"Presentation scene for '%s' must instantiate AnimalNode" % animal_definition_id
|
|
)
|
|
if not node.apply_animal_definition(definition):
|
|
node.free()
|
|
return _fail("Presentation rejected definition '%s'" % animal_definition_id)
|
|
node.animal_id = animal_id
|
|
node.display_name = display_name
|
|
_apply_configuration(node, configuration)
|
|
return node
|
|
|
|
|
|
func _configuration_is_valid(configuration: Dictionary) -> bool:
|
|
for key in configuration:
|
|
if (key is not String and key is not StringName) or String(key) not in CONFIGURATION_KEYS:
|
|
return _fail_bool("Unknown animal presentation configuration '%s'" % key)
|
|
if configuration.has("initial_hunger"):
|
|
if (
|
|
configuration["initial_hunger"] is not int
|
|
and configuration["initial_hunger"] is not float
|
|
):
|
|
return _fail_bool("initial_hunger must be numeric")
|
|
var hunger := float(configuration["initial_hunger"])
|
|
if not is_finite(hunger) or hunger < 0.0 or hunger > 100.0:
|
|
return _fail_bool("initial_hunger must be between 0 and 100")
|
|
if (
|
|
configuration.has("initial_routine_site_id")
|
|
and not AnimalDefinition.is_valid_stable_id(configuration["initial_routine_site_id"])
|
|
):
|
|
return _fail_bool("initial_routine_site_id is invalid")
|
|
if configuration.has("initial_next_routine_tick"):
|
|
if configuration["initial_next_routine_tick"] is not int:
|
|
return _fail_bool("initial_next_routine_tick must be an int")
|
|
if int(configuration["initial_next_routine_tick"]) < 0:
|
|
return _fail_bool("initial_next_routine_tick must not be negative")
|
|
for key in ["initial_enabled", "can_npcs_feed", "can_player_feed", "debug_label_enabled"]:
|
|
if configuration.has(key) and configuration[key] is not bool:
|
|
return _fail_bool("%s must be a bool" % key)
|
|
return true
|
|
|
|
|
|
func _apply_configuration(node: AnimalNode, configuration: Dictionary) -> void:
|
|
if configuration.has("initial_hunger"):
|
|
node.initial_hunger = float(configuration["initial_hunger"])
|
|
if configuration.has("initial_enabled"):
|
|
node.initial_enabled = bool(configuration["initial_enabled"])
|
|
if configuration.has("can_npcs_feed"):
|
|
node.can_npcs_feed = bool(configuration["can_npcs_feed"])
|
|
if configuration.has("can_player_feed"):
|
|
node.can_player_feed = bool(configuration["can_player_feed"])
|
|
if configuration.has("debug_label_enabled"):
|
|
node.debug_label_enabled = bool(configuration["debug_label_enabled"])
|
|
if configuration.has("initial_routine_site_id"):
|
|
node.initial_routine_site_id = StringName(configuration["initial_routine_site_id"])
|
|
if configuration.has("initial_next_routine_tick"):
|
|
node.initial_next_routine_tick = int(configuration["initial_next_routine_tick"])
|
|
|
|
|
|
func _fail(message: String) -> AnimalNode:
|
|
last_error = message
|
|
return null
|
|
|
|
|
|
func _fail_bool(message: String) -> bool:
|
|
last_error = message
|
|
return false
|