feat: define authoritative action effects
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
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
|
||||
@@ -9,6 +11,14 @@ extends Resource
|
||||
@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]:
|
||||
@@ -35,8 +45,34 @@ func validate() -> Array[String]:
|
||||
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
|
||||
|
||||
@@ -92,7 +92,9 @@ func rebuild(
|
||||
)
|
||||
)
|
||||
|
||||
_validate_action_references(actions, actions_by_id, professions_by_id, items_by_id, errors)
|
||||
_validate_action_references(
|
||||
actions, actions_by_id, professions_by_id, items_by_id, supported_handlers, errors
|
||||
)
|
||||
_validate_enemy_references(enemies, items_by_id, errors)
|
||||
errors.sort()
|
||||
_errors = errors
|
||||
@@ -249,9 +251,23 @@ static func _validate_action_references(
|
||||
actions_by_id: Dictionary,
|
||||
professions_by_id: Dictionary,
|
||||
items_by_id: Dictionary,
|
||||
supported_handlers: Dictionary,
|
||||
errors: Array[String]
|
||||
) -> void:
|
||||
for definition in actions:
|
||||
for handler_field in [
|
||||
["selection policy", definition.selection_policy_id],
|
||||
["target policy", definition.target_policy_id],
|
||||
["completion handler", definition.completion_handler_id],
|
||||
]:
|
||||
var handler_id: StringName = handler_field[1]
|
||||
if not handler_id.is_empty() and not supported_handlers.has(handler_id):
|
||||
errors.append(
|
||||
(
|
||||
"Action '%s' references unknown %s '%s'"
|
||||
% [definition.action_id, handler_field[0], handler_id]
|
||||
)
|
||||
)
|
||||
if (
|
||||
not definition.preferred_profession_id.is_empty()
|
||||
and not professions_by_id.has(definition.preferred_profession_id)
|
||||
|
||||
Reference in New Issue
Block a user