I started using Bolt (https://assetstore.unity.com/packages/tools/visual-scripting/bolt-87491), along with ORK. Mostly for building quest logic and triggers, for its live debug and modularity features.

The integration does require custom coding, but it has not proven difficult so far. I thought we could use this topic to share integration code bits if anyone else uses or wants to use Bolt along with ORK.

I'll start with simple setup of running Bolt Flow Event from ORK Event and waiting until it's finished.
The way it works we're gonna start a Custom Trigger on Bolt Event to run it, and then provide ORK event callback to tell ORK event has finished.

!!!Obviously first familiarize yourself with ORK and Bolt basics!!! This is not a basics tutorial

Everything I posted is tested on BOLT 1.x, I have not idea if it works on BOLT 2. Also everything provided as is, I can't guarantee it won't mess with your project. Especially be careful with custom bolt nodes. They can break your access to bolt macros. So test on new, blank Bolt macros first. And make backup if you update BOLT.

First you need this to create new C# file : RunBoltEventStep.cs
using UnityEngine;
using ORKFramework;
using ORKFramework.Menu;
using ORKFramework.Reflection;
using ORKFramework.Behaviours;
using System.Collections.Generic;
using Ludiq;
using Bolt;
namespace ORKFramework.Events.Steps
{

[ORKEditorHelp("Run Bolt Event", "", "")]
[ORKEventStep(typeof(BaseEvent))]
[ORKNodeInfo("Animmal/Event")]
public class RunBoltEventStep : BaseEventStep
{
// moving object
[ORKEditorInfo(labelText = "Bolt Event Object")]
public EventObjectSetting TimelineObject = new EventObjectSetting();
[ORKEditorHelp("Bolt Custom Event name", "Bolt Custom Event name.\n", "")]
[ORKEditorInfo(expandWidth = true, labelText = "Bolt Custom Event name")]
public EventString EventName = new EventString();
[ORKEditorInfo(labelText = "Wait until Bolt Event has finished")]
public bool WaitUntilFinished;

private List<GameObject> BoltObjects;

bool Finished;

public RunBoltEventStep()
{

}

public override void Execute(BaseEvent baseEvent)
{
this.BoltObjects = this.TimelineObject.GetObject(baseEvent);


if (this.BoltObjects.Count > 0)
{
CustomEvent.Trigger(BoltObjects[0], EventName.GetValue(baseEvent), this, WaitUntilFinished);
if (WaitUntilFinished)
{
this.Continue(baseEvent);
}
else
{
Clear(baseEvent);
}

}
else
{
Debug.LogError("Run Bolt Event: Can't find object");
Clear(baseEvent);
}
}

public override void Continue(BaseEvent baseEvent)
{
if (Finished)
{
Clear(baseEvent);
}
else
{
//this.Continue(baseEvent);
baseEvent.StartContinue(Time.deltaTime + Time.deltaTime, this);
}
}

public void Finish()
{
Finished = true;
}


void Clear(BaseEvent baseEvent)
{
this.BoltObjects = null;
Finished = false;
baseEvent.StepFinished(this.next);
}
/*
============================================================================
Node name functions
============================================================================
*/
public override string GetNodeDetails()
{
return "Run Bolt Event";
}
}
}


Now via Animmal/Event/RunBoltEvent you can create this node, and provide it event object with Bolt Flow Machine and Bolt Custom Event Name. In our case "ORKStart"
image

Now we need to add this to Bolt Unit Options. In unity bar at the top(File/Edit etc) go to Tools/Bolt/UnitOptionsWizard

In the first list add OrkFramework
image
In the second add RunBoltEventStep
image

Ok now going to Bolt. for simplicity create new bolt macro, Name it ORKStart and set it up like this:
image
Make sure to enable Coroutine toggle on Custom Event node.
image

Now Create a new Macro ORKEnd and set it up like this:
image

Now Start your ORK logic with ORKStart super unit, and end with ORKEnd super unit. For example:
image
Post edited by hellwalker on
  • BOLT basically can have access to any C# code without need for custom integration. We can use it to create a Static Class to run some functions on ORK.
    First create a new C# file BoltHelpers.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using ORKFramework;
    using ORKFramework.Behaviours;

    namespace Animmal.YezugaRPG
    {
    public static class BoltHelpers
    {
    #region ORK
    public static void BlockPlayerControl(bool _State)
    {
    ORK.Control.SetBlockPlayer((_State) ? 1 : -1, true);
    }

    public static void BlockCameraControl(bool _State)
    {
    ORK.Control.SetBlockCamera((_State) ? 1 : -1, true);
    }

    public static void ORKChangeFaction(List<GameObject> _Combatants, int _Faction)
    {
    List<Combatant> _CombatantsList = ComponentHelper.GetCombatants(_Combatants);
    for (int i = 0; i < _CombatantsList.Count; i++)
    {
    ORKChangeFaction(_CombatantsList[i], _Faction);
    }
    }

    public static void ORKChangeFaction(GameObject _Combatant, int _Faction)
    {
    ORKChangeFaction(ComponentHelper.GetCombatant(_Combatant), _Faction);
    }

    public static void ORKChangeFaction(Combatant _Combatant, int _Faction)
    {
    _Combatant.Group.FactionID = _Faction;
    }

    public static void SetCameraControlTarget(GameObject _Target)
    {
    ORK.Control.SetCameraControlTarget(_Target, null);
    }

    public static void ORKUseAttack(GameObject _User, GameObject _Target, int _AttackIndex)
    {
    Combatant _UserCombatant = ComponentHelper.GetCombatant(_User);
    AbilityShortcut _AbilityShortcut = _UserCombatant.Abilities.GetBaseAttack(_AttackIndex);
    if (_AbilityShortcut == null)
    {
    Debug.LogError("ORKUseAttack: Combatant" + _UserCombatant.GameObject.name + " doesn't have attack with index - " + _AttackIndex.ToString());
    return;
    }
    List<Combatant> _Targets = new List<Combatant>();
    _Targets.Add(ComponentHelper.GetCombatant(_Target));
    //_AbilityShortcut.GetActiveLevel().UseAccess(_AbilityShortcut, _UserCombatant, _Targets, false, true, false, false, 0, 0, null, null, null);
    _AbilityShortcut.Use(_UserCombatant, _Targets, true);
    }

    public static void ORKUseAbility(GameObject _User, GameObject _Target, int _Ability)
    {
    Combatant _UserCombatant = ComponentHelper.GetCombatant(_User);
    AbilityShortcut _AbilityShortcut = _UserCombatant.Abilities.Get(_Ability);
    if (_AbilityShortcut == null)
    {
    Debug.LogError("ORKUseAbility: Combatant" + _UserCombatant.GameObject.name + " doesn't have ability - " + _Ability.ToString());
    return;
    }
    List<Combatant> _Targets = new List<Combatant>();
    _Targets.Add(ComponentHelper.GetCombatant(_Target));
    _AbilityShortcut.Use(_UserCombatant, _Targets, false);
    }

    public static void BlockMoveAI(GameObject _Character, bool _State)
    {
    MoveAIComponent _MoveAI = _Character.GetComponent<MoveAIComponent>();
    if (_MoveAI == null)
    {
    Debug.LogError("BlockMoveAI: Combatant" + _Character.name + " has no move AI.");
    return;
    }
    _MoveAI.blocked = _State;
    }

    public static void BlockMoveAI(bool _State)
    {
    ORK.Control.SetBlockMoveAI(_State ? 1 : -1);
    }


    public static GameObject GetPlayer
    {
    get
    {
    return ORK.Game.ActiveGroup.Leader.GameObject;
    }
    }

    #region VARIABLES

    //Bool
    public static void ORKSetVariableGlobalBool(string _Key, bool _Value)
    {
    ORK.Game.Variables.Set(_Key, _Value);
    }

    public static void ORKSetVariableLocalBool(string _Key, bool _Value, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    _ObjectVariables.GetHandler().Set(_Key, _Value);
    }
    }

    public static bool ORKGetVariableGlobalBool(string _Key)
    {
    return ORK.Game.Variables.GetBool(_Key);
    }

    public static bool ORKGetVariableLocalBool(string _Key, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    return _ObjectVariables.GetHandler().GetBool(_Key);
    }

    return false;
    }

    //Float
    public static void ORKSetVariableGlobalFloat(string _Key, float _Value)
    {
    ORK.Game.Variables.Set(_Key, _Value);
    }

    public static void ORKSetVariableLocalFloat(string _Key, float _Value, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    _ObjectVariables.GetHandler().Set(_Key, _Value);
    }
    }

    public static float ORKGetVariableGlobalFloat(string _Key)
    {
    return ORK.Game.Variables.GetFloat(_Key);
    }

    public static float ORKGetVariableLocalFloat(string _Key, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    return _ObjectVariables.GetHandler().GetFloat(_Key);
    }

    return -1f;
    }

    //String
    public static void ORKSetVariableGlobalString(string _Key, string _Value)
    {
    ORK.Game.Variables.Set(_Key, _Value);
    }

    public static void ORKSetVariableLocalString(string _Key, string _Value, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    _ObjectVariables.GetHandler().Set(_Key, _Value);
    }
    }

    public static string ORKGetVariableGlobalString(string _Key)
    {
    return ORK.Game.Variables.GetString(_Key);
    }

    public static string ORKGetVariableLocalString(string _Key, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    return _ObjectVariables.GetHandler().GetString(_Key);
    }

    return string.Empty;
    }

    //Vector3
    public static void ORKSetVariableGlobalVector3(string _Key, Vector3 _Value)
    {
    ORK.Game.Variables.Set(_Key, _Value);
    }

    public static void ORKSetVariableLocalVector3(string _Key, Vector3 _Value, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    _ObjectVariables.GetHandler().Set(_Key, _Value);
    }
    }

    public static Vector3 ORKGetVariableGlobalVector3(string _Key)
    {
    return ORK.Game.Variables.GetVector3(_Key);
    }

    public static Vector3 ORKGetVariableLocalVector3(string _Key, GameObject _GameObject)
    {
    ORKFramework.Behaviours.ObjectVariablesComponent _ObjectVariables = _GameObject.GetComponent<ORKFramework.Behaviours.ObjectVariablesComponent>();
    if (_ObjectVariables != null)
    {
    return _ObjectVariables.GetHandler().GetVector3(_Key);
    }

    return Vector3.zero;
    }
    #endregion

    #endregion
    }
    }

    Now we need to add this to Bolt Unit Options. In unity bar at the top(File/Edit etc) go to Tools/Bolt/UnitOptionsWizard
    image

    Now if you search BoltHelpers class in Bolt you'll have bunch of new options to change ork variables, block camera etc.

    You can add your own functions to this list. And then click Tools/Bolt/BuildUnitOptions and it will update with your custom functions.
  • edited April 4
    Here is custom node for Bolt that starts and waits for ORK battle.
    image
    BUT!!!!
    You need to replace line 37 and 52 with your own Way of listening to ORK battle End.
    The way I do it is that I need to consider battle finished sometime in the middle of ORK's Battle End event, so in battle end event I send message to my UI manager and tell it battle ended, and this is delegate I'm listeting to in this event. You need to provide custom solution of this, for this node to work.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Bolt;
    using System;

    [UnitCategory("Animmal")]
    public class StartBattle : Unit
    {
    [Ludiq.DoNotSerialize]
    public ControlInput start;

    [Ludiq.DoNotSerialize]
    public ControlOutput exit;

    [Ludiq.DoNotSerialize]
    public ControlOutput battleFinished;

    [Ludiq.DoNotSerialize]
    public ValueInput BattleObject;

    [Ludiq.DoNotSerialize]
    public ValueInput Combatants;

    protected override void Definition()
    {
    start = ControlInputCoroutine("start", WaitForBattleEnd);
    BattleObject = ValueInput<ORKFramework.Behaviours.BattleComponent>("BattleObject");
    Combatants = ValueInput<List<GameObject>>("Combatants");
    exit = ControlOutput("exit");
    battleFinished = ControlOutput("battleFinished");

    }
    bool BattleFinished = false;
    private void BattleEnded(bool arg0)
    {
    Animmal.YezugaRPG.ORK_UIManager.instance.BattleEndSetupFinishedNotification.RemoveListener(BattleEnded);
    BattleFinished = true;
    }

    private IEnumerator WaitForBattleEnd(Flow flow)
    {
    List<GameObject> _Combatants = flow.GetValue<List<GameObject>>(Combatants);
    ORKFramework.Behaviours.BattleComponent _Battle = flow.GetValue<ORKFramework.Behaviours.BattleComponent>(BattleObject);
    for (int i = 0; i < _Combatants.Count; i++)
    {
    _Battle.JoinOnStart(ORKFramework.ComponentHelper.GetCombatant(_Combatants[i]));
    }
    _Battle.StartEvent(_Battle);
    yield return exit;
    BattleFinished = false;
    Animmal.YezugaRPG.ORK_UIManager.instance.BattleEndSetupFinishedNotification.AddListener(BattleEnded);
    while (BattleFinished == false)
    {
    yield return null;
    }
    yield return battleFinished;
    }
    }
    Post edited by hellwalker on
  • Ok this one will call on ORK's own Fade function:
    image

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Bolt;
    using ORKFramework;

    [UnitCategory("Animmal")]
    public class FadeScreen : Unit
    {
    [Ludiq.DoNotSerialize]
    public ControlInput start;

    [Ludiq.DoNotSerialize]
    public ControlOutput exit;


    [Ludiq.DoNotSerialize]
    public ControlOutput WaitFinished;

    [Ludiq.DoNotSerialize]
    public ValueInput time;

    [Ludiq.DoNotSerialize]
    public ValueInput interpolation;

    [Ludiq.DoNotSerialize]
    public ValueInput alpha;

    [Ludiq.DoNotSerialize]
    public ValueInput red;

    [Ludiq.DoNotSerialize]
    public ValueInput green;

    [Ludiq.DoNotSerialize]
    public ValueInput blue;

    [Ludiq.DoNotSerialize]
    public ValueInput fromCurrent;

    [Ludiq.DoNotSerialize]
    public ValueInput startColor;

    [Ludiq.DoNotSerialize]
    public ValueInput endColor;

    float Timer = 0;

    protected override void Definition()
    {
    start = ControlInputCoroutine("start", Fade);
    time = ValueInput("time", 0.25f);
    interpolation = ValueInput("interpolation", EaseType.Linear);
    alpha = ValueInput("alpha", true);
    red = ValueInput("red", false);
    green = ValueInput("green", false);
    blue = ValueInput("blue", false);
    fromCurrent = ValueInput("fromCurrent", false);
    startColor = ValueInput("startColor", new Color(0, 0, 0, 0));
    endColor = ValueInput("endColor", new Color(0, 0, 0, 1));
    exit = ControlOutput("exit");
    WaitFinished = ControlOutput("WaitFinished");
    }

    private IEnumerator Fade(Flow flow)
    {
    FadeColorSettings _FadeColor = new FadeColorSettings();
    _FadeColor.time = flow.GetValue<float>(time);
    _FadeColor.interpolation = flow.GetValue<EaseType>(interpolation);
    _FadeColor.alpha = flow.GetValue<bool>(alpha);
    _FadeColor.red = flow.GetValue<bool>(red);
    _FadeColor.green = flow.GetValue<bool>(green);
    _FadeColor.blue = flow.GetValue<bool>(blue);
    _FadeColor.fromCurrent = flow.GetValue<bool>(fromCurrent);
    _FadeColor.startColor = flow.GetValue<Color>(startColor);
    _FadeColor.endColor = flow.GetValue<Color>(endColor);
    ORK.GUI.ScreenFader.FadeScreen(_FadeColor);

    yield return exit;
    Timer = _FadeColor.time;
    //while (Timer > 0)
    //{
    // Timer -= Time.deltaTime;
    // yield return wait;
    //}
    yield return new WaitForSeconds(_FadeColor.time);
    yield return WaitFinished;
    }
    }
Sign In or Register to comment.