--- 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(); } } ```