void AddButtonOnClick()
    {
        if (derivedStats == null)
        {
            derivedStats = ScriptableObject.CreateInstance <DerivedStatList>();
        }
        List <DerivedStat> newDerivedStats;

        newDerivedStats = new List <DerivedStat>(derivedStats.stats);
        newDerivedStats.Add(new DerivedStat());

        derivedStats.stats = newDerivedStats.ToArray();
        this.Repaint();
    }
    public bool TryEvaluate(Actor actor, DerivedStatList derivedStats, out int outcome)
    {
        Dictionary <string, int> statSubs = new Dictionary <string, int>();

        statSubs.Add("MAXHP", actor.maxHitPoints);
        statSubs.Add("HP", actor.hitPoints);
        statSubs.Add("DAMAGE", actor.damage);

        int numTargets = 1;

        if (actor.actionTarget.ToString().StartsWith("All"))
        {
            numTargets = actor.GetAvailableTargets().Count;
        }
        statSubs.Add("NUMTARGETS", numTargets);

        string workbench = expression.ToUpper();

        foreach (string k in statSubs.Keys)
        {
            workbench = workbench.Replace(k, statSubs[k].ToString());
        }

        // TODO: Watch out for circular definitions
        if (derivedStats != null)
        {
            for (int i = 0; i < derivedStats.Length; i++)
            {
                if (derivedStats.list[i].statName != statName)
                {
                    int derivedValue;
                    if (derivedStats.list[i].TryEvaluate(actor, null, out derivedValue))
                    {
                        workbench = workbench.Replace(derivedStats.list[i].statName.ToUpper(), derivedValue.ToString());
                    }
                }
            }
        }

        if (!UnityEditor.ExpressionEvaluator.Evaluate <int>(workbench, out outcome))
        {
            UnityEngine.MonoBehaviour.print(workbench);
            return(false);
        }
        else
        {
            return(true);
        }
    }
Example #3
0
    public bool TryEvaluate(string propertyName, DerivedStatList derivedStats, out int result)
    {
        string propertyNameUpper = propertyName.Trim().ToUpper();

        switch (propertyNameUpper)
        {
        case "MAXHP":
            result = maxHitPoints;
            return(true);

        case "HP":
            result = hitPoints;
            return(true);

        case "INITIATIVE":
            result = initiative;
            return(true);

        case "DAMAGE":
            result = damage;
            return(true);

        case "SOURCE":
            result = (int)actionEffectSource;
            return(true);
        }

        if (propertyName.StartsWith("IMMUNITIES[") && propertyName.EndsWith("]"))
        {
            result = 0;
            int targetImmunity = int.Parse(propertyName.Replace("IMMUNITIES[", "").Replace("]", ""));
            if (immunities == null)
            {
                return(true);
            }
            for (int i = 0; i < immunities.Length; i++)
            {
                if ((int)immunities[i] == targetImmunity)
                {
                    result = 1;
                }
            }
            return(true);
        }

        result = 0;
        return(false);
    }
    public bool HasCircularReference(DerivedStatList derivedStats)
    {
        // Assumption: All stats have different names. (Enforceable?)
        // (Append (1) (2) etc.? )

        // TODO: Recursion
        // Find derivedStat references within this expression
        // For each, drill down into their derived stats; if we ever find
        // the statName of this item, return true up the recursion.
        //
        // Is it necessary to check for infinite recursion, since
        // by definition, if there is no circular reference,
        // eventually we'll hit the bottom of the tree on all branches?


        throw new System.NotImplementedException();
    }
    public override void OnInspectorGUI()
    {
        #region Actor Stats
        Actor myActor = target as Actor;

        #region Actor Name
        myActor.actorName = EditorGUILayout.TextField("Actor Name: ", myActor.actorName);
        #endregion

        #region Action Target
        myActor.actionTarget = (Actor.ActionTarget)EditorGUILayout.EnumPopup("Action Target: ", myActor.actionTarget);

        #endregion

        #region Action Effect
        myActor.actionEffect = (Actor.ActionEffect)EditorGUILayout.EnumPopup("Action Effect: ", myActor.actionEffect);
        #endregion

        #region AES & Immunities
        Actor.ActionSource[] sourceValues = Enum.GetValues(typeof(Actor.ActionSource)) as Actor.ActionSource[];
        string[]             sourceNames  = Enum.GetNames(typeof(Actor.ActionSource));

        SelectionList <Actor.ActionSource> sources = new SelectionList <Actor.ActionSource>(sourceValues, sourceNames);
        myActor.actionEffectSource = sources.RadioList("Action Source: ", myActor.actionEffectSource, 3);
        myActor.immunities         = sources.CheckboxList("Immunities: ", myActor.immunities, 3);
        #endregion

        #region MaxHit Points
        string mhpLabel        = "Max Hit Points: ";
        int    newMaxHitPoints = myActor.GetComponent <Actor>().maxHitPoints;
        newMaxHitPoints = EditorGUILayout.IntSlider(mhpLabel, newMaxHitPoints, 0, 1500);
        myActor.GetComponent <Actor>().maxHitPoints = newMaxHitPoints;
        #endregion

        #region Hit Points
        string hpLabel      = "Hit Points: ";
        int    newHitPoints = myActor.GetComponent <Actor>().hitPoints;
        newHitPoints = EditorGUILayout.IntSlider(hpLabel, newHitPoints, 1, 100);
        myActor.GetComponent <Actor>().hitPoints = newHitPoints;
        #endregion

        #region Initiative
        string iLabel        = "Initiative: ";
        int    newInitiative = myActor.GetComponent <Actor>().initiative;
        newInitiative = EditorGUILayout.IntSlider(iLabel, newInitiative, 10, 100);
        myActor.GetComponent <Actor>().initiative = newInitiative;

        #endregion

        #region Damage
        string dLabel    = "Damage: ";
        int    newDamage = myActor.GetComponent <Actor>().damage;
        newDamage = EditorGUILayout.IntSlider(dLabel, newDamage, 0, 180);
        myActor.GetComponent <Actor>().damage = newDamage;
        #endregion

        #region Percent Chance to Hit
        string pchLabel = "Percent Chance To Hit:  ";
        int    newPcth  = myActor.GetComponent <Actor>().percentChanceToHit;
        newPcth = EditorGUILayout.IntSlider(pchLabel, newPcth, 0, 100);
        myActor.GetComponent <Actor>().percentChanceToHit = newPcth;
        #endregion

        #region Board Position
        Actor.Position[] positionValues          = Enum.GetValues(typeof(Actor.Position)) as Actor.Position[];
        string[]         positionNames           = Enum.GetNames(typeof(Actor.Position));
        SelectionList <Actor.Position> positions = new SelectionList <Actor.Position>(positionValues, positionNames);
        myActor.boardPosition = positions.PositionGrid("Board Position: ", myActor.boardPosition, 3);
        #endregion
        #endregion

        #region AI Authoring
        if (errorBoxStyle == null)
        {
            InitializeStyles();
        }

        showDerivedProperties = EditorGUILayout.Foldout(showDerivedProperties, new GUIContent("Derived Properties", "Properties based on static unit stats."));
        if (showDerivedProperties)
        {
            derivedStats = AssetDatabase.LoadAssetAtPath("Assets/DerivedProperties.asset", typeof(DerivedStatList)) as DerivedStatList;
            if (derivedStats == null)
            {
                UnityEngine.MonoBehaviour.print("Nope, not there");
                derivedStats = ScriptableObject.CreateInstance <DerivedStatList>();
                AssetDatabase.CreateAsset(derivedStats, "Assets/DerivedProperties.asset");
                AssetDatabase.SaveAssets();
            }

            int nameFieldWidth = 80;
            for (int i = 0; i < derivedStats.Length; i++)
            {
                int statNameWidth = (int)EditorStyles.textField.CalcSize(new GUIContent(derivedStats.list[i].statName + " ")).x;
                if (statNameWidth > nameFieldWidth)
                {
                    nameFieldWidth = statNameWidth;
                }
            }

            bool derivedPropEquationChanged = false;

            EditorGUILayout.BeginVertical();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Name", GUILayout.Width(nameFieldWidth));
            EditorGUILayout.LabelField("Expression");
            EditorGUILayout.LabelField("Current Value", GUILayout.MaxWidth(90));
            EditorGUILayout.EndHorizontal();

            for (int i = 0; i < (derivedStats != null ? derivedStats.Length : 0); i++)
            {
                EditorGUILayout.BeginHorizontal();


                derivedStats.list[i].statName = EditorGUILayout.TextField(derivedStats.list[i].statName, GUILayout.Width(nameFieldWidth));

                int    derivedValue = 0;
                string derivedEquationErrorMessage = string.Empty;


                if (!derivedStats.list[i].TryEvaluate((target as Actor), derivedStats, out derivedValue))
                {
                    derivedEquationErrorMessage = "Invalid expression.";
                }

                string newDerivedPropEquation = EditorGUILayout.TextField(derivedStats.list[i].expression, derivedEquationErrorMessage.Length == 0 ? EditorStyles.textField : errorBoxStyle);
                if (derivedEquationErrorMessage.Length > 0)
                {
                    GUI.Label(GUILayoutUtility.GetLastRect(), new GUIContent(string.Empty, derivedEquationErrorMessage));
                }
                else
                {
                    EditorGUILayout.LabelField(derivedValue.ToString(), GUILayout.MaxWidth(90));
                }

                if (newDerivedPropEquation != derivedStats.list[i].expression)
                {
                    derivedPropEquationChanged = true;
                }

                derivedStats.list[i].expression = newDerivedPropEquation;

                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.EndVertical();

            bool added = false;
            if (GUILayout.Button("Add"))
            {
                added = true;
                if (derivedStats == null)
                {
                    derivedStats = new DerivedStatList();
                }

                List <DerivedStat> newDerivedStats;
                if (derivedStats.list != null)
                {
                    newDerivedStats = new List <DerivedStat>(derivedStats.list);
                }
                else
                {
                    newDerivedStats = new List <DerivedStat>();
                }
                newDerivedStats.Add(new DerivedStat());

                derivedStats.list = newDerivedStats.ToArray();
                this.Repaint();
            }

            if (GUI.changed || added)
            {
                EditorUtility.SetDirty(derivedStats);
                serializedObject.ApplyModifiedProperties();
                AssetDatabase.SaveAssets();
            }

            if (derivedPropEquationChanged)
            {
                this.Repaint();
            }
            DrawDefaultInspector();
        }
        #endregion
    }
        public List <Actor> Apply(Actor initiator, List <Actor> availableTargets, DerivedStatList derivedStats)
        {
            string operation = null;

            if (expression.Contains(">="))
            {
                operation = ">=";
            }
            else if (expression.Contains("<="))
            {
                operation = "<=";
            }
            else if (expression.Contains("!="))
            {
                operation = "!=";
            }
            else if (expression.Contains(">"))
            {
                operation = ">";
            }
            else if (expression.Contains("<"))
            {
                operation = "<";
            }
            else if (expression.Contains("="))
            {
                operation = "=";
            }

            if (operation == null)
            {
                throw new System.Exception("Invalid operator in SelectionRule expression [" + expression + "]. Only <, >, <=, >=, =, != are allowed.");
            }

            string[]     components          = expression.Split(new string[] { operation }, System.StringSplitOptions.RemoveEmptyEntries);
            List <Actor> newAvailableTargets = new List <Actor>();

            for (int i = 0; i < availableTargets.Count; i++)
            {
                Actor    candidateTarget = availableTargets[i];
                string[] left            = components[0].ToLower().Split('.');
                string[] right           = components[1].ToLower().Split('.');

                int leftValue, rightValue;
                if (left[0] == "my")
                {
                    initiator.TryEvaluate(left[1], derivedStats, out leftValue);
                }
                if (left[0] == "target")
                {
                    candidateTarget.TryEvaluate(left[1], derivedStats, out leftValue);
                }
                if (left[0] == "targets")
                {
                    int[] allValues = new int[availableTargets.Count];
                    for (int j = 0; j < allValues.Length; j++)
                    {
                        availableTargets[j].TryEvaluate(left[2], derivedStats, out allValues[j]);
                    }
                    int outcome = allValues[0];
                    for (int j = 1; j < allValues.Length; j++)
                    {
                        if (left[1] == "max" && allValues[j] > outcome)
                        {
                            outcome = allValues[j];
                        }
                        if (left[1] == "min" && allValues[i] < outcome)
                        {
                            outcome = allValues[j];
                        }
                    }
                    leftValue = outcome;
                }

                if (right[0] == "my")
                {
                    initiator.TryEvaluate(right[1], derivedStats, out rightValue);
                }
                if (right[0] == "target")
                {
                    candidateTarget.TryEvaluate(right[1], derivedStats, out rightValue);
                }
                if (right[0] == "targets")
                {
                    int[] allValues = new int[availableTargets.Count];
                    for (int j = 0; j < allValues.Length; j++)
                    {
                        availableTargets[j].TryEvaluate(right[2], derivedStats, out allValues[j]);
                    }
                    int outcome = allValues[0];
                    for (int j = 1; j < allValues.Length; j++)
                    {
                        if (right[1] == "max" && allValues[j] > outcome)
                        {
                            outcome = allValues[j];
                        }
                        if (right[1] == "min" && allValues[i] < outcome)
                        {
                            outcome = allValues[j];
                        }
                    }
                    rightValue = outcome;
                }
            }
        }
Example #7
0
    public List <Actor> Apply(Actor initiator, List <Actor> availableTargets, DerivedStatList derivedStats)
    {
        // Parse the expression.
        string operation = null;

        if (expression.Contains(">="))
        {
            operation = ">=";
        }
        else if (expression.Contains("<="))
        {
            operation = "<=";
        }
        else if (expression.Contains("!="))
        {
            operation = "!=";
        }
        else if (expression.Contains(">"))
        {
            operation = ">";
        }
        else if (expression.Contains("<"))
        {
            operation = "<";
        }
        else if (expression.Contains("="))
        {
            operation = "=";
        }

        if (operation == null)
        {
            throw new System.Exception("Invalid operator in SelectionRule expression [" + expression + "]. Only <, >, <=, >=, =, != are allowed.");
        }

        string[] components = expression.Split(new string[] { operation }, System.StringSplitOptions.RemoveEmptyEntries);

        // Require a simple expression; each side is a property of either the initiator or a target..? What about things like targets.max?

        // Maybe start with the left side? Oh, or, evaluate for each either way. Derp.
        List <Actor> newAvailableTargets = new List <Actor>();

        for (int i = 0; i < availableTargets.Count; i++)
        {
            Actor    candidateTarget = availableTargets[i];
            string[] left            = components[0].ToLower().Split('.');
            string[] right           = components[1].ToLower().Split('.');

            int leftValue, rightValue;
            // Evaluate left
            if (left[0] == "my")
            {
                // Evaluate on initiator
                initiator.TryEvaluate(left[1], derivedStats, out leftValue);
            }
            if (left[0] == "target")
            {
                // Evaluate on candidateTarget
                candidateTarget.TryEvaluate(left[1], derivedStats, out leftValue);
            }
            if (left[0] == "targets")
            {
                // max or min here
                int[] allValues = new int[availableTargets.Count];
                for (int j = 0; j < allValues.Length; j++)
                {
                    availableTargets[j].TryEvaluate(left[2], derivedStats, out allValues[j]);
                }
                int outcome = allValues[0];
                for (int j = 1; j < allValues.Length; j++)
                {
                    if (left[1] == "max" && allValues[j] > outcome)
                    {
                        outcome = allValues[j];
                    }
                    if (left[1] == "min" && allValues[i] < outcome)
                    {
                        outcome = allValues[j];
                    }
                }
                leftValue = outcome;
            }

            // Evaluate right
            if (right[0] == "my")
            {
                // Evaluate on initiator
                initiator.TryEvaluate(right[1], derivedStats, out rightValue);
            }
            if (right[0] == "target")
            {
                // Evaluate on candidateTarget
                candidateTarget.TryEvaluate(right[1], derivedStats, out rightValue);
            }
            if (right[0] == "targets")
            {
                // max or min here
                int[] allValues = new int[availableTargets.Count];
                for (int j = 0; j < allValues.Length; j++)
                {
                    availableTargets[j].TryEvaluate(right[2], derivedStats, out allValues[j]);
                }
                int outcome = allValues[0];
                for (int j = 1; j < allValues.Length; j++)
                {
                    if (right[1] == "max" && allValues[j] > outcome)
                    {
                        outcome = allValues[j];
                    }
                    if (right[1] == "min" && allValues[i] < outcome)
                    {
                        outcome = allValues[j];
                    }
                }
                rightValue = outcome;
            }
        }
    }
    public override void OnInspectorGUI()
    {
        Actor editActor = target as Actor;

        Actor.ActionSource[] immTypeVal  = Enum.GetValues(typeof(Actor.ActionSource)) as Actor.ActionSource[];
        string[]             immTypeName = Enum.GetNames(typeof(Actor.ActionSource));
        for (int i = 0; i < immTypeName.Length; i++)
        {
            immTypeName[i] += '\t';
        }

        Actor.Position[] posVal  = Enum.GetValues(typeof(Actor.Position)) as Actor.Position[];
        string[]         posName = Enum.GetNames(typeof(Actor.Position));
        for (int i = 0; i < posName.Length; i++)
        {
            posName[i] += '\t';
        }

        immunityList = new SelectionList <Actor.ActionSource>(immTypeVal, immTypeName);
        positionList = new SelectionList <Actor.Position>(posVal, posName);

        #region Name, and HP
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Name");
        actName = GUILayout.TextField(editActor.actorName);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Max Hit Points");
        maxHP = EditorGUILayout.IntSlider(maxHP, 1, 10000);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Current Hit Points");
        currentHP = EditorGUILayout.IntSlider(currentHP, 0, maxHP);
        EditorGUILayout.EndHorizontal();
        #endregion

        #region Position
        editPosition = EditorGUILayout.Foldout(editPosition, "Position");
        if (editPosition)
        {
            boardPos = positionList.RadioList("", boardPos, 2);
        }
        #endregion

        #region Damage
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Damage");
        dmg = EditorGUILayout.IntSlider(dmg, 0, 180);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Effect");
        EditorGUILayout.EnumFlagsField(effect);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Damage Type");
        EditorGUILayout.EnumFlagsField(dmgType);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Attack type");
        EditorGUILayout.EnumFlagsField(targetType);
        EditorGUILayout.EndHorizontal();
        #endregion

        #region Immunities
        editImmunity = EditorGUILayout.Foldout(editImmunity, "Immunities");
        if (editImmunity)
        {
            immunities = immunityList.CheckboxList("Immunities", immunities, 2);
        }
        #endregion

        #region AI
        editAI = EditorGUILayout.Foldout(editAI, "AI Options");
        if (editAI)
        {
            derivedStats = AssetDatabase.LoadAssetAtPath("Assets/DerivedProperties.asset", typeof(DerivedStatList)) as DerivedStatList;
            if (derivedStats == null)
            {
                derivedStats = ScriptableObject.CreateInstance <DerivedStatList>();
                AssetDatabase.CreateAsset(derivedStats, "Assets/DerivedProperties.asset");
                AssetDatabase.SaveAssets();
            }

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Chance to Hit");
            chanceToHit = EditorGUILayout.IntSlider(chanceToHit, 0, 100);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Inititive");
            init  = EditorGUILayout.IntSlider(init, 5, 100);
            init  = init / 5;
            init *= 5;
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Separator();
            EditorGUILayout.LabelField("AI Targeting Filters");
            EditorGUILayout.LabelField("Filter order does matter (Ordered top to bottom)");
            EditorGUILayout.Separator();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Name", GUILayout.MaxWidth(80));
            EditorGUILayout.LabelField("Expression");
            EditorGUILayout.EndHorizontal();

            FilterLayout();

            EditorGUILayout.Separator();
            bool added = false;
            if (GUILayout.Button("Add Filter"))
            {
                added = true;
                AddButtonOnClick();
            }

            if (GUI.changed || added)
            {
                EditorUtility.SetDirty(derivedStats);
                serializedObject.ApplyModifiedProperties();
                AssetDatabase.SaveAssets();
            }
        }
        #endregion

        #region Assignment
        editActor.actorName          = actName;
        editActor.boardPosition      = boardPos;
        editActor.maxHitPoints       = maxHP;
        editActor.damage             = dmg;
        editActor.actionEffect       = effect;
        editActor.actionEffectSource = dmgType;
        editActor.immunities         = immunities;
        editActor.actionTarget       = targetType;
        editActor.percentChanceToHit = chanceToHit;
        editActor.initiative         = init;
        editActor.hitPoints          = currentHP;
        #endregion
    }
Example #9
0
    private void DisplayDerivedProperties()
    {
        showDerivedProperties = EditorGUILayout.Foldout(showDerivedProperties, new GUIContent("Derived Properties", "Properties based on static unit stats."));
        if (showDerivedProperties)
        {
            derivedStats = AssetDatabase.LoadAssetAtPath("Assets/DerivedProperties.asset", typeof(DerivedStatList)) as DerivedStatList;
            if (derivedStats == null)
            {
                UnityEngine.MonoBehaviour.print("Nope, not there");
                derivedStats = ScriptableObject.CreateInstance <DerivedStatList>();
                AssetDatabase.CreateAsset(derivedStats, "Assets/DerivedProperties.asset");
                AssetDatabase.SaveAssets();
            }

            int nameFieldWidth = 80;
            for (int i = 0; i < derivedStats.Length; i++)
            {
                int statNameWidth = (int)EditorStyles.textField.CalcSize(new GUIContent(derivedStats.list[i].statName + " ")).x;
                if (statNameWidth > nameFieldWidth)
                {
                    nameFieldWidth = statNameWidth;
                }
            }

            bool derivedPropEquationChanged = false;

            EditorGUILayout.BeginVertical();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Name", GUILayout.Width(nameFieldWidth));
            EditorGUILayout.LabelField("Expression");
            EditorGUILayout.LabelField("Current Value", GUILayout.MaxWidth(90));
            EditorGUILayout.EndHorizontal();



            for (int i = 0; i < (derivedStats != null ? derivedStats.Length : 0); i++)
            {
                EditorGUILayout.BeginHorizontal();

                // TODO: Watch out for repeats
                derivedStats.list[i].statName = EditorGUILayout.TextField(derivedStats.list[i].statName, GUILayout.Width(nameFieldWidth));

                int    derivedValue = 0;
                string derivedEquationErrorMessage = string.Empty;

                // How to detect expression errors vs. circular definitions?
                if (!derivedStats.list[i].TryEvaluate((target as Actor), derivedStats, out derivedValue))
                {
                    derivedEquationErrorMessage = "Invalid expression.";
                }

                string newDerivedPropEquation = EditorGUILayout.TextField(derivedStats.list[i].expression, derivedEquationErrorMessage.Length == 0 ? EditorStyles.textField : errorBoxStyle);
                if (derivedEquationErrorMessage.Length > 0)
                {
                    GUI.Label(GUILayoutUtility.GetLastRect(), new GUIContent(string.Empty, derivedEquationErrorMessage));
                }
                else
                {
                    EditorGUILayout.LabelField(derivedValue.ToString(), GUILayout.MaxWidth(90));
                }

                if (newDerivedPropEquation != derivedStats.list[i].expression)
                {
                    derivedPropEquationChanged = true;
                }

                derivedStats.list[i].expression = newDerivedPropEquation;

                EditorGUILayout.EndHorizontal();
            }



            EditorGUILayout.EndVertical();

            bool added = false;
            if (GUILayout.Button("Add"))
            {
                added = true;
                if (derivedStats == null)
                {
                    derivedStats = new DerivedStatList();
                }

                List <DerivedStat> newDerivedStats;
                if (derivedStats.list != null)
                {
                    newDerivedStats = new List <DerivedStat>(derivedStats.list);
                }
                else
                {
                    newDerivedStats = new List <DerivedStat>();
                }
                newDerivedStats.Add(new DerivedStat());

                derivedStats.list = newDerivedStats.ToArray();
                this.Repaint();
            }


            if (GUI.changed || added)
            {
                EditorUtility.SetDirty(derivedStats);
                serializedObject.ApplyModifiedProperties();
                AssetDatabase.SaveAssets();
            }

            if (derivedPropEquationChanged)
            {
                this.Repaint();
            }
        }
    }