---
# System prepended metadata

title: Sequencer

---

---
title: "Sequencer"
---

<style>

html, body, .ui-content {
    background-color: #333;
    color: #ddd;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
    color: #ddd;
}

.markdown-body h1,
.markdown-body h2 {
    border-bottom-color: #ffffff69;
}

.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
    color: #fff;
}

.markdown-body img {
    background-color: transparent;
}

.ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a {
    color: white;
    border-left: 2px solid white;
}

.expand-toggle:hover, 
.expand-toggle:focus, 
.back-to-top:hover, 
.back-to-top:focus, 
.go-to-bottom:hover, 
.go-to-bottom:focus {
    color: white;
}


.ui-toc-dropdown {
    background-color: #333;
}

.ui-toc-label.btn {
    background-color: #191919;
    color: white;
}

.ui-toc-dropdown .nav>li>a:focus, 
.ui-toc-dropdown .nav>li>a:hover {
    color: white;
    border-left: 1px solid white;
}

.markdown-body blockquote {
    color: #bcbcbc;
}

.markdown-body table tr {
    background-color: #5f5f5f;
}

.markdown-body table tr:nth-child(2n) {
    background-color: #4f4f4f;
}

.markdown-body code,
.markdown-body tt {
    color: #eee;
    background-color: rgba(230, 230, 230, 0.36);
}

a,
.open-files-container li.selected a {
    color: #5EB7E0;
}

</style>

# Sequencer
[TOC]

#### Links
> Blade & Sorcery Discord server: https://discord.gg/bladeandsorcery
> Discord Forum: https://discord.com/channels/327809947272478720/1196482135398293575
> GitHub Repo: https://github.com/ksmto/Sequencer
> Download: https://github.com/ksmto/Sequencer/releases/tag/sequencer
> Documentation: https://hackmd.io/@ksmto/kseqencer

To get the DLL file, go the the GitHub repository or the Discord forum to retrieve it.

## How to Use
(Note: this is an example using an item behaviour component!)
In your class make a field of the type "Sequencer" like this:
```csharp    
public class SequencerExample : MonoBehaviour
{
    private Item _item;

    // Initialize and start our sequencer
    private readonly Sequencer _sequencer = Sequencer.Start();

    // When our item is spawned
    private void Start()
    {
        _item = GetComponent<Item>();
    }
}
```

Now in a Update method, use the "_sequencer.Update()" function. This will ensure the Sequencer is continuously checking for new sequences.
```csharp    
public class SequencerExample : MonoBehaviour
{
    private Item _item;

    // Initialize and start our sequencer
    private readonly Sequencer _sequencer = Sequencer.Start();

    // When our item is spawned
    private void Start()
    {
        _item = GetComponent<Item>();
    }

    // Runs every frame of the game, while the item is spawned
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

Finally, in a Start method you can check conditions, like this:
```csharp    
public class SequencerExample : MonoBehaviour
{
    private Item _item;

    // Initialize and start our sequencer
    private readonly Sequencer _sequencer = Sequencer.Start();

    // When our item is spawned
    private void Start()
    {
        _item = GetComponent<Item>();

        if (_item != null && _item.mainHandler != null)
        {
            // Use the sequencer to check if we pressed the alternate use button while holding it, if so, despawn the item
            _sequencer?.If(() => _item.mainHandler.playerHand.controlHand.alternateUsePressed).Do(_item.Despawn);
        }
    }

    // Runs every frame of the game, while the item is spawned
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

## Functions & Conditions
There are a few functions when using the Sequencer, so lets jump right in.

### Start
First, we have Start. Start initializes and starts the sequencer. Use this when creating the field for your Sequencer, like this:
```csharp=
public class SequencerExample
{
    private Sequencer _sequencer = Sequencer.Start();
}
```

### Update
Next we have Update, Update makes the Sequencer run and check conditions continuosly, you need to put it inside of an Update method to ensure the Sequencer is continuously checking for new sequences! Here's an example in MonoBehaviour:
```csharp=
public class SequencerExample : MonoBehaviour
{
    // Initialize and start our sequencer
    private Sequencer _sequencer = Sequencer.Start();
    
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

### Do
The Do method is used to do something, it can also be used alone, use it in Start like this:
```csharp=
public class SequencerExample : MonoBehaviour
{
    // Initialize and start our sequencer
    private Sequencer _sequencer = Sequencer.Start();
    
    private void Start()
    {
        // Alone
        _sequencer.Do(() => DO_SOMETHING);
        
        // Chained
        _sequencer.If(() => CONDITION).Do(() => DO_SOMETHING);
    }
    
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

Now we're getting into the condition checkers, these will be used to execute functions and check if something happened.
:::danger
NOTE: The statment methods (If and While) are MEANT to be used in Start!!
:::

### If
The If method checks if a condition was met, use it in Start like this:
```csharp=
public class SequencerExample : MonoBehaviour
{
    // Initialize and start our sequencer
    private Sequencer _sequencer = Sequencer.Start();
    
    private void Start()
    {
        _sequencer.If(() => CONDITION).Do(() => DO_SOMETHING);
    }
    
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

### While
The While method is used with the Do method to do something while a condition is met, use it in Start like this:
```csharp=
public class SequencerExample : MonoBehaviour
{
    // Initialize and start our sequencer
    private Sequencer _sequencer = Sequencer.Start();
    
    private void Start()
    {
        _sequencer.While(() => CONDITION).Do(() => DO_SOMETHING);
    }
    
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

## Examples
### ThunderScript Example
```csharp
using System.Collections;
using ThunderRoad;
using UnityEngine;

namespace kSequencer.Examples;

public class SequencerThunderScript : ThunderScript
{
    // Initialize and start our sequencer
    private readonly Sequencer _sequencer = Sequencer.Start();

    // When our script is enabled in the game
    public override void ScriptEnable()
    {
        base.ScriptEnable();
        _sequencer.If(() => Player.currentCreature != null).Do(() => GameManager.local.StartCoroutine(SpawnItemPerSecond()));
    }

    // Spawns an item in the position of the players left hand magic position, per second the player is active
    private IEnumerator SpawnItemPerSecond()
    {
        while (Player.currentCreature != null)
        {
            // Spawn an item
            var itemData = Catalog.GetData<ItemData>("DaggerCommon");
            itemData?.SpawnAsync(null, Player.currentCreature.handLeft.caster.magicSource.position, Quaternion.identity);

            // Wait 1 second
            yield return new WaitForSeconds(1.0f);
        }
    }

    // Runs every frame, while our script is active
    public override void ScriptUpdate()
    {
        base.ScriptUpdate();
        // Update the sequencer
        _sequencer.Update();
    }
}
```

### Item Example
```csharp
using ThunderRoad;
using UnityEngine;

namespace kSequencer.Examples;

public class SequencerItemModule : ItemModule
{
    // When the item is loaded
    public override void OnItemLoaded(Item item)
    {
        base.OnItemLoaded(item);
        // Add our behaviour component
        item.gameObject.TryGetOrAddComponent(out MonoBehaviour behaviour);
    }
}

public class SequencerItemBehaviour : MonoBehaviour
{
    private Item _item;

    // Initialize and start our sequencer
    private readonly Sequencer _sequencer = Sequencer.Start();

    // When our item is spawned
    private void Start()
    {
        _item = GetComponent<Item>();

        if (_item != null && _item.mainHandler != null)
        {
            // Use the sequencer to check if we pressed the alternate use button while holding it, if so, despawn the item
            _sequencer?.If(() => _item.mainHandler.playerHand.controlHand.alternateUsePressed).Do(_item.Despawn);
        }
    }

    // Runs every frame of the game, while the item is spawned
    private void Update()
    {
        // Update the sequencer
        _sequencer.Update();
    }
}
```

### Spell Example
```csharp
using ThunderRoad;
using UnityEngine;

namespace kSequencer.Examples;

public class SequencerSpell : SpellCastCharge
{
    // Initialize and start our sequencer
    private Sequencer _sequencer = Sequencer.Start();
    
    public override void Load(SpellCaster spellCaster, Level level)
    {
        base.Load(spellCaster, level);
        // Uses the Sequencer to check if we pressed the grip while we are casting the spell, then spawn an item into the players hand
        _sequencer.If(() => spellCaster.ragdollHand.playerHand.controlHand.gripPressed).While(() => spellCaster.isFiring).Do(SpawnItemInHand);
    }

    // Spawns an item into the players hand
    private void SpawnItemInHand()
    {
        // Spawn an item
        var itemData = Catalog.GetData<ItemData>("DaggerCommon");
        itemData?.SpawnAsync(item =>
        {
            // Grab the item
            spellCaster.ragdollHand.Grab(item.GetMainHandle(spellCaster.ragdollHand.side));
        }, spellCaster.magicSource.position, Quaternion.identity);
        
        // End the spell's cast
        spellCaster.Fire(false);
    }

    // Runs every frame, while the spell is active (casting or not)
    public override void UpdateCaster()
    {
        base.UpdateCaster();
        // Update the sequencer
        _sequencer.Update();
    }
}
```