> For the complete documentation index, see [llms.txt](https://malbersanimations.gitbook.io/animal-controller/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://malbersanimations.gitbook.io/animal-controller/main-components/combo-manager.md).

# Combo Manager

Last updated AC v1.5.3

## Overview

This component uses the Ability Index of a [Mode](/animal-controller/main-components/manimal-controller/modes.md) in the Animal Controller to create combo sequences.

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FQsieTTMprF5PjvVEJo0g%2Fimage.png?alt=media&#x26;token=e5092f3a-104d-411c-97ba-56a14b789178" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Changes in AC v1.5.3**

* New **Combo Set** asset (`Create > Malbers Animations > Combo Set`). Combos can now live in a shareable ScriptableObject. The Combo Manager clones them at runtime, so many characters can use the same asset.
* `SetActiveCombo(ComboSet)` selects a combo by the asset that owns it. Two Combo Sets that share the same Mode ID no longer mix their variations.
* New **Disable On Lock Input** toggle and **Combo Conditions**.
* New manager events: `OnComboRestart`, `OnComboIncomplete`. New runtime properties: `ActiveCombo`, `PlayingCombo`.
* Fixes: null exception at the end of a combo or when the combo was deactivated while its Mode was still playing; selecting the combo that is already playing no longer restarts it; mirrored sequences (negative Ability index) now match their Mode; ending a combo while its Mode was playing no longer drops the pending Mode End.
  {% endhint %}

## Requirements

It requires an Animal Controller component. It does not have to be in the same GameObject as the Animal script. I recommend setting this component in a child GameObject.

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FKsZvOhvEcmUcxqb3gm8f%2Fimage.png?alt=media&#x26;token=d619e570-fa87-4542-a937-45ea3fb79684" alt=""><figcaption></figcaption></figure>

If the **Animal** field is empty the manager searches for an `MAnimal` on itself, its parents and its children when it is enabled. The combo's Mode must exist on that Animal; otherwise an error is logged and the combo cannot play.

## How it Works

The Combo Manager uses Modes to play animations. It checks the right time on the current Ability to play the next Ability, given a **Branch** value. The Branch value is the Input you give the character.

E.g. **Branch 0** is Left Click; **Branch 1** is Right Click. You can have as many branches as you like.

![First: Atk1 +Atk1+Atk1(0-0-0)                               Second: Atk1+Atk1+Atk2 (0-0-1)](https://963537199-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lzhr1XSMzMqNXjRnNlb%2F-MTgvTNYL8WBFRD_vsA8%2F-MTgwLdUSmjDQ85Hg41E%2Fmg2R4BEpeY.gif?alt=media\&token=42094af2-2087-4d5e-9e1d-c630201c0fd9)

{% hint style="info" %}
To play a combo, call the method **`ComboManager.Play(int Branch)`**
{% endhint %}

Connect the method to your Input Provider:

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FYD1XeNeyqxIS0wTvtlkO%2Fimage.png?alt=media&#x26;token=a85a16c6-800c-4ee4-a0a9-0a4251cd569f" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
If you are using the [Weapon Manager](/animal-controller/main-components/weapon-manager.md), there is no need to call the `Play()` method. The [Weapon Manager](/animal-controller/main-components/weapon-manager.md) does it automatically and also selects the active combo when a weapon is equipped or unequipped.
{% endhint %}

The combo can also be played from a **Reaction**: `Malbers > Damage > Play Combo`. It has a single **Branch** value and calls `ComboManager.Play(Branch)` on the target.

### Playing a sequence

1. `Play(branch)` runs the checks in **Parameters** below (enabled, Sleep, Lock Input, Combo Conditions, Timeline, Active Combo, Mode enabled, cooldown).
2. If the Animal is not playing the combo's Mode, the first unused **starter** sequence (Required Ability = 0) that matches the Branch tries to activate its **Play Ability** on the Mode.
3. If the Animal is already playing the combo's Mode, the manager searches the sequences after the current one for the first unused sequence whose **Required Ability** equals the Ability that is playing and whose Branch matches.
   * If the Mode's normalized time is inside the sequence's **Buffer Time** range and past the **Anim** time, the next Ability is force-activated right away.
   * If the Mode time is inside the range but before the **Anim** time, the input is **buffered** and the Ability plays when the animation reaches that time.
   * Outside the range the input is ignored.
4. When the Mode ends, the manager checks the sequence that was playing. A **Finisher** raises `On Combo Finished` and restarts the combo. Any other sequence that ended without the Mode continuing raises `On Combo Interrupted` and `OnComboIncomplete`, then restarts the combo.

### State variations

Several combos can use the same Mode and differ only by their **States** list (e.g. one for Ground, one for Fall). When the Animal changes State, the manager switches to the first combo that shares the active combo's Mode **and origin** (same Combo Set asset, or both authored on the manager) and lists the new State. Combos with a States list must be higher in the list than the unrestricted one; the inspector shows a State icon on those rows to remind you.

### Combo Set (asset)

A **Combo Set** is a ScriptableObject that stores the combos for a single Mode ID. Create it with `Create > Malbers Animations > Combo Set`. The same asset can be shared by many characters: each Combo Manager instantiates its own runtime copy when the set is loaded, so animals never share mutable state.

\[Insert Image - Combo Set asset inspector]

The asset inspector is the same as the Combo Manager's. It draws:

#### Mode

The Mode ID this Combo Set drives (e.g. Attack). It is written into every variation of the set, so the per-combo Mode field is not shown on the asset.

#### Preview Character

Editor-only reference to an `MAnimal`. It is used to show the Ability names and popups on the sequences. It is not saved on the asset.

#### Variations

The list of combos on the set (Active toggle, Index, Name). Each variation has the same fields as a combo on the manager: **States**, **Cool Down**, **Disable On Finish**, **Disable On Interrupt** and the **Combo Sequence List**. Per-sequence events are not drawn on the asset.

A Combo Set reaches a Combo Manager in one of two ways:

* **From code**: `comboSet.Play(comboManager, branch)` loads the set on the manager (once), selects its variation for the current State and plays the branch. Overloads that take a `GameObject` or a `Component` find the Combo Manager on that object, its parents or its children.
* **From the Super Item Combo processor**: the Item Processor Combo has a `comboSet` field and calls `SetActiveCombo(ComboSet)` when the item is equipped and `Play` on use.

{% hint style="info" %}
Loaded sets are appended after the combos authored on the manager. Their combos are removed when the manager is disabled and loaded again when it is enabled, so **Active Combo Index** always points at a valid combo after a disable/enable cycle (e.g. hiding the player).

Combos cloned from a set remember their **Source** asset. Selecting by `SetActiveCombo(ComboSet)` or switching State variations uses that Source, so two sets that share a Mode ID (e.g. a Melee Weapon and a Melee Super Item) never pick each other's combos. Selecting by `SetActiveCombo(ModeID)` still returns the first combo with that Mode ID.
{% endhint %}

## Parameters

Parameters are listed in the order the inspector draws them.

#### Animal

Reference to the Animal component. It is filled automatically when the component is added or enabled if the field is empty.

#### Active Combo \[Name]

Which combo is currently active (`ActiveComboIndex`). Use it when you want to change combos, e.g. when the character equips a weapon. The active combo row shows **(Active)** in the list and is highlighted. Changing the value in Play Mode calls `SetActiveCombo(int)` so the change takes effect at once.

![](https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FOy8S3wOB3kIvcYj48JmB%2FUnity_df8htplJTP.gif?alt=media\&token=2e0b096b-a154-4271-9260-7dbc4afd7c23)

{% hint style="info" %}
If the Active Combo Index is set to **-1**, no combo will play. The Combo Manager is disabled internally.
{% endhint %}

The **Debug** icon next to this field logs every decision the manager takes (failed checks, buffered sequences, finished or interrupted combos) with the animal and combo names.

#### Branch

Current Branch ID for the combo sequence. For example, set Branch 0 for Mouse Left Click and 1 for Mouse Right Click. Changing the Branch value in the middle of a sequence allows different animation variations in a single combo. `Play(int)` writes this value before playing.

#### Disable On Sleep

If the Animal Controller is Sleep, the Combo Manager is disabled internally too. It also blocks the State variation swap.

#### Disable On Lock Input

If the Animal has **Lock Input** enabled, the Combo Manager is disabled internally.

{% hint style="info" %}
Turn this **OFF** for Riders. Mounting sets the rider's Animal to Sleep, which also sets Lock Input, and that would veto every mounted combo. Each veto reports its own reason on the Debug log.
{% endhint %}

#### Combo Conditions

Conditions evaluated on the Animal every time a combo tries to play. If the conditions are not met the combo is not played.

\[Insert Image - Combo Conditions field]

## Combo List

Combos are groups of sequences that activate a new [**Mode**](/animal-controller/main-components/manimal-controller/modes.md) **Ability** on the Animal using the activation time of the current/Required Mode Ability.

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2Fjv5oa5NTfyn5SfvSWxiM%2Fimage.png?alt=media&#x26;token=11e2a1d6-bc56-4a09-831b-519c87d1926c" alt=""><figcaption></figcaption></figure>

#### Active

Toggle to enable or disable the combo. A disabled combo does not play. **Disable On Finish** and **Disable On Interrupt** clear this toggle at runtime; use `Combo_Enable` to set it again.

#### Index

Index of the combo. Use it to set the current active combo with **`ComboManager.SetActiveCombo(int Index)`**. An example is when a new weapon is equipped: the active combo changes from Unarmed to Melee.

#### Name

Name of the combo. Use it if you do not want to use the index value, with **`ComboManager.SetActiveCombo(string Name)`**. The search is case-insensitive for `Combo_Enable`/`Combo_Disable`, exact for `SetActiveCombo(string)` and `ResetCoolDown(string)`.

#### Mode

The Mode that will be used in the combo. The Mode must exist on the Animal. On a Combo Set this field is set once on the asset and copied to every variation.

Select a combo on the list to expand its settings:

#### States

States the combo can be played on. Leave it empty to allow every State. The manager uses this list to swap between State variations (see **How it Works**).

#### Cool Down

After the combo is finished (with a Finisher) or interrupted, it cannot play again until this time (seconds) has passed. `0` means no cooldown. `ResetCoolDown(name)` clears it.

#### Disable On Finish

Disable the combo after it has been completed to the last sequence (Finisher).

#### Disable On Interrupt

Disable the combo if the sequence was not completed.

## Sequences

Each sequence holds the values needed to activate the proper animation at the proper time.

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FQluWpXd8MVp9umZr3j1S%2Fimage.png?alt=media&#x26;token=26dcda9a-1ffe-4f69-95d7-2fd5047904c8" alt=""><figcaption></figcaption></figure>

#### Index

Position of the sequence in the list. The manager searches forward from the current sequence, so order matters.

#### Branch

Helps activate different sequences with different inputs. Use **-1** to let the sequence play on any Branch.

#### Required Ability

The Ability that must be playing on the Mode for this sequence to activate. Use the popup next to the field to pick an Ability of the Mode.

{% hint style="success" %}
If it is set to **Zero** the sequence is a **Combo Starter**.

It is recommended that all combo starters are placed at the top of the list. They are color coded in <mark style="color:green;">**green**</mark>**.**
{% endhint %}

#### Play Ability

The Ability to activate on the Mode when the Required Ability is within the Buffer Time range.

{% hint style="info" %}
A **negative** index plays that Ability **mirrored** (e.g. `-102` plays Ability 102 inverted), the same as on the Mode. Since v1.5.3 mirrored sequences are matched correctly when the Mode ends, and the Finisher toggle is shown for them.
{% endhint %}

#### Finisher

Marks the sequence as the Finisher animation of the combo. It is color coded in **Cyan**. A starter (Required Ability 0) cannot be a Finisher. When a Finisher ends, `On Combo Finished` is raised, the cooldown starts and the combo restarts.

#### Restarter (R)

Only shown on a Finisher. If enabled, calling `Play` while the Finisher is playing and past the **Finisher Time** restarts the combo from a starter without waiting for the Mode to end.

#### Finisher Time

Only shown on a Restarter. Normalized time (0-1) of the Finisher animation that must pass before the combo can restart.

#### Buffer Time \[Ab:N]

Range in normalized time of the Required Ability animation. If you call `Play` within that range, the next sequence is activated (or buffered).

#### Anim

Normalized time of the Required Ability animation at which the Play Ability actually starts. If the input arrives inside the Buffer Time range but before this time, the sequence is buffered and plays when the animation reaches it. The Anim time is usually inside the Buffer Time range.

All sequences use a Mode **Ability** index to identify which animation can be activated:

![Steve Attack Mode and its Abilities Index. E.g. Right Punch Index is 1](https://963537199-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lzhr1XSMzMqNXjRnNlb%2F-MTgzaaKunHhQCnSX1Mg%2F-MTh1VxDXGGrDSbd7dBo%2Fimage.png?alt=media\&token=686fe6f6-a557-4e6a-828d-79a53f40b87a)

In Play Mode the list is color coded: unused sequences are **green**, the sequence playing is **yellow** (orange when it is the Finisher) and used sequences are **gray**. With Debug enabled the inspector also shows the runtime values **Playing Combo**, **ActiveCombo** and **ActiveComboSequence**.

## Events

<figure><img src="https://963537199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lzhr1XSMzMqNXjRnNlb%2Fuploads%2FWVHcQZb2WOX6E90momnl%2Fimage.png?alt=media&#x26;token=7e6ae1e4-6c17-4d7c-8063-d6bc2943dd56" alt=""><figcaption></figcaption></figure>

### Inspector events

| Event                          | Where             | Value                                           | Invoked when                                                       |
| ------------------------------ | ----------------- | ----------------------------------------------- | ------------------------------------------------------------------ |
| **On Sequence Play** (Int)     | Selected sequence | `Mode ID * 1000 + Ability`                      | The sequence starts playing.                                       |
| **On Combo Finished** (Int)    | Per combo         | `Mode ID * 1000 + Ability` of the Finisher      | The combo played a Finisher sequence, or a Restarter restarted it. |
| **On Combo Interrupted** (Int) | Per combo         | `Mode ID * 1000 + Ability` of the last sequence | The Mode ended and the combo **did not** play a Finisher.          |

The per-combo events are drawn on the Combo Manager only. They are not drawn on a Combo Set asset.

### Code events

These are plain `System.Action` fields on the Combo Manager. Subscribe from code.

| Event               | Invoked when                                                                                                            |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `OnComboRestart`    | `Restart()` runs: after a Finisher, after an interruption, or after a combo was ended while its Mode was still playing. |
| `OnComboIncomplete` | The Mode ended without a Finisher (same moment as the per-combo On Combo Interrupted).                                  |
| `OnComboFinished`   | Declared on the manager but **not raised** in v1.5.3. Use the per-combo **On Combo Finished** event instead.            |

{% hint style="info" %}
Since v1.5.3 the manager keeps `PlayingCombo` true while the outgoing combo's Mode is still playing, even if you select another combo or call `SetActiveCombo(-1)`. The pending Mode End then reaches the manager and `Restart()` raises `OnComboRestart` on the frame the animation really ends. Systems that wait for that callback (e.g. a Super Item Combo action) are no longer left playing forever.
{% endhint %}

## Functions and Methods

### Combo Manager

```csharp
// Play the active combo on the current Branch
public virtual void Play();
public virtual bool TryPlay();

// Set the Branch and play the active combo on it
public virtual void Play(int branch);
public virtual bool TryPlay(int branch);

// Set the Branch value without playing
public virtual void SetBranch(int branch);

// Select the active combo. -1 disables all combos
public virtual void SetActiveCombo(int index);
public virtual void SetActiveCombo(IntVar index);
public virtual void SetActiveCombo(string ComboName);

// Select the first combo with this Mode ID that can play on the current State. null = -1
public virtual void SetActiveCombo(ModeID ComboMode);

// Select the variation owned by a Combo Set asset that can play on the current State.
// Loads the set on this manager if needed. null = -1
public virtual void SetActiveCombo(ComboSet asset);

// Clone a Combo Set into this manager (once per asset). Returns its runtime combos
public List<Combo> LoadComboSet(ComboSet asset);

// Reset the sequence index, clear PlayingCombo and raise OnComboRestart
public virtual void Restart();

// Enable or disable a combo by index or by name (case-insensitive)
public virtual void Combo_Enable(int index);
public virtual void Combo_Disable(int index);
public virtual void Combo_Enable(string name);
public virtual void Combo_Disable(string name);
public virtual void Combo_Enable(string name, bool value);

// Clear the cooldown of a combo by name
public void ResetCoolDown(string name);
```

| Property                                | Type             | Description                                                                                 |
| --------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------- |
| `animal`                                | `MAnimal`        | Animal the manager drives.                                                                  |
| `Branch`                                | `int`            | Current Branch value.                                                                       |
| `combos`                                | `List<Combo>`    | Combos authored on the manager, plus the runtime clones of loaded Combo Sets while enabled. |
| `comboAssets`                           | `List<ComboSet>` | Combo Set assets loaded when the manager is enabled.                                        |
| `ComboConditions`                       | `Conditions2`    | Conditions checked before playing.                                                          |
| `ActiveComboIndex`                      | `IntReference`   | Index of the active combo. -1 = none.                                                       |
| `ActiveCombo`                           | `Combo`          | The active combo, or null.                                                                  |
| `ActiveComboSequence`                   | `ComboSequence`  | The sequence playing on the active combo, or null.                                          |
| `ActiveComboSequenceIndex`              | `int`            | `Mode ID * 1000 + Ability` of the playing sequence.                                         |
| `PlayingCombo`                          | `bool`           | True while a combo sequence is in flight.                                                   |
| `DisableOnSleep` / `DisableOnLockInput` | `bool`           | See Parameters.                                                                             |

`SetActiveCombo(ModeID)` and `SetActiveCombo(ComboSet)` do nothing when the combo found is already the active one, so a combo in progress is not restarted.

### Combo Set

```csharp
// Load the set on the manager (once), select its variation for the current State and play the branch
public bool Play(ComboManager manager, int branch);

// Find the Combo Manager on the object, its parents or its children, then Play
public bool Play(GameObject gameObject, int branch);
public bool Play(Component component, int branch);
```

| Property | Type          | Description                         |
| -------- | ------------- | ----------------------------------- |
| `Mode`   | `ModeID`      | Mode ID applied to every variation. |
| `combos` | `List<Combo>` | The variations of the set.          |

### Combo

```csharp
// True while the cooldown has not passed
public bool InCoolDown { get; }

// Clear the cooldown
public void ResetCoolDown();

// True if the States list is empty or contains the State
public bool HasState(StateID activeState);
```

| Property                                 | Type                   | Description                                                                         |
| ---------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------- |
| `active`                                 | `bool`                 | Combo enabled.                                                                      |
| `Name`                                   | `string`               | Combo name.                                                                         |
| `Mode`                                   | `ModeID`               | Mode used by the combo.                                                             |
| `CachedMode`                             | `Mode`                 | The Mode instance found on the Animal.                                              |
| `States`                                 | `IDListCheck<StateID>` | States the combo can play on.                                                       |
| `CoolDown`                               | `FloatReference`       | Cooldown in seconds.                                                                |
| `DisableOnFinish` / `DisableOnInterrupt` | `BoolReference`        | See Combo List.                                                                     |
| `Sequence`                               | `List<ComboSequence>`  | The sequences.                                                                      |
| `CurrentSequence`                        | `ComboSequence`        | Sequence playing, or null.                                                          |
| `ActiveSequenceIndex`                    | `int`                  | Index of the playing sequence in `Sequence`.                                        |
| `ComboIndex`                             | `int`                  | Index of the combo on the manager.                                                  |
| `Source`                                 | `ComboSet`             | Combo Set asset the combo was cloned from. Null for combos authored on the manager. |
| `OnComboFinished` / `OnComboInterrupted` | `IntEvent`             | See Events.                                                                         |

### Combo Sequence

| Property                 | Type          | Description                                |
| ------------------------ | ------------- | ------------------------------------------ |
| `Activation`             | `RangedFloat` | Buffer Time range (0-1).                   |
| `ActivationTime`         | `float`       | Anim time (0-1).                           |
| `PreviewsAbility`        | `int`         | Required Ability. 0 = starter.             |
| `Ability`                | `int`         | Play Ability. Negative = mirrored.         |
| `Branch`                 | `int`         | Branch. -1 = any.                          |
| `Finisher` / `Restarter` | `bool`        | See Sequences.                             |
| `FinisherTime`           | `float`       | Finisher Time (0-1).                       |
| `Used`                   | `bool`        | The sequence already played on this run.   |
| `Buffer`                 | `bool`        | The sequence is waiting for its Anim time. |
| `OnSequencePlay`         | `IntEvent`    | See Events.                                |
