How-To: Gate Combo Branches with Conditions

Goal: make a finisher hit harder only when the player actually landed the whole string - not merely because they mashed the button in time.

Prerequisites
How-To: Author a Combo - you need a working two-step combo first. How-To: Create and Equip an Augment if you want the reward to be an augment.

What a condition is

A UCrimsonComboTransitionCondition is a per-step observer. The controller creates one instance for each conditional-augment slot on each transition when the step is entered, feeds it everything that happens during that step, and then asks it one question when the player fires the transition: should this transition's augments be granted?

The event itself does not travel downstream. Augments do, gated by the condition's answer.

text
Step N ability broadcasts Augment.Event.OnHit
-> ASC OnAugmentEventBroadcast (spec handle + tag + payload)
-> ComboController routes it, filtered to the observed step
-> Condition::OnAugmentEvent accumulates "3 of 3 hits landed"
-> player presses, transition fires
-> Condition::EvaluateCondition -> true / false
-> transition ConditionalAugments equipped onto step N+1
Conditions are server-side
They never replicate. The owning client predicts the transition without evaluating conditions and snaps to the server's authoritative answer if they disagree. Never put player-visible state in a condition - broadcast it from the augment or a combo event instead.

1. Create the condition

Subclass UCrimsonComboTransitionCondition. It is Blueprintable and EditInlineNew, so a Blueprint subclass is a first-class choice.

Content Browser -> right-click -> Crimson -> Ability System -> Combo -> Transition Condition. Name it TC_LandedEveryHit.

Add an int32 variable HitCount, then override these events:

  • On Observation Begin -> Set HitCount to 0. This is your reset hook.
  • On Augment Event -> Branch on Event Tag Matches Tag Augment.Event.OnHit -> Increment Int HitCount.
  • Evaluate Condition -> return HitCount >= 3.
Verify
The class compiles and appears in the condition dropdown in step 2.

2. Attach it to a transition

Open the combo graph, click the Transition node into your finisher, and expand Conditional Augments. Add an entry, set Condition to your new class (it instantiates inline), and add the augments to grant under Augments.

No condition means always grant
Leave Condition empty and the augments are granted whenever the transition fires. The condition is the optional gate, not the mechanism.
Verify
Select the transition. Your condition appears as an inline object with its properties editable.

3. Make the step broadcast something to count

A condition can only count what the step ability actually broadcasts. Augment.Event.OnHit is emitted for you whenever an ability applies an effect spec to a target through ApplyEffectSpecToTarget. To signal anything else, broadcast your own tag.

In the step ability, call Broadcast Augment Event with an Event Tags container holding your tag (for example Augment.Event.OnComboMark) and a payload. Fire it from an AnimNotify, a trace hit, or wherever the moment actually happens.

Verify
Add a print to On Augment Event and confirm it fires while the step is running.

Augment.Event.OnActivate never reaches a condition

OnActivate is filtered out by design - use OnObservationBegin
A step ability broadcasts Augment.Event.OnActivate during its own activation. At that instant the combo controller has not yet recorded the new step, so the event is attributed to the PREVIOUS step and the spec filter correctly drops it. Your condition will never see it.

This is not a bug you can configure around, and it is not going to change - the ordering exists because the ability instance does not exist until activation has run.

Concretely, UCrimsonComboController::EnterNode does this:

text
EnterNode(...)
ASC->TryActivateAbility(Spec->Handle) <-- the ability broadcasts OnActivate HERE
...
CurrentStepState.StepHandle = Spec->Handle; <-- only now is the step identified
...
BeginConditionObservation(Node, StepAbility); <-- only now do conditions exist

So at the moment OnActivate fires there is no condition to receive it, and CurrentStepState.StepHandle still points at the step you are leaving. The filter is doing its job; the event is genuinely early.

Working around it

Three approaches, in the order you should reach for them.

1. Use `OnObservationBegin` - this is the intended answer. It fires at exactly the moment OnActivate would have been useful, and it hands you the ability itself, so anything you would have read from the activation is available.

Override On Observation Begin. Its Observed Ability pin is the step ability that just activated - Cast To your ability class and read whatever you need. This is also where you reset counters.

2. Broadcast your own tag one beat later. Any augment event emitted during the step - from an AnimNotify, a timer, a trace, or simply the next frame - arrives normally, because by then the controller has registered the step and built the conditions. If you specifically need "activation happened" as an event, emit your own tag instead of relying on OnActivate.

In the step ability, add an AnimNotify early in the montage (or a Delay of 0) and from it call Broadcast Augment Event with your own tag, for example Augment.Event.OnComboMark. The condition observes that tag instead.

3. Nothing else is affected. Augment.Event.OnHit, Augment.Event.OnEnd, Augment.Event.OnCrit, Augment.Event.OnKill and every tag you define yourself all reach conditions normally, because they fire while the step is the observed one. OnActivate is the single exception.

EventReaches a condition?Use instead
Augment.Event.OnActivateNo - fires before the step is registeredOnObservationBegin
Augment.Event.OnHitYes-
Augment.Event.OnEndYes-
Augment.Event.OnCrit / OnKillYes-
Your own tagsYes, if broadcast during the step-
Verify
Print inside On Observation Begin and inside On Augment Event. Observation Begin fires once per step entry; OnActivate never appears in the event handler, while OnHit does.

Observing attributes instead of events

A condition can also watch attribute changes - useful for "only chain if you are above 50 stamina" or "only if you took no damage during that step".

Override Get Observed Attributes and return an array containing the attributes you care about, then override On Observed Attribute Changed to accumulate.

The attribute list is read once
GetObservedAttributes is queried when the step is entered and cached for that step. Returning a different list later has no effect until the next step entry.
Verify
Change the observed attribute during a step and confirm the handler fires with the old and new values.

See also

  • How-To: Author a Combo - the graph these conditions attach to.
  • How-To: Create and Equip an Augment - what a passing condition grants.
  • Concept: Combo System - where conditions sit in the whole flow.
  • Concept: Multiplayer and Prediction - why conditions are server-only.