How-To: Drive Behavior from Step Phases
Goal: make a combo step's wind-up, active and recovery frames readable to the rest of your game - so a dodge only cancels during recovery, a follow-up edge only opens in recovery, a cue fires the moment the step commits, and the HUD can show which part of the swing the player is in.
1. Author the phase boundaries on a step
Open the combo graph and select a Step node. Its timeline draws five tracks and the first three are the phase boundaries. Drag a bar, or type the value in the Details panel: every number is seconds at 1x play rate, measured from the moment the step's ability activates.
| Value | Track | What it does at runtime |
|---|---|---|
| Startup End | Startup | Authored for readability, and exposed to UI on the telegraph snapshot. The live phase does not read it: a step is in Startup until Active Start, so an authored gap between the two still counts as Startup rather than falling into a hole. |
| Active Start | Active | The step enters Active here. Set it to 0 and the step begins in Active and never reports Startup at all. |
| Active End | Active | The step enters Recovery here. Active is the closed range from Active Start to Active End. |
| Recovery End | Recovery | End of the recovery bar, and the opt-in switch. Any value above 0 means this step has phases. 0 means it has none. The step stays in Recovery past this point until it actually exits, so a recovery-gated cancel never drops out mid-step. |
| Transition Open / Transition Close | Transition Window | Unrelated to phases. This is the window in which a follow-up press chains. Author it wherever the move should feel chainable, phases or no phases. |
None for its whole life, no Combo.Phase.* tag is applied, and no phase hook or phase message fires. A step node you add starts with boundaries already authored, so opting out is a deliberate edit.Startup -> Active -> Recovery as the step plays, and reads (node authored no phases) on a step you opted out.2. Let a dodge cancel only during recovery
While a phase is live the controller sets one loose gameplay tag on the owner's ability system component - exactly one at a time. Any GAS gate that reads owner tags can therefore read a phase, including the two gates every ability already has.
| Tag | Present when |
|---|---|
Combo.Phase.Startup | The active step has not reached its Active Start yet. |
Combo.Phase.Active | The active step is between its Active Start and its Active End. |
Combo.Phase.Recovery | The active step is past its Active End and has not exited yet, including the tail past Recovery End. |
Combo.Phase | Never applied on its own - it is the parent of the three above. Match against it to ask "is a phase-authored step running at all". |
Open the dodge ability and go to Class Defaults -> Tags:
- Add
Combo.Phase.Recoveryto Activation Required Tags. The dodge can now only start while a combo step is in recovery. - Or add
Combo.Phase.Startupto Activation Blocked Tags instead, to allow it everywhere except the wind-up.
These are native tags this plugin declares, so they are already in the tag picker - there is nothing to add to a tag table.
Combo.Phase into the Owned Gameplay Tags filter: exactly one phase tag is listed at a time and it changes as the step plays. Press dodge during the wind-up and nothing happens; press it after the active frames and it fires.3. Open a transition only in one phase
A transition can carry its own gate. Select the Transition edge node and fill in Edge Required Tags Query under Combo | Gating: the edge is eligible only while the owner's tags satisfy the query, and an empty query always passes. Because the live phase is a tag, a query of "match all: Combo.Phase.Recovery" makes that edge a recovery-only chain.
The step node's Node Tags are applied the same way, as loose tags, for as long as that node is the active step - so one query can mix the two. A query of "match all: Combo.Phase.Recovery, Combat.Step.Heavy" opens the edge only out of a step whose Node Tags contain your own Combat.Step.Heavy, and only in recovery.
Combo.Phase.Recovery still accepts a press made late in Active - the player does not have to wait for the phase to flip.Edge required-tags query not satisfied while the gate fails, and stops reporting that reason the moment the phase arrives.4. Fire an event on one phase
Combo events subscribe to lifecycle hooks through Hook Mask, and two of the eight hooks are the phase hooks. Phase Filter, on the same event, narrows them to a single phase and is ignored by the other six.
- Right-click the Step node and add an event sub-node, as in How-To: React to Combo Events.
- Tick On Phase Entered, On Phase Exited, or both, in Hook Mask.
- Set Phase Filter to
Activeto fire only for the active phase. Leave it atNoneto fire on every phase the step passes through.
UCrimsonComboEvent_GameplayCue set to add a cue on On Phase Entered is still auto-removed at step exit by Auto Remove On Step Exit. For a cue that lives exactly as long as one phase, use two instances with the same Phase Filter: an Add on On Phase Entered and a Remove on On Phase Exited.For anything the four shipped event types do not cover, make a Blueprint subclass of UCrimsonComboEventBase and override On Phase Entered. The Context pin carries Phase (the phase just entered), Avatar Actor, Node ID and Combo. Then add an instance of your subclass as a sub-node on the step, tick On Phase Entered in Hook Mask, and set Phase Filter.
To react without authoring anything on the node, bind On Phase Entered Delegate on the combo controller instead - see step 5.
UCrimsonComboEvent_GameplayMessage on On Phase Entered with Phase Filter set to Active, and listen for its channel. It fires once per step, as the step crosses its Active Start - and not at all on a step you opted out of phases.5. Read the phase from UI or code
Three ways in, depending on whether you want to poll, listen on the controller, or listen on a message channel.
| Source | Gives you |
|---|---|
| Get Current Phase on the combo controller | The live phase as an ECrimsonComboPhase. None when no combo is running, and for the whole life of a step that authored no phases. |
| Get Telegraph Snapshot on the combo controller | Current Phase and Has Authored Phases, plus the four boundaries as Startup End Local Seconds, Active Start Local Seconds, Active End Local Seconds and Recovery End Local Seconds - offsets from step entry, already scaled by the step's play rate, the same convention as Window Open Local Seconds. Everything a phase bar needs in one read. |
The Combo.Message.PhaseEntered and Combo.Message.PhaseExited channels | An FCrimsonComboUIMessage whose Event is PhaseEntered or PhaseExited, carrying Context (with Phase) and a fresh Snapshot. On PhaseExited the Context's Phase is the phase being left, which is deliberately not what the Snapshot's Current Phase reads. |
| On Phase Entered Delegate / On Phase Exited Delegate on the controller | The same two moments as a multicast delegate you can bind in Blueprint or C++, with (Context, Phase). Server and owning client only. |
Polling, anywhere you already have the controller: Get Component By Class (CrimsonComboController) -> Get Current Phase, and switch on the result.
Event-driven, in a HUD widget: Event Construct -> Get Owning Player Pawn -> Get Component By Class (Crimson Combo Controller) -> Bind Event to On Combo UI Message. In the event, return early unless Channel is Combo.Message.PhaseEntered; then read the Context's Phase and the Snapshot's boundary fields.
Watching another player's pawn shows nothing, and that is correct: a simulated proxy runs no combo logic. Drive someone else's phase UI from your own replicated gameplay state instead.
See also
- How-To: Author a Combo - where the boundaries are authored.
- How-To: React to Combo Events - the full hook list and the four shipped event types.
- How-To: Debug Combos (Dev Tools) - the Phase readout and the Transition Inspector.
- How-To: Drive Combos from AI - the same phases on a driven combo.
- Concept: Combo System - why a phase is a loose tag.