class_name ActionExecutor extends Node signal action_executed(action: Resource, judgement: StringName) signal action_failed(action: Resource, reason: StringName) @export var energy_component_path: NodePath @export var damage_emitter_path: NodePath @onready var _energy_component: Node = get_node_or_null(energy_component_path) @onready var _damage_emitter: Node = get_node_or_null(damage_emitter_path) func execute(action: Resource, judgement: StringName, burst_component: Variant = null) -> bool: if action == null: action_failed.emit(action, &"missing_action") return false var cost := _resolve_cost(action, burst_component) if _energy_component != null and not _energy_component.spend(cost): action_failed.emit(action, &"insufficient_energy") return false if _damage_emitter != null and _damage_emitter.has_method("configure_hit"): _damage_emitter.configure_hit(action, {"label": str(judgement)}) var reward := int(action.get("energy_reward")) if reward != 0 and _energy_component != null: _energy_component.change(reward) action_executed.emit(action, judgement) return true func _resolve_cost(action: Resource, burst_component: Variant) -> float: var combat := _combat_manager_or_null() if combat != null: return float(combat.call("resolve_cost", action, burst_component)) var base_cost := float(action.get("base_cost")) return base_cost if base_cost > 0.0 else float(action.get("energy_cost")) func _combat_manager_or_null() -> Node: if not is_inside_tree(): return null return get_tree().root.get_node_or_null("CombatManager")