# Step-by-Step Enemy Creation

> Build one enemy end to end: pawn, controller, a moveset with a combo, a weapon that lands its hits, and something to fight.

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

> One enemy, from an empty project to a real fight: it holds its range, circles, opens with a light attack, chains into a heavy, and gives ground when you crowd it.

## Set it up (5 minutes)

1. **Make the pawn and the controller**

   Right-click in the Content Browser, **Blueprint Class**, **All Classes**, and pick **Enemy Character Base**. Name it `BP_Grunt`, assign your skeletal mesh, and size the capsule.

   Do it again from **Enemy Controller Base** and name that one `BP_GruntController`.

   Both arrive carrying every component the AI needs.
2. **Create the moveset**

   Right-click in the Content Browser, **SEC**, **Actions**, **Action Set**, and name it `DA_ActionSet_Grunt`. It opens on its own card canvas.

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

   *Right-click in the Content Browser, SEC, Actions, Action Set.*

   Right-click the canvas, choose **Add Action**, and name the **Action ID** `LightAttack`. Set **Ability Class** to **GA_SEC_MontageAbility**, which ships with the plugin, and point the **Montage** underneath it at your attack animation. Add a **Distance Scorer** to the card's **Scoring > Scorers** list.
3. **Create the AI Config**

   Right-click in the Content Browser, **SEC**, **AI**, **Enemy AI Config**, and name it `EnemyConfig_Grunt`.

   Create the asset: right-click in the Content Browser, choose **SEC > AI > Enemy AI Config**, and name it **EnemyConfig_Grunt**.

   *Right-click in the Content Browser, SEC, AI, Enemy AI Config.*

   Set **Default Action Set** to the moveset and **Target Selector** to **Closest Target Selector**.

   The enemy also needs senses. Create an **Awareness Config** from the same **SEC** menu, name it `DA_Awareness_Grunt`, leave its defaults alone, and point the AI Config's **Awareness Config** field at it. Those defaults are a working guard: 1500 cm of sight across a 180 degree cone, 1200 cm of hearing, and a damage sense that reveals whoever hits it from behind.

   In **EnemyConfig_Grunt** set:

   | Property | Value |
   | --- | --- |
   | Target Selector | Closest Target Selector (replaces None) |
   | Awareness Config | DA_Awareness_Grunt (replaces None) |
   | Manage Action Sets Automatically | true |
   | Default Action Set | DA_ActionSet_Grunt |

   *Target Selector and Awareness Config both ship empty. Without a selector the enemy takes the first target it may fight; without an awareness config it fights the target it is given without sensing it first. The rest of the config has working defaults.*
4. **Wire the pawn to both**

   Open `BP_Grunt`, go to **Class Defaults**, and set **AI Controller Class** to `BP_GruntController` and **AI Config** to `EnemyConfig_Grunt`.

   In **BP_Grunt**, under Class Defaults, set:

   | Property | Value |
   | --- | --- |
   | AI Controller Class | BP_GruntController |
   | AI Config | EnemyConfig_Grunt |

   *The controller reads the pawn's config on possession, so one controller class serves many enemy types.*
5. **Register the player, and play**

   On the player pawn's **Event BeginPlay**, add the **AICombat Role Subsystem** node and call **Register Combat Target** with **Target Actor** set to **Self** and **Auto Assign Unassigned** ticked.

   Blueprint graph, nodes in reading order:

   - **Comment box: Player pawn · Event BeginPlay**

     - **AICombatRoleSubsystem** (subsystem getter)
     - **Register Combat Target** (function; Target is AICombat Role Subsystem); inputs: Target, Target Actor = Self, Auto Assign Unassigned = true, Reevaluate Existing = false

   Drop `BP_Grunt` into a level with a built NavMesh and press Play. Walk into its sight cone: it closes to about 400 cm, circles you, and swings when you come into range.

> **Warning**
>
> An enemy fights only targets in the shared target pool, and with none it does nothing at all: no movement, no attacks, no reactions. Registering the player puts you there from the start. Without that step the enemy adds you only once it detects you, and an enemy with no Awareness Config never does. See [Targeting](https://rigbak.com/docs/soulslike-combat/targeting-system).

The rest of this page turns that one attack into a fight.

---

## Build the pawn and the controller

`BP_Grunt` arrives with an ability system, melee traces, vitals, defenses, equipment, and the action, reaction and role components. `BP_GruntController` arrives with the parts that decide: movement, action scoring, reactions, awareness, threat, and the brain that ticks them.

Set the pawn up like any character. Assign the skeletal mesh, size the capsule to it, and set **Max Walk Speed** on its Character Movement component to around 400.

Nothing else on either Blueprint needs touching to get a fight running.

<details>
<summary>Use a character you already have (Alternative)</summary>

Reparent it instead of rebuilding it.

1. Open your character Blueprint.
2. **File > Reparent Blueprint**, and pick **Enemy Character Base**.
3. Your existing components, variables and graphs stay, and you inherit the ability system, the combat components and the combat interfaces.
4. Delete any duplicate the Blueprint already added itself, so only the inherited copies remain.
5. Set **AI Config** on Class Defaults, then assign the mesh and the controller as usual.

The inherited ability system needs no setup call. An Ability System Component on a pawn starts itself up, whether it comes from the base class or your Blueprint adds it.

A character that has to inherit from some other C++ class cannot reparent. [API Reference](https://rigbak.com/docs/soulslike-combat/api-reference) covers rebuilding the pawn from a different base.

</details>

<details>
<summary>Use an AI controller you already have (Alternative)</summary>

Reparent it to **Enemy Controller Base** the same way, and you inherit the evaluators, the behavior-tree helper, the committed-attack rotation lock, smooth focus, and awareness-based facing.

Adding the components to a bare AI Controller is not the same thing. The base holds the pawn's facing during an attack and turns it toward a target's last-known location, and attack abilities read the controller for that lock. A plain controller keeps tracking the player mid-swing and carries none of that facing work.

The base puts that on Blueprint nodes: **Lock Rotation By** and **Unlock Rotation By** freeze and release facing around a committed attack, and **Is Rotation Locked** reads the current state. Override **Get Desired Facing Location** to redirect where the pawn looks each frame.

</details>

---

## Build the moveset

One action is enough to see an enemy attack. A fight needs several that win at different ranges and moments. Open `DA_ActionSet_Grunt` and add the three below.

A new card ships with an empty **Scorers** list, so it scores the same at every distance and angle until you add one.

*Interactive diagram on the page: Each scorer multiplies in; each gate can veto. Mix built-ins with Blueprint subclasses of your own.*

### The light attack

**Category: Identity**

| Property | Value |
| --- | --- |
| Action ID | LightAttack |
| Enabled | true |

**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_Attack_Light |

**Category: Scoring**

| Property | Value |
| --- | --- |
| Selection Weight | 1 |
| Scorers | 2 Array elements |
| Gates | 0 Array elements |

**Category: Scoring > Index [ 0 ] Distance Scorer**

| Property | Value |
| --- | --- |
| Min Value | 0 |
| Optimal Min | 100 |
| Optimal Max | 250 |
| Max Value | 500 |

**Category: Scoring > Index [ 1 ] Angle Scorer**

| Property | Value |
| --- | --- |
| Min Value | 0 |
| Optimal Min | 0 |
| Optimal Max | 30 |
| Max Value | 90 |

**Category: Chaining**

| Property | Value |
| --- | --- |
| Chain Links | 1 Array element |
| Chain Links > HeavyAttack > Target Action ID | HeavyAttack |
| Chain Links > HeavyAttack > Bonus Multiplier | 1.5 |

**Category: Cooldown**

| Property | Value |
| --- | --- |
| Cooldown Duration | 2 |
| Initial Cooldown | 1 |

Distance ranges are in centimeters and angle ranges in degrees. Each one scores 1 between **Optimal Min** and **Optimal Max** and falls to 0 at **Min Value** and **Max Value**, so this attack peaks between 100 and 250 cm, fades out by 500, and wants the enemy facing you. **Initial Cooldown** keeps it from being the opening move. The **Chain Links** row is what feeds the heavy attack below.

### The heavy attack, as the combo finisher

**Category: Identity**

| Property | Value |
| --- | --- |
| Action ID | HeavyAttack |
| Enabled | true |

**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_Attack_Heavy |

**Category: Scoring**

| Property | Value |
| --- | --- |
| Selection Weight | 0.8 |
| Risk Penalty | 1.5 |
| Scorers | 1 Array element |

**Category: Scoring > Index [ 0 ] Distance Scorer**

| Property | Value |
| --- | --- |
| Min Value | 0 |
| Optimal Min | 150 |
| Optimal Max | 300 |
| Max Value | 450 |

**Category: Cooldown**

| Property | Value |
| --- | --- |
| Cooldown Duration | 4 |

A **Selection Weight** under 1 and a **Risk Penalty** over 1 both bias against this coming up on its own, which is what leaves room for the combo. The light attack's chain link names `HeavyAttack` with a **Bonus Multiplier** of 1.5, so the heavy scores 50% higher for a short window once the light completes.

An interrupt or a cancel clears that window, so a parried enemy cannot combo out of the hit it took.

### The retreat, for when you crowd it

**Category: Identity**

| Property | Value |
| --- | --- |
| Action ID | QuickRetreat |
| Enabled | true |

**Category: Execution**

| Property | Value |
| --- | --- |
| Execution Method | Behavior Tree Sequence |
| Execution Method > Behavior Tree Sequence | 1 Array element |
| Execution Method > Behavior Tree Sequence > Index [0] | BT_QuickBackstep |

**Category: Scoring**

| Property | Value |
| --- | --- |
| Selection Weight | 1.5 |
| Scorers | 1 Array element |
| Tag Score Multipliers | YourGame.State.PlayerAttacking = 2.0 |

**Category: Scoring > Index [ 0 ] Distance Scorer**

| Property | Value |
| --- | --- |
| Min Value | 0 |
| Optimal Min | 0 |
| Optimal Max | 100 |
| Max Value | 200 |

**Category: Cooldown**

| Property | Value |
| --- | --- |
| Cooldown Duration | 3 |

This one runs a behavior tree rather than an ability. Build `BT_QuickBackstep` as a one-node tree around the **Make Distance** task, which backs the pawn away from its target until it reaches a distance you set.

Its **Distance Scorer** peaks close in, from 0 to 100 cm, so it wins exactly when you have crowded the enemy. The **Tag Score Multipliers** row is optional, and the tag in it comes from your project rather than the plugin. `YourGame.State.PlayerAttacking` stands in for a tag you define yourself and apply for the length of a player swing, which doubles the retreat score while the player is committed to an attack. Leave the row empty and the retreat still picks itself on distance alone.

> **Note**
>
> **Tag Score Multipliers** takes any gameplay tag and scales the score while the AI, the target or the world holds it. The plugin declares `SEC.State.Staggered` for a reaction montage to hold, so 2.0 on that tag makes a punish. A tag of your own works the same way: `YourGame.Phase.BossPhase2` at 1.3 makes an enemy meaner late in a fight. The [Action System](https://rigbak.com/docs/soulslike-combat/action-system) covers scoring in full.

---

## Make the swings land

The montages play, but nothing takes damage until a swept trace runs over the strike frames.

1. Build the weapon on **SEC Weapon Base**, and place sockets at the hilt and the tip of its mesh.
2. Add one **Trace Sockets** entry and set its **Shape** to **Capsule Two Point**, which reveals **End Socket or Bone Name**. Name the hilt socket in **Socket or Bone Name** and the tip in **End Socket or Bone Name**, so the capsule spans the blade. The default **Sphere** sweeps a single point.
3. Select the pawn's **SEC Equipment Component** and add the weapon class to **Starting Loadout**, with **Use as Weapon** ticked.
4. Open each attack montage, add a **SEC Melee Trace Window** notify state, and drag it across the frames that connect.
5. Set the window's **Damage Config**. Six ship under `Core/Damage`, one per damage type.

[Weapons](https://rigbak.com/docs/soulslike-combat/weapons) covers the weapon Blueprint, and [Melee Trace](https://rigbak.com/docs/soulslike-combat/melee-trace) covers the sweep shapes, damage and impact effects.

A weapon can also carry its own moveset in **Weapon Action Set**, which wins over the AI Config while the enemy holds it. Hand the same skeleton a bow and it fights like an archer.

> **Warning**
>
> A trace window sweeps sockets that were registered before it opened, and a weapon registers its own the moment the enemy equips it. An enemy that spawns unarmed swings through everything. The Output Log names any socket ID a window asked for that nothing registered.

---

## Give it ground to hold

The Movement Evaluator on the controller ships with a working default, so the enemy already closes to 400 cm and circles. Author a **Movement Behavior Profile** when you want that range to be part of the enemy's design: 250 cm for a brawler, 600 for something that hangs back.

Create one under **SEC**, **AI**, **Movement Behavior Profile**, set **Desired Distance**, then set **Default Movement Profile** on the AI Config. See [Movement System](https://rigbak.com/docs/soulslike-combat/movement-system).

---

## Let it answer a hit

An enemy that only attacks reads as a punching bag. Author a **Reaction Set** with a flinch, a parry or a dodge, wire a trigger to each on its canvas, and set **Default Reaction Set** on the AI Config. See [Reaction System](https://rigbak.com/docs/soulslike-combat/reaction-system).

---

## Debug it

Press Play and turn the overlays on:

```
SEC.Debug.Scoring 1              // Score list above each enemy, highest first
SEC.Debug.Actions 1              // Cooldown list above each enemy
SEC.Debug.Movement 1             // Movement layer, strafe side and heading
SEC.Debug.Role 1                 // Name and combat role, colored by role
SEC.Debug.Melee.DrawTracing 1    // The swept shape, every frame a window is open
```

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

For a record you can scroll back through, `SEC.Debug.LogActionDecisions 1` prints why each action scored what it did:

```
LogSECActions: [EvalComp] LightAttack: Ctx=0.95 Nov=1.00 Chain=1.00 Risk=1.00 Runtime=1.00 Custom=0.95 -> 0.90
LogSECActions: [EvalComp] HeavyAttack: Ctx=0.40 Nov=1.00 Chain=1.00 Risk=0.67 Runtime=1.00 Custom=0.40 -> 0.11
LogSECActions: [EvalComp] Committed to: LightAttack (score 0.90)
```

Every scorer on a card folds into the single **Custom** figure rather than getting a column of its own. To read one scorer at a time, open the Action Set while the game runs: the [Action Set Editor](https://rigbak.com/docs/soulslike-combat/action-set-editor#watching-the-ai-decide) lights each card up with its live score, its cooldown, and the gate that refused it.

Expect the enemy to close to its range, circle, open with a light attack, sometimes chain into the heavy, and back off when you crowd it.

---

<details>
<summary>It stands there and does nothing (Advanced)</summary>

In the order worth checking:

- **No combat target.** The player was never registered and no enemy has detected you yet, so the target pool is empty. This failure is silent, and it is the common one.
- **The enemy has not sensed you.** With an Awareness Config set, the enemy fights only what it has noticed: stand inside its 180 degree sight cone, within 1500 cm. Run `SEC.Debug.Awareness 1` to read the state above its head. With the field empty the built-in brain skips sensing and fights its target at once, while a StateTree that gates its combat on the **Awareness State At Least** condition never enters combat.
- **No NavMesh.** Add a **NavMeshBoundsVolume** and build navigation.
- **Target Selector is empty** on the AI Config and in project settings. That alone does not stall the enemy: it takes the first target it may fight, one registered after it started included. Check it when the enemy engages the wrong target.
- **AI Controller Class** on the pawn points at a controller not made from **Enemy Controller Base**, such as the engine's **AIController**.
- **AI Config** is empty on both the pawn and the controller, so no set resolves.

</details>

<details>
<summary>It picks a move, and nothing happens (Advanced)</summary>

- **The ability has no activation graph.** An ability implementing neither **Activate Ability** nor **Activate Ability From Event** starts and never ends, and the enemy locks up behind it. **Ability Timeout** on the execution method cuts a hung ability off and names it in the log.
- **The Montage Payload has no montage.** Saving the Action Set reports this into the **Asset Check** message log.
- **The Action ID is empty.** An action with no ID cannot be found again, so the execution that follows the poll drops it. Nothing prints unless `SEC.Debug.LogActionExecution 1` is on. Name it on the canvas.
- **Enabled is unticked**, which also stops the ability being granted.
- **Manage Action Sets Automatically is unticked** on the AI Config, which applies no set at all.

</details>

<details>
<summary>It repeats one move, or swings from across the room (Advanced)</summary>

Both come from missing scorers. A card with an empty **Scorers** list scores the same everywhere, so it wins at every range and the others never get a look in.

Give each action its own **Distance Scorer** with a different band, and an **Angle Scorer** where facing matters. Then set **Cooldown Duration**, which defaults to 0, and **Max Consecutive Uses** to force a switch after a set number of repeats.

**Recovery** on the AI Config puts a gap between any two attacks rather than between two uses of one attack. It defaults to 0, so it stays off until you set **Action Recovery Time**.

</details>

<details>
<summary>The weapon swings through the player (Advanced)</summary>

- **The Socket IDs on the montage notify do not match the weapon's Trace Sockets ID.** They are matched by name.
- **Use as Weapon is unticked** on the loadout entry, so the weapon spawns and attaches while none of it reaches the enemy.
- **The window sits on the wrong frames.** `SEC.Debug.Melee.DrawTracing 1` draws the swept shape so you can see where it opened.
- **The target refuses the hit.** A pawn answering as **SEC Damageable** can block, parry or shrug a hit off. See [Defense System](https://rigbak.com/docs/soulslike-combat/defense-system).

</details>

<details>
<summary>Structure the fight with a StateTree (Alternative)</summary>

Leave **Default State Tree** empty on the AI Config and a native loop runs the combat you built: gather context, move, then score and run the best action.

The loop already patrols a [Territory](https://rigbak.com/docs/soulslike-combat/territory), investigates what the enemy half noticed, and walks home after a fight. Set **Default State Tree** to `ST_SEC_Core`, which ships in the demo content, or author your own, when you want to edit that flow as a graph or the enemy needs structure the loop has no opinion about, such as boss phases. The graph nodes are on [StateTree Tasks](https://rigbak.com/docs/soulslike-combat/statetree).

Both routes use the same Action Sets, Reaction Sets and movement profiles, so swapping between them changes no data.

</details>

<details>
<summary>Give each combat role its own moveset (Alternative)</summary>

**Role Action Sets** on the AI Config hands each [combat role](https://rigbak.com/docs/soulslike-combat/combat-roles) a different set, so a Flanker opens differently from an Attacker, and the swap happens on its own when the role changes. **Role Reaction Sets** and **Role Movement Profiles** do the same for reactions and positioning.

Fill in **Default Action Set** alongside them. A role you did not list falls back to it, and an enemy that has not been assigned a role gets nothing without it.

</details>

<details>
<summary>Editing while the game runs (Advanced)</summary>

Tuning values on an existing action during Play In Editor is safe, and the running enemy picks the change up on its next decision. Adding, deleting or renaming an action goes through, but a running enemy holds positions in the list and the entries move underneath it. The editor warns you once per session in the message log when you do it. Restart Play In Editor after those.

</details>

---

Previous page: [Getting Started](https://rigbak.com/docs/soulslike-combat/getting-started). Next page: [Minimal Enemy](https://rigbak.com/docs/soulslike-combat/minimal-enemy)
