class_name ActionDefinition extends Resource const ActionEffectScript := preload("res://simulation/commands/ActionEffect.gd") @export var action_id: StringName @export var display_name: String @export_range(0.0, 1000.0, 0.1) var default_duration := 1.0 @export var preferred_profession_id: StringName @export var target_type: StringName = SimulationIds.TARGET_ACTIVITY @export var resource_action_id: StringName @export var completion_cost_resource_id: StringName @export_range(0.0, 1000.0, 0.1) var completion_cost_amount := 0.0 @export var actor_capability_tags: Array[StringName] = [] @export var target_capability_tags: Array[StringName] = [] @export var selection_policy_id: StringName @export var target_policy_id: StringName @export var completion_handler_id: StringName @export var effects: Array[Resource] = [] @export var event_type_id: StringName @export var presentation_cue_id: StringName func validate() -> Array[String]: var errors: Array[String] = [] if action_id.is_empty(): errors.append("action_id is empty") if display_name.is_empty(): errors.append("display_name is empty for '%s'" % action_id) if default_duration <= 0.0: errors.append("default_duration must be positive for '%s'" % action_id) if ( target_type not in [ SimulationIds.TARGET_RESOURCE, SimulationIds.TARGET_ACTIVITY, SimulationIds.TARGET_ANIMAL, SimulationIds.TARGET_FREE, ] ): errors.append("target_type '%s' is invalid for '%s'" % [target_type, action_id]) if target_type == SimulationIds.TARGET_RESOURCE and resource_action_id.is_empty(): errors.append("resource_action_id is required for '%s'" % action_id) if completion_cost_resource_id.is_empty() and completion_cost_amount > 0.0: errors.append("completion cost resource is required for '%s'" % action_id) if not completion_cost_resource_id.is_empty() and completion_cost_amount <= 0.0: errors.append("completion cost amount must be positive for '%s'" % action_id) _validate_unique_tags(actor_capability_tags, "actor capability", errors) _validate_unique_tags(target_capability_tags, "target capability", errors) var effect_ids := {} for effect in effects: if effect == null or effect.get_script() != ActionEffectScript: errors.append("effects contains a null definition for '%s'" % action_id) continue for error in effect.call("validate"): errors.append("ActionEffect: " + error) var effect_id: StringName = effect.get("effect_id") if effect_ids.has(effect_id): errors.append("duplicate effect_id '%s' for '%s'" % [effect_id, action_id]) effect_ids[effect_id] = true return errors func has_completion_cost() -> bool: return not completion_cost_resource_id.is_empty() and completion_cost_amount > 0.0 static func _validate_unique_tags( tags: Array[StringName], label: String, errors: Array[String] ) -> void: var seen := {} for tag in tags: if tag.is_empty(): errors.append("%s is empty" % label) elif seen.has(tag): errors.append("duplicate %s '%s'" % [label, tag]) else: seen[tag] = true