// This code is part of the Fungus library (https://github.com/snozbot/fungus) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) using UnityEngine; namespace Fungus { /// /// Standard comparison operators. /// public enum CompareOperator { /// == mathematical operator. Equals, /// != mathematical operator. NotEquals, /// < mathematical operator. LessThan, /// > mathematical operator. GreaterThan, /// <= mathematical operator. LessThanOrEquals, /// >= mathematical operator. GreaterThanOrEquals } /// /// Mathematical operations that can be performed on variables. /// public enum SetOperator { /// = operator. Assign, /// =! operator. Negate, /// += operator. Add, /// -= operator. Subtract, /// *= operator. Multiply, /// /= operator. Divide } /// /// Scope types for Variables. /// public enum VariableScope { /// Can only be accessed by commands in the same Flowchart. Private, /// Can be accessed from any command in any Flowchart. Public, /// Creates and/or references a global variable of that name, all variables of this name and scope share the same underlying fungus variable and exist for the duration of the instance of Unity. Global, } /// /// Attribute class for variables. /// public sealed class VariableInfoAttribute : System.Attribute { //Note do not use "isPreviewedOnly:true", it causes the script to fail to load without errors shown public VariableInfoAttribute(string category, string variableType, int order = 0, bool isPreviewedOnly = false) { this.Category = category; this.VariableType = variableType; this.Order = order; this.IsPreviewedOnly = isPreviewedOnly; } public string Category { get; set; } public string VariableType { get; set; } public int Order { get; set; } public bool IsPreviewedOnly { get; set; } } /// /// Attribute class for variable properties. /// public sealed class VariablePropertyAttribute : PropertyAttribute { public VariablePropertyAttribute (params System.Type[] variableTypes) { this.VariableTypes = variableTypes; } public VariablePropertyAttribute(AllVariableTypes.VariableAny any) { VariableTypes = AllVariableTypes.AllFungusVarTypes; } public VariablePropertyAttribute (string defaultText, params System.Type[] variableTypes) { this.defaultText = defaultText; this.VariableTypes = variableTypes; } public string defaultText = ""; public string compatibleVariableName = string.Empty; public System.Type[] VariableTypes { get; set; } } /// /// Abstract base class for variables. /// [RequireComponent(typeof(Flowchart))] [System.Serializable] public abstract class Variable : MonoBehaviour { [SerializeField] protected VariableScope scope; [SerializeField] protected string key = ""; #region Public members /// /// Visibility scope for the variable. /// public virtual VariableScope Scope { get { return scope; } set { scope = value; } } /// /// String identifier for the variable. /// public virtual string Key { get { return key; } set { key = value; } } /// /// Callback to reset the variable if the Flowchart is reset. /// public abstract void OnReset(); /// /// Used by SetVariable, child classes required to declare and implement operators. /// /// /// public abstract void Apply(SetOperator setOperator, object value); /// /// Used by Ifs, While, and the like. Child classes required to declare and implement comparisons. /// /// /// /// public abstract bool Evaluate(CompareOperator compareOperator, object value); /// /// Does the underlying type provide support for +-*/ /// public virtual bool IsArithmeticSupported(SetOperator setOperator) { return false; } /// /// Does the underlying type provide support for < <= > >= /// public virtual bool IsComparisonSupported() { return false; } /// /// Boxed or referenced value of type defined within inherited types. /// Not recommended for direct use, primarily intended for use in editor code. /// public abstract object GetValue(); //we are required to be on a flowchart so we provide this as a helper public virtual Flowchart GetFlowchart() { return GetComponent(); } #endregion } /// /// Generic concrete base class for variables. /// public abstract class VariableBase : Variable { //caching mechanism for global static variables private VariableBase _globalStaicRef; private VariableBase globalStaicRef { get { if (_globalStaicRef != null) { return _globalStaicRef; } else if(Application.isPlaying) { return _globalStaicRef = FungusManager.Instance.GlobalVariables.GetOrAddVariable(Key, value, this.GetType()); } else { return null; } } } [SerializeField] protected T value; public virtual T Value { get { if (scope != VariableScope.Global || !Application.isPlaying) { return this.value; } else { return globalStaicRef.value; } } set { if (scope != VariableScope.Global || !Application.isPlaying) { this.value = value; } else { globalStaicRef.Value = value; } } } public override object GetValue() { return value; } protected T startValue; public override void OnReset() { Value = startValue; } public override string ToString() { if (Value != null) return Value.ToString(); else return "Null"; } protected virtual void Start() { // Remember the initial value so we can reset later on startValue = Value; } //Apply to get from base system.object to T public override void Apply(SetOperator op, object value) { if(value is T || value == null) { Apply(op, (T)value); } else if(value is VariableBase) { var vbg = value as VariableBase; Apply(op, vbg.Value); } else { Debug.LogError("Cannot do Apply on variable, as object type: " + value.GetType().Name + " is incompatible with " + typeof(T).Name); } } public virtual void Apply(SetOperator setOperator, T value) { switch (setOperator) { case SetOperator.Assign: Value = value; break; default: Debug.LogError("The " + setOperator.ToString() + " set operator is not valid."); break; } } //Apply to get from base system.object to T public override bool Evaluate(CompareOperator op, object value) { if (value is T || value == null) { return Evaluate(op, (T)value); } else if (value is VariableBase) { var vbg = value as VariableBase; return Evaluate(op, vbg.Value); } else { Debug.LogError("Cannot do Evaluate on variable, as object type: " + value.GetType().Name + " is incompatible with " + typeof(T).Name); } return false; } public virtual bool Evaluate(CompareOperator compareOperator, T value) { bool condition = false; switch (compareOperator) { case CompareOperator.Equals: condition = Equals(Value, value);// Value.Equals(value); break; case CompareOperator.NotEquals: condition = !Equals(Value, value); break; default: Debug.LogError("The " + compareOperator.ToString() + " comparison operator is not valid."); break; } return condition; } public override bool IsArithmeticSupported(SetOperator setOperator) { return setOperator == SetOperator.Assign || base.IsArithmeticSupported(setOperator); } } }