# Reaction System

> Give an enemy an answer to what happens to it: author a reaction, point a trigger rule at the event, and it parries, dodges or flinches on its own.

Markdown version of https://rigbak.com/docs/soulslike-combat/reaction-system, a page of the Soulslike Enemy Combat documentation. Link that page when citing it.

> An enemy that answers your swing instead of eating it. One asset holds the answers and the rules that pick between them.

## Set it up (60 seconds)

1. **Create a Reaction Set**

   Right-click in the Content Browser, **SEC**, **Actions**, **Reaction Set**. It opens on its own card canvas.

   Create the asset: right-click in the Content Browser, choose **SEC > Actions > Reaction Set**, and name it **DA_ReactionSet_Grunt**.

   *Right-click in the Content Browser, SEC, Actions, Reaction Set.*
2. **Add the reaction**

   Right-click the canvas and choose **Add Reaction**. A card appears carrying a **Reaction ID** and a **Gameplay Ability** execution method already on it. Name the Reaction ID `Parry`.

   Set **Ability Class** to **GA_SEC_MontageAbility**, which ships with the plugin. A **Montage Payload** appears underneath it; set its **Montage** to your parry animation.

   In **DA_ReactionSet_Grunt**, under Execution, set:

   | Property | Value |
   | --- | --- |
   | Ability Class | GA_SEC_MontageAbility |
   | Montage | AM_Parry |

   *The shipped ability plays whatever montage the reaction names.*
3. **Say which event it answers**

   Right-click the canvas again and choose **Add Trigger**. Set its **On Stimulus** to `SEC.Stimulus.AttackTelegraphed`, then drag from the pin on the right of the trigger card to the pin on the left of the Parry card.

   That arrow reads: when an attack winds up nearby, parry it.
4. **Point the AI Config at it**

   Open the enemy's **Enemy AI Config** and set **Default Reaction Set** to the asset. Leave **Manage Reaction Sets Automatically** ticked.

   In **EnemyConfig_Grunt**, under Reaction Sets, set:

   | Property | Value |
   | --- | --- |
   | Manage Reaction Sets Automatically | true |
   | Default Reaction Set | DA_ReactionSet_Grunt |

   *Default Reaction Set covers every role, so one entry is enough to start.*
5. **Make the attack announce itself, and play**

   Open the player's attack montage and drag a **SEC Telegraph Window** across the wind-up frames. That window tells nearby enemies a blow is coming.

   Press Play, swing at the enemy, and run `SEC.Debug.LogReactions 1` to read which rule answered and which reaction won.

> **Warning**
>
> An attack montage carrying neither a **SEC Telegraph Window** nor a one-frame **SEC Telegraph** sends no warning, so no rule runs before the blow lands and the enemy stands there taking hits. Without a montage, **Report Area Stimulus** or **Report Stimulus To** reach the rules from any Blueprint, and **Report Damage Taken Stimulus** (or **Resolve Enemy Damage**, which calls it) reaches them once a blow lands. Turn on `SEC.Debug.Stimulus.Draw 1` to see whether anything is going out at all. See [Telegraphs](https://rigbak.com/docs/soulslike-combat/attack-telegraphs).

An enemy answers a stimulus whether or not it has a combat target, so a patrolling enemy can parry the first swing of an ambush.

---

## Say what answers each event

**Trigger Rules** on the Reaction Set turn an event into an answer. The enemy asks them in **Rule Priority** order, highest first, and takes the first rule that fits and yields a reaction, so specific rules sit above general ones.

**Category: Trigger**

| Property | Value |
| --- | --- |
| Enabled | true |
| Rule ID | ParryFrontal |
| On Stimulus | SEC.Stimulus.AttackTelegraphed |
| Require Context Tags | no tags |
| Block Context Tags | SEC.Attack.Unblockable |
| Conditions | 1 Array element |

**Category: Trigger > Index [ 0 ]**

| Property | Value |
| --- | --- |
| Incoming Angle Gate | Incoming Angle Gate |
| Half Angle Degrees | 60.0 |
| Pass Without Direction | true |
| Invert | false |

**Category: Trigger > Answers**

| Property | Value |
| --- | --- |
| Reaction Links | 2 Array elements |
| Reaction Category | SEC.Reaction.Defensive |
| Rule Priority | 20 |
| Chance | 0.60 |
| Min Interval | 1.5 |

| Field | Sets |
| --- | --- |
| **Rule ID** | Short name, shown in the row title and in the log when the rule fires or is skipped: `ParryFrontal`, `DodgeUnblockable`. |
| **On Stimulus** | Which event this rule answers, matched against any tag the announcement carries. A rule on a parent tag catches everything beneath it, so one on `SEC.Stimulus.AttackTelegraphed` also answers your own `SEC.Stimulus.AttackTelegraphed.Heavy`. |
| **Require Context Tags** | The event must carry all of these, which is how a rule answers heavy attacks alone. Empty requires nothing. |
| **Block Context Tags** | The rule steps aside when the event carries any of these, so a parry rule refuses `SEC.Attack.Unblockable` and the dodge rule below it answers. |
| **Conditions** | Gates that all have to pass before the rule answers. A refused rule hands the event to the rule below it. |
| **Chance** | How often the rule fires when everything else fits, 0 to 1. Drop it to 0.3 and the enemy parries roughly a third of the swings. |
| **Min Interval** | Shortest gap in seconds between two firings, so an enemy cannot parry every swing of a fast combo. 0 sets no limit. |

Three stimulus names ship with the plugin. `SEC.Stimulus.AttackTelegraphed` is a swing winding up, and `SEC.Stimulus.DamageTaken` a blow that already landed; author child tags of either for an attack that needs its own answer. `SEC.Stimulus.StanceBroken` names a stance pool that ran out, and the plugin never sends it on its own: bind **On Vital Depleted** on the enemy's **SEC Vitals** component and, for the stance pool, call **Report Stimulus To** with the enemy as **Receiver** and `SEC.Stimulus.StanceBroken` in the stimulus **Tags**. A rule on it then answers a guard break with a stun.

### Which reactions a rule can answer with

Draw an arrow to each reaction the rule may pick, or name a group instead with **Reaction Category** and let every reaction carrying that category compete. Fill in both and the rule answers only with a reaction that is wired **and** carries the category, which narrows the field.

Each arrow carries a **Weight Multiplier**: 1 leaves the reaction's own weight alone, 2 makes this rule lean twice as hard on that answer.

> **Tip: One rule, two answers**
>
> Wire a rule to both Parry and Dodge, then put an Incoming Angle Gate and the higher Priority on Parry. A frontal blow gets parried, and a blow from the side falls to the dodge with no second rule.

Laying this out as cards and watching a live enemy answer is what the [Reaction Set Editor](https://rigbak.com/docs/soulslike-combat/reaction-set-editor) is for.

---

## Author the reaction

A reaction card carries what runs, what it holds while it runs, and how often it may run.

**Category: Identity**

| Property | Value |
| --- | --- |
| Enabled | true |
| Reaction ID | Parry |
| Reaction Category | None |

**Category: Execution**

| Property | Value |
| --- | --- |
| Execution Method | Gameplay Ability |
| Execution Method > Ability Class | GA_SEC_MontageAbility |
| Execution Method > Payload | Montage Payload |
| Execution Method > Payload > Montage | AM_Parry |
| Cancel Current Action | true |

**Category: Tags**

| Property | Value |
| --- | --- |
| Add Tags | no tags |
| Requires Tags | no tags |
| Block Tags | no tags |

**Category: Scoring**

| Property | Value |
| --- | --- |
| Priority | 0 |
| Selection Weight | 1 |
| Scoring | 0 Array elements |

**Category: Action Interaction**

| Property | Value |
| --- | --- |
| Cancel Current Action | true |

**Execution Method** is how the reaction runs, the same picker actions use. **Gameplay Ability** covers almost everything: name an ability class, fill in its payload, and the reaction is set up. **Gameplay Ability By Tag** starts an ability something else already granted. **Gameplay Ability (Fire And Forget)** starts one and finishes in the same frame, for a shout the enemy should not stand still for.

**Add Tags** sit on the enemy while the reaction runs and come off when it ends. Put `SEC.Action.BlockActions` there to freeze the moveset for the duration.

**Cancel Current Action** is on by default, so a reaction cuts the swing the enemy was mid-way through. Untick it for a flinch that should play over the top.

**Cooldown Duration** is the wait before the same reaction can run again, 0 by default. **Randomization (%)** jitters it so a pack does not parry in lockstep, and **Max Consecutive Uses** forces a different answer after a set number of repeats.

Swapping the Reaction Set ends every running reaction cooldown, whether a role change that brings a different set, a StateTree set task that swaps it or **Set Reaction Set** does it, and each ended cooldown fires **On Reaction Cooldown Expired** on the server and on every client. A role change that keeps the same set keeps its cooldowns running.

> **Note**
>
> Nothing has to report back. SEC watches the ability system for the ability it started, so any ability that reaches **End Ability** on completion, cancel and interrupt works with no extra wiring. An ability still running after 30 seconds is cut off; set **Ability Timeout** to cap it sooner.

> **Warning**
>
> One reaction runs at a time. A second one asked for while the first is going is refused outright, so a reaction that never ends mutes the enemy until the safety limit expires.

<details>
<summary>Reading the hit direction to pick a montage section (Advanced)</summary>

`GA_SEC_Reaction` ships as the directional variant. It plays one montage and picks the section by the direction the blow arrived from, which is how a single hit reaction covers front, back and both sides.

It carries the montage as a class default rather than a payload, so make a Blueprint subclass per hit reaction and set **Reaction Montage** on it. **Reaction Montage** ships empty on `GA_SEC_Reaction` itself, so a reaction that runs the base class plays nothing. The demo's block is `GA_SEC_TwoHanded_Block`, a subclass beside the two-handed weapon's assets, which the Block reaction of `ReactionSet_SEC_TwoHanded` runs.

</details>

<details>
<summary>Stop two reactions overlapping (Advanced)</summary>

Put the same tag in one reaction's **Add Tags** and another's **Block Tags**. `SEC.State.ReactionActive` ships for this, and nothing adds it on your behalf.

Parry reaction

Adds `SEC.State.ReactionActive` while it runs. No block tags.

**Category: Tags**

| Property | Value |
| --- | --- |
| Add Tags | SEC.State.ReactionActive |
| Requires Tags | no tags |
| Block Tags | no tags |

Dodge reaction

Same add tag, plus **Block Tags** so it cannot fire during Parry.

**Category: Tags**

| Property | Value |
| --- | --- |
| Add Tags | SEC.State.ReactionActive |
| Requires Tags | no tags |
| Block Tags | SEC.State.ReactionActive |

While Parry runs it holds the tag, so Dodge is refused until Parry ends and the tag comes off.

</details>

---

## Pick between several answers

When a rule can answer with several reactions, they compete. Gates run first and drop the reactions that cannot help, scorers scale each survivor's weight, the highest **Priority** band takes the field, and a weighted random picks inside that band.

**Reaction Evaluation Flow** (Content > Plugins > SoulslikeEnemyCombat > Components)

Waiting for stimulus…

- **Stimulus (Your Code)** (OnDamageReceived, OnSenseDetected…)

* **EvaluateBestReaction(Category)** (Gates → Scorers → Priority → Weighted random)

- **Cancel Current Action** (StopCurrentAction() if bCancelCurrentAction)

* **ExecuteReaction(Id, Context)** (AddTags → Pack context → Activate ability)

- **OnReactionCompleted** (Remove AddTags → Fire delegate → Reset)

*Reactions are event-driven: your code decides *when*, the system decides *what*. Every 3rd cycle shows a blocked reaction.*

**Category: Scoring**

| Property | Value |
| --- | --- |
| Priority | 0 |
| Selection Weight | 1 |
| Scoring | 0 Array elements |

| Field | Does |
| --- | --- |
| **Priority** | The band. A reaction in a higher band beats every reaction below it, whatever the weights say. |
| **Selection Weight** | The odds inside a band. Weight 2 is twice as likely as weight 1. |
| **Scoring** | Gates that veto the reaction, and scorers that scale its weight. |

A scorer that drives a weight to zero vetoes the reaction outright, even at a high priority.

### Scorers on reactions

Reactions take the same scorers and gates as [actions](https://rigbak.com/docs/soulslike-combat/action-system#decide-when-the-enemy-picks-a-move), reading live distance, angle, speed and the pawn's [vitals](https://rigbak.com/docs/soulslike-combat/vitals) at the moment the blow arrives. Each built-in scorer shapes its dimension through one **Range** curve:

**Category: Range**

| Property | Value |
| --- | --- |
| Min Value | 0 |
| Optimal Min | 100 |
| Optimal Max | 250 |
| Max Value | 500 |
| Exponent | 2 |
| Clamp to Zero | true |

Four gates read the event rather than the pawn, so each one works either on a reaction's **Scoring** or in a rule's **Conditions**:

| Gate | Blocks unless | Defaults |
| --- | --- | --- |
| **Incoming Angle Gate** | The blow arrives inside an arc in front of the pawn. | **Half Angle Degrees** 60, so anything up to 60 degrees off the front passes; 180 turns it off. **Pass Without Direction** on. |
| **Time To Impact Gate** | There is still time to answer before the blow lands. | **Min Seconds** 0, **Max Seconds** 0 (no bound). Set Min Seconds to the parry's own start-up. |
| **Stimulus Magnitude Gate** | The blow is worth answering, in whatever the producer measured. | **Min Magnitude** 0, **Max Magnitude** 0 (no bound). A ceiling on one and a floor on the next splits a flinch from a stagger. |
| **Source Distance Gate** | The source is within reach, in centimeters. | **Min Distance** 0, **Max Distance** 0 (no bound). **Pass Without Source** on. |

The two placements read differently. A gate on a rule's **Conditions** decides whether this kind of answer is considered at all, and a refusal sends the event to the next rule down. A gate on a reaction's **Scoring** decides whether this reaction is the right one among the others that matched.

An action carries no event, so one of these four added to an action has nothing to judge and passes.

<details>
<summary>Writing a gate or scorer of your own (Advanced)</summary>

Subclass **SEC Scorer** or **SEC Gate** in Blueprint or C++ and override its one function. The context hands you the controller, the target, the ability system component, and a snapshot carrying distance, angle, speed, health, stamina and the event that set the reaction off.

Keep subclasses stateless. Every enemy using the asset shares one instance, so a stored field aliases across the whole pack. The seeded random helper is fixed on the reaction path, so use the world's random for per-enemy variation.

</details>

---

## Which Reaction Set an enemy uses

Fill in **Default Reaction Set** on the AI Config and every combat role uses it. Beyond that, four things can answer instead, and the first match wins:

| Source | Use it for |
| --- | --- |
| **Runtime Override** | Boss phase transitions. Set it in Blueprint, clear it to fall back. |
| **An equipped weapon** | Reactions that come with what the enemy is holding, such as a parry it can only do with a sword. |
| **Role Reaction Sets** | A different set per [combat role](https://rigbak.com/docs/soulslike-combat/combat-roles), so a Waiter guards more than an Attacker. |
| **Default Reaction Set** | Everything else. |

A weapon carries its set in **Weapon Reaction Set** on the weapon Blueprint. While the enemy holds it, that set wins; drop the weapon and the enemy falls back to its config. See [Weapons](https://rigbak.com/docs/soulslike-combat/weapons).

The set is resolved when the controller possesses the pawn and again on every role change, and each reaction's ability is granted as the set arrives. An enemy standing idle can answer a stimulus before it has picked a combat role.

> **Warning**
>
> Author **Role Reaction Sets** without a **Default Reaction Set** and an enemy that has not been assigned a role gets nothing. Fill in the default as well.

<details>
<summary>Swapping a set while a reaction is running (Advanced)</summary>

A swap takes a mode. **Immediate** cancels the running reaction and swaps now, which is the default. **Wait For Completion** queues the swap and applies it when the reaction finishes, so a boss phase change does not cut a parry in half. Both **Set Runtime Override** and **Clear Runtime Override** take it.

**Set Provided Reaction Set** drives the weapon slot directly for a pawn running its own equipment, and passing nothing falls back to the config. Override **Get Weapon Reaction Set for Role** on the weapon to vary it per role; a weapon deriving from something other than **SEC Weapon Base** adds the **SEC Weapon Reaction Set Provider** interface in Class Settings.

</details>

<details>
<summary>Per-enemy setup without the base classes (Advanced)</summary>

Two components carry reactions. **Reaction Evaluation** sits on the AI controller and does the choosing and the running. **SEC Reaction Set** sits on the pawn, resolves which set applies, and replicates the state a HUD reads.

**Enemy Controller Base** and **Enemy Character Base** ship with them. A custom controller and pawn need them added by hand.

For a pawn with no AI Config at all, **Default Reaction Set** on the pawn's SEC Reaction Set component is the last link in the chain and enough for a test.

</details>

---

## Debug it

```
SEC.Debug.LogReactions 1        // Which rule answered, which declined and why, which reaction won
SEC.Debug.Reactions 1           // Reaction list above each enemy, with priorities and cooldowns
SEC.Debug.Stimulus.Draw 1       // The announced shape, and every pawn it reached
```

`SEC.Debug.All 1` turns every overlay on at once, and `SEC.Debug.WatchPawn <name>` narrows them to one enemy.

Two of them have a per-enemy equivalent that needs no console: **Debug Log Reactions** on the Reaction Evaluation component, and **Debug Overlay Reactions** on the pawn's SEC Reaction Set component.

Saving the asset runs validation, which reports into the **Asset Check** message log and names any reaction with nothing to run.

<details>
<summary>The attack lands and the enemy does nothing (Advanced)</summary>

Read `SEC.Debug.LogReactions 1` first; it names the stage that refused. In the order worth checking:

- **Nothing was announced.** The attacker's montage has no telegraph notify, so no event ever arrived. `SEC.Debug.Stimulus.Draw 1` shows whether anything goes out.
- **The enemy did not notice.** **Stimulus Filters** on the AI Config decide that, and a facing cone or a line of sight filter refuses a blow the enemy could not see. See [Attack Telegraphs](https://rigbak.com/docs/soulslike-combat/attack-telegraphs).
- **No rule matched.** The rule's **On Stimulus** tag has to match the tag the announcement carries, and a context tag can block it.
- **The rule matched and found no answer.** Every reaction it names was on cooldown, disabled, or refused by a gate. The canvas flags a rule wired outside its own category, which answers nothing at all.
- **A reaction is already running.** One runs at a time, and a second request is refused.
- **`SEC.Reaction.BlockReactions` sits on the enemy.** That mutes reactions outright.

</details>

<details>
<summary>What silently drops a reaction before it is picked (Advanced)</summary>

**Category: Identity**

| Property | Value |
| --- | --- |
| Enabled | true |

**Category: Tags**

| Property | Value |
| --- | --- |
| Requires Tags | no tags |
| Block Tags | no tags |

**Category: Cooldown**

| Property | Value |
| --- | --- |
| Cooldown Duration | 5 |
| Initial Cooldown | 0 |
| Randomization (%) | 0.2 |
| Interrupt Refund (%) | 0 |
| Spawn Cooldown Chance | 0 |
| Max Consecutive Uses | -1 |

| Cause | Drops the reaction when |
| --- | --- |
| **Enabled** | It is toggled off. |
| **No execution method** | Nothing is set, or the method is missing data it needs. |
| **Behavior Tree Sequence** | A reaction interrupts what the AI is doing rather than replacing its brain, so that method is refused. |
| **Cooldown or repeat limit** | It is still cooling down, or **Max Consecutive Uses** is spent. |
| **`SEC.Reaction.BlockReactions`** | The tag sits on the enemy's ability system component. |
| **Requires Tags / Block Tags** | The enemy's own tags do not line up. Reactions read the enemy's tags alone, not the target's or the world's. |
| **A gate** | Any gate in **Scoring** answered no. |

The same checks run at selection and again when the reaction starts, so one that stops qualifying in between is dropped rather than started.

</details>

---

<details>
<summary>Firing a reaction from your own Blueprint (Alternative)</summary>

When your game already knows which answer fits, call the controller's **Reaction Evaluation** component directly and leave the trigger rules out of it.

**Execute Reaction** takes the **Reaction ID** and a context struct. Fill in **Target** with the attacker, **Magnitude** with the damage, and **Event Tag** with your own category; the ability reads all of it back through **Get Action Context**.

**Can React** runs the same checks without executing, for a check ahead of time. Pass the attacker as the target override so distance and angle gates measure against it.

**On Stimulus Received** fires for everything the enemy notices, before the rules look at it. Call **Execute Reaction** from that binding and the rules sit the event out, since a rule fires only when nothing already answered. That is the opt-out for a project routing events its own way.

A Reaction Set with no rules authored answers nothing by itself, which leaves this as the only way in.

</details>

<details>
<summary>Replacing the perception or the routing step (Advanced)</summary>

Two overridable events on a Blueprint or C++ subclass of the Reaction Evaluation component each take over one stage.

| Override | Replaces |
| --- | --- |
| **Can Sense Stimulus** | The whole perception step. The default runs every filter in force and requires all of them to pass. |
| **Select Reaction Category** | The whole rule walk. Return a category tag to route an event your own way without authoring rules. |

**Evaluate Best Reaction for Stimulus** is the selection the rules run, with the event carried down so gates and scorers can read which way the blow is arriving. **Evaluate Best Reaction Among Links** narrows that same selection to a named few and applies each link's weight multiplier.

**Fallback Stimulus Filters** on the component covers a pawn running without an AI Config. A config listing any filters replaces that list outright rather than adding to it.

</details>

<details>
<summary>What a reaction hands its ability (Advanced)</summary>

Both actions and reactions pass the same context struct through to the ability, which reads it with **Get Action Context**.

| Field | Carries |
| --- | --- |
| **Target** | Who caused it. Filled in from the event's source for a reaction the rules fired. |
| **Optional Object** | The weapon, the projectile, the item. |
| **Magnitude** | Damage, charge level, intensity, in the producer's own units. |
| **Event Tag** | Which category set this off. |
| **Context Tags** | Situational tags such as an unblockable marker. |
| **Target Data** | Spatial payload, packed with the target data helpers. |
| **Stimulus** | What set this off, filled in for a reaction the rules fired and empty for one started by hand. |

Distance and direction to the target are filled in when the ability activates, along with both sides' gameplay tags.

Override **Can Activate Ability** on the ability, read the context, and return false to refuse. A refusal costs nothing: no cooldown is charged and no running reaction is interrupted.

</details>

<details>
<summary>Multiplayer</summary>

Reactions are chosen and run on the authority. **Receive Stimulus** is server side. A telegraph window announces on every machine playing the montage, and only the machine with authority over the attacker passes the warning on to enemies, so a montage playing on a client reaches no enemy.

The pawn's SEC Reaction Set component replicates what a client needs: the running reaction, the active set, the cooldowns, and delegates for reaction started, completed, set changed, and cooldown started and expired. Bind those for a HUD or client-side effects. See [Multiplayer](https://rigbak.com/docs/soulslike-combat/multiplayer).

</details>

---

## Related

| Page | Why |
| --- | --- |
| [Enemies That Parry, Dodge and Counter](https://rigbak.com/docs/soulslike-combat/enemy-parry-dodge-counter) | A parry, a dodge and a counter set up end to end, as a short guide. |
| [Telegraphs](https://rigbak.com/docs/soulslike-combat/attack-telegraphs) | Where the events come from, how far they carry, and which enemies notice. |
| [Reaction Set Editor](https://rigbak.com/docs/soulslike-combat/reaction-set-editor) | The canvas the rules and reactions are wired on. |
| [Action System](https://rigbak.com/docs/soulslike-combat/action-system) | The poll-driven side, and the scorers and gates both share. |
| [Defense System](https://rigbak.com/docs/soulslike-combat/defense-system) | What the raised guard is worth once the blow arrives. |
| [Vitals](https://rigbak.com/docs/soulslike-combat/vitals) | The health and stamina the scorers and gates read live. |

Previous page: [Action Set Editor](https://rigbak.com/docs/soulslike-combat/action-set-editor). Next page: [Reaction Set Editor](https://rigbak.com/docs/soulslike-combat/reaction-set-editor)
