Well, it all highly depends on how your system is actually used at runtime. Pure dialog-trees are completely static data that is simply used at runtime. However you want now an information flow in the opposite direction. So your static dialog data should reference runtime state. This is in general a bit tricky.
The easiest way would probably be introducing “variables” / parameteres just like the Mecanim system does. It uses [this class][1] to represent a parameter which is created inside the mecanim system.
The more variable types you want to support the more complicated / complex things might get. In theory a float would be enough to represent fractional number, whole numbers and booleans.
The link between your dialog nodes and the variables should be made by a string. Indices are dangerous as when you remove an element from the beginning the indices after would be wrong. You also need a name for each variable to actually “set” the value from scripting.
For example something like that:
[System.Serializable]
public class DynVariable
{
public string name;
public float initialValue;
private float currentValue;
public float Value
{
get { return currentValue; }
set { currentValue = value; }
}
}
public class YourDialogMasterScript : ScriptableObject
{
public List<DynVariable> variables;
private Dictionary<string, DynVariable> varLookup = null;
public void SetVariable(string aName, float aValue)
{
if (varLookup == null)
InitVariables();
DynVariable tmp;
if (varLookup.TryGetValue(aName, out tmp))
{
tmp.Value = aValue;
return;
}
Debug.LogWarning("SetVariable: variable with name '" + aName + "' doesn't exist");
}
public float GetVariable(string aName)
{
if (varLookup == null)
InitVariables();
DynVariable tmp;
if (varLookup.TryGetValue(aName, out tmp))
{
return tmp.Value;
}
Debug.LogWarning("GetVariable: variable with name '"+aName+"' doesn't exist");
return 0f;
}
void InitVariables()
{
varLookup = new Dictionary<string, DynVariable>();
for (int i = 0; i < variables.Count; i++)
{
varLookup.Add(variables_.name, variables*);*_
variables_.Value = variables*.initialValue;
}*_
}
void OnEnable()
{
if (varLookup == null)
InitVariables();
}
}
public enum EComparison
{
Equal,
NotEqual,
Greater,
GreaterOrEqual,
Lower,
LowerOrEqual,
}
[System.Serializable]
public class DynVarCondition
{
public string variableName;
public EComparison comparison;
public float refValue;
public bool roundToInt = false;
public bool ConditionMet(YourDialogMasterScript aMaster)
{
float v = aMaster.GetVariable(variableName);
if (roundToInt)
v = Mathf.RoundToInt(v);
switch(comparison)
{
case EComparison.NotEqual: return v != refValue;
case EComparison.Greater: return v > refValue;
case EComparison.GreaterOrEqual: return v >= refValue;
case EComparison.Lower: return v < refValue;
case EComparison.LowerOrEqual: return v <= refValue;
case EComparison.Equal:
default: return v == refValue;
}
}
}
public class YourDialogNodeTransition
{
public List conditions;
public bool ConditionsMet(YourDialogMasterScript aMaster)
{
for (int i = 0; i < conditions.Count; i++)
if (!conditions*.ConditionMet(aMaster))*
return false;
return true;
}
}
DynVariable represents an actual “variable”. They are defined in your dialog master script or any other global script. From scripting you can use the GetVariable and SetVariable methods to read and write the variable at runtime.
Inside your dialog node transitions or other place where you need an external condition you simply add a list of “DynVarConditions”. There the user can specify a variable name, a reference value and how they should be compared. At runtime when you would use the “ConditionsMet” method to evaluate if the conditions are currently met or not.
Note that all conditions need to be met. So it’s an implicit “and” connection between them. If you want an optional “or” it gets way more complicated as you would need a true evaluation tree. The [WarCraft3 map editor][2] uses such a node based evaluation tree, but that’s far more than a dialog editor but a whole visual scripting solution. You have to decide how much you want to solve visually and hom much you want to solve via scripting. Some things are way easier to solve with a simple C# script.
As for the usability you could create some custom inspectors / editorwindows for editing those variables / conditions so the user can’t create duplicates (with the same name) and can only select existing variables from a list instead of typing in the variable name. But that’s not necessary.
How you actually implement that in your current system is up to you ^^.
*[1]: https://docs.unity3d.com/ScriptReference/AnimatorControllerParameter.html*_
*[2]: Theef's Warcraft 3 World Editor Tutorial #14 - Waves (and Timers) - YouTube