118 lines
3.3 KiB
GDScript
118 lines
3.3 KiB
GDScript
@tool
|
|
class_name GUIDETriggerCombo
|
|
extends GUIDETrigger
|
|
|
|
enum ActionEventType {
|
|
TRIGGERED = 1,
|
|
STARTED = 2,
|
|
ONGOING = 4,
|
|
CANCELLED = 8,
|
|
COMPLETED = 16
|
|
}
|
|
|
|
## If set to true, the combo trigger will print information
|
|
## about state changes to the debug log.
|
|
@export var enable_debug_print:bool = false
|
|
@export var steps:Array[GUIDETriggerComboStep] = []
|
|
@export var cancellation_actions:Array[GUIDETriggerComboCancelAction] = []
|
|
|
|
var _current_step:int = -1
|
|
var _remaining_time:float = 0
|
|
|
|
func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState:
|
|
if steps.is_empty():
|
|
push_warning("Combo with no steps will never fire.")
|
|
return GUIDETriggerState.NONE
|
|
|
|
# initial setup
|
|
if _current_step == -1:
|
|
for step in steps:
|
|
step._prepare()
|
|
for action in cancellation_actions:
|
|
action._prepare()
|
|
_reset()
|
|
|
|
|
|
var current_action := steps[_current_step].action
|
|
if current_action == null:
|
|
push_warning("Step ", _current_step , " has no action ", resource_path)
|
|
return GUIDETriggerState.NONE
|
|
|
|
# check if any of our cancellation actions fired
|
|
for action in cancellation_actions:
|
|
# if the action is the current action we don't count its firing as cancellation
|
|
if action.action == current_action:
|
|
continue
|
|
|
|
if action._has_fired:
|
|
if enable_debug_print:
|
|
print("Combo cancelled by action '", action.action._editor_name(), "'.")
|
|
_reset()
|
|
return GUIDETriggerState.NONE
|
|
|
|
# check if any of the steps has fired out of order
|
|
for step in steps:
|
|
if step.action == current_action:
|
|
continue
|
|
|
|
if step._has_fired:
|
|
if enable_debug_print:
|
|
print("Combo out of order step by action '", step.action._editor_name(), "'.")
|
|
_reset()
|
|
return GUIDETriggerState.NONE
|
|
|
|
# check if we took too long (unless we're in the first step)
|
|
if _current_step > 0:
|
|
_remaining_time -= delta
|
|
if _remaining_time <= 0.0:
|
|
if enable_debug_print:
|
|
print("Step time for step ", _current_step , " exceeded.")
|
|
_reset()
|
|
return GUIDETriggerState.NONE
|
|
|
|
# if the current action was fired, if so advance to the next
|
|
if steps[_current_step]._has_fired:
|
|
# reset this step, so it will not count as misfired next round
|
|
steps[_current_step]._has_fired = false
|
|
if _current_step + 1 >= steps.size():
|
|
# we finished the combo
|
|
if enable_debug_print:
|
|
print("Combo fired.")
|
|
_reset()
|
|
return GUIDETriggerState.TRIGGERED
|
|
|
|
# otherwise, pick the next step
|
|
_current_step += 1
|
|
if enable_debug_print:
|
|
print("Combo advanced to step " , _current_step, ".")
|
|
_remaining_time = steps[_current_step].time_to_actuate
|
|
|
|
# Reset all steps and cancellation actions to "not fired" in
|
|
# case they were triggered by this action. Otherwise a double-tap
|
|
# would immediately fire for both taps once the first is through
|
|
for step in steps:
|
|
step._has_fired = false
|
|
for action in cancellation_actions:
|
|
action._has_fired = false
|
|
|
|
# and in any case we're still processing.
|
|
return GUIDETriggerState.ONGOING
|
|
|
|
|
|
func _reset():
|
|
if enable_debug_print:
|
|
print("Combo reset.")
|
|
_current_step = 0
|
|
_remaining_time = steps[0].time_to_actuate
|
|
for step in steps:
|
|
step._has_fired = false
|
|
for action in cancellation_actions:
|
|
action._has_fired = false
|
|
|
|
func _editor_name() -> String:
|
|
return "Combo"
|
|
|
|
func _editor_description() -> String:
|
|
return "Fires, when the input exceeds the actuation threshold."
|
|
|