Vector2 DrawAbilityConfigurator(float startX, float startY, Ability ability)
        {
            float originX = startX;
            float originY = startY;
            //float cachedX=startX;
            float cachedY = startY;

            cont = new GUIContent("Prefab:", "The prefab object of the tower\nClick this to highlight it in the ProjectTab");
            EditorGUI.LabelField(new Rect(startX + 65, startY, width, height), cont);
            abilityList[selectID].prefab = (GameObject)EditorGUI.ObjectField(new Rect(startX + 120, startY, 130, height), abilityList[selectID].prefab, typeof(GameObject), false);

            cont = new GUIContent("ID :" + ability.ID, "The prefab object of the tower\nClick this to highlight it in the ProjectTab");
            EditorGUI.LabelField(new Rect(startX + 260, startY, width, height), cont);

            //EditorUtilities.DrawSprite(new Rect(startX, startY, 60, 60), ability.icon);
            startX += 65;

            cont = new GUIContent("Name:", "The ability name to be displayed in game");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.name = EditorGUI.TextField(new Rect(startX + spaceX - 65, startY, width - 5, height), ability.name);

            cont = new GUIContent("Selfcast:", "When checked, Selfcast ability");
            EditorGUI.LabelField(new Rect(startX + 235, startY, width + 10, height), cont);
            ability.selfCast = EditorGUI.Toggle(new Rect(startX + 290, startY, 40, height), ability.selfCast);

            if (!ability.selfCast)
            {
                cont = new GUIContent("At Caster:", "Cast at position of Caster");
                EditorGUI.LabelField(new Rect(startX + 310, startY, width + 10, height), cont);
                ability.castAtCaster = EditorGUI.Toggle(new Rect(startX + 365, startY, 40, height), ability.castAtCaster);
            }

            cont = new GUIContent("Layer:", "Layer of targetable object");
            EditorGUI.LabelField(new Rect(startX + 235, startY += spaceY, width + 10, height), cont);
            ability.customMask = EditorUtilities.LayerMaskField(new Rect(startX + 290, startY, 100, height), "", ability.customMask);

            //ability.customMask = EditorGUI.IntField(new Rect(startX + 390, startY+40, 185, height), ability.customMask);

            cont = new GUIContent("Icon:", "The ability icon to be displayed in game, must be a sprite");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.icon = (Sprite)EditorGUI.ObjectField(new Rect(originX, originY, 60, 60), ability.icon, typeof(Sprite), false);

            cont = new GUIContent("Disable in AbilityManager:", "When checked, the ability won't appear on AbilityManager list and thus can't be access from the get go\nThis is to mark ability that can only be unlocked from perk");
            EditorGUI.LabelField(new Rect(startX + 235, startY, width + 10, height), cont);
            ability.disableInAbilityManager = EditorGUI.Toggle(new Rect(startX + 400, startY, 185, height), ability.disableInAbilityManager);

            cont = new GUIContent("Belong to Hero:", "When checked, the ability won't appear on AbilityManager list and thus can't be access from the get go\nThis is to mark ability that can only be unlocked from perk");
            EditorGUI.LabelField(new Rect(startX + 235, startY += spaceY, width + 10, height), cont);
            ability.belongToHero = EditorGUI.Toggle(new Rect(startX + 400, startY, 185, height), ability.belongToHero);


            startX -= 65;
            startY += 10 + spaceY / 2;

            cachedY = startY + spaceY;

            cont = new GUIContent("Cost:", "The energy cost to use the ability");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.cost = EditorGUI.IntField(new Rect(startX + spaceX, startY, 40, height), ability.cost);

            cont = new GUIContent("Cooldown:", "The cooldown duration of the ability. Once used, the ability cannot be used again until the cooldown duration has passed");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.cooldown = EditorGUI.FloatField(new Rect(startX + spaceX, startY, 40, height), ability.cooldown);


            cont = new GUIContent("Ability type:", "Check if ability need a specific position or unit as target. When checked, the user will need to select a position/unit before the ability can be cast. Otherwise the ability be cast without a target position/unit. If ability uses default effects and this is unchecked, the effect will be apply to all unit in the game");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            contL = new GUIContent[abilityTypeLabel.Length];
            for (int i = 0; i < contL.Length; i++)
            {
                contL[i] = new GUIContent(abilityTypeLabel[i], abilityTypeTooltip[i]);
            }
            ability.abilityType = (Ability.AbilityType)EditorGUI.Popup(new Rect(startX + spaceX, startY, width - 20, height), new GUIContent(""), (int)ability.abilityType, contL);

            // ability.requireTargetSelection = EditorGUI.Toggle(new Rect(startX + spaceX, startY, 40, height), ability.requireTargetSelection);

            if (ability.requireTargetSelection)
            {
                cont = new GUIContent(" - Single Unit Only:", "Check if the ability require a specific unit as a target. Otherwise the ability can be cast anywhere without a specific target");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                ability.singleUnitTargeting = EditorGUI.Toggle(new Rect(startX + spaceX, startY, 40, height), ability.singleUnitTargeting);

                if (ability.singleUnitTargeting)
                {
                    //~ cont=new GUIContent(" - Target Friendly:", "Check if the ability is meant to target firendly unit. Otherwise it will target");
                    //~ EditorGUI.LabelField(new Rect(startX, startY+=spaceY, width, height), cont);
                    //~ ability.targetType=EditorGUI.Toggle(new Rect(startX+spaceX, startY, 40, height), ability.targetType);

                    cont = new GUIContent(" - Target :", "Determine which type of unit the tower can target. Hostile for hostile unit. Friendly for friendly unit. Hybrid for both.");
                    EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                    contL = new GUIContent[targetTypeLabel.Length];
                }

                cont = new GUIContent(" - Indicator:", "(Optional) The cursor indicator that used to indicate the ability target position during target selection phase for the ability. If left unassigned, the default indicator specified in the AbilityManager will be used instead");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                ability.indicator = (Transform)EditorGUI.ObjectField(new Rect(startX + spaceX, startY, width, height), ability.indicator, typeof(Transform), false);

                if (ability.indicator == null)
                {
                    cont = new GUIContent(" - Scale Indicator:", "Automatically scale the indicator size to match the aoeRadius of the ability, or a unit width in case of a single unit targeting. Only applicable if ability is using default effects");
                    EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                    ability.autoScaleIndicator = EditorGUI.Toggle(new Rect(startX + spaceX, startY, 40, height), ability.autoScaleIndicator);
                }
                else
                {
                    cont = new GUIContent(" - Scale Indicator:", "Automatically scale the indicator size to match the aoeRadius of the ability. Only applicable if ability is using default effects");
                    EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                    EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");
                }
            }
            else
            {
                cont = new GUIContent(" - Targets Unit:", "Check if the unit is immuned to critical hit");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");

                cont = new GUIContent(" - Indicator:", "(Optional) The cursor indicator that used to indicate the ability target position during target selection phase for the ability. If left unassigned, the default indicator specified in the AbilityManager will be used instead");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");

                cont = new GUIContent(" - Scale Indicator:", "Automatically scale the indicator size to match the aoeRadius of the ability. Only applicable if ability is using default effects");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");
            }


            cont = new GUIContent("Max Use Count:", "The maximum amount which the ability can be used in a level. Indicate unlimited usage when set to <0");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.maxUseCount = EditorGUI.IntField(new Rect(startX + spaceX, startY, 40, height), ability.maxUseCount);


            //cont = new GUIContent("Effect Object:", "The effect object spawned at the selected position when the ability is used. This object can contain custom script to do custom effect for the ability");
            //EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            //ability.effectObj = (GameObject)EditorGUI.ObjectField(new Rect(startX + spaceX, startY, width, height), ability.effectObj, typeof(GameObject), false);

            //if(!ability.effectObj && ability.prefab)
            //{
            //    ability.effectObj = ability.prefab;
            //}

            cont = new GUIContent("Use Default Effect:", "Check to use default built in ability effects. Alternative you can script your custom effect and have it spawn as the ability's EffectObject");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.useDefaultEffect = EditorGUI.Toggle(new Rect(startX + spaceX, startY, 40, height), ability.useDefaultEffect);

            if (ability.useDefaultEffect)
            {
                if (ability.requireTargetSelection)
                {
                    cont = new GUIContent(" - AOE Radius:", "The Area of Effective radius of the effect. Only target within the radius of the target position will be affected by the ability");
                    EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                    ability.aoeRadius = EditorGUI.FloatField(new Rect(startX + spaceX, startY, 40, height), ability.aoeRadius);
                }
                else
                {
                    cont = new GUIContent(" - AOE Radius:", "The Area of Effective radius of the effect. Only target within the radius of the target position will be affected by the ability");
                    EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                    EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");
                }

                cont = new GUIContent(" - Effect Delay:", "The delay in second before the effect actually hit after the ability is cast. This is mostly used to sync-up the visual effect with the effects.");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                ability.effectDelay = EditorGUI.FloatField(new Rect(startX + spaceX, startY, 40, height), ability.effectDelay);
            }
            else
            {
                cont = new GUIContent(" - AOE Radius:", "The Area of Effective radius of the effect. Only target within the radius of the target position will be affected by the ability");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");

                cont = new GUIContent(" - Effect Delay:", "The delay in second before the effect actually hit after the ability is cast. This is mostly used to sync-up the visual effect with the effects.");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
                EditorGUI.LabelField(new Rect(startX + spaceX, startY, width, height), "not applicable");
            }

            startY += 10;


            cont = new GUIContent("Custom Description:", "Check to use use custom description. If not, the default one (generated based on the effect) will be used");
            EditorGUI.LabelField(new Rect(startX, startY += spaceY, width, height), cont);
            ability.useCustomDesp = EditorGUI.Toggle(new Rect(startX + spaceX, startY, 40, height), ability.useCustomDesp);
            if (ability.useCustomDesp)
            {
                GUIStyle style = new GUIStyle("TextArea");
                style.wordWrap = true;
                cont           = new GUIContent("Perk description (to be used in runtime): ", "");
                EditorGUI.LabelField(new Rect(startX, startY += spaceY, 400, 20), cont);
                ability.desp = EditorGUI.TextArea(new Rect(startX, startY + spaceY - 3, 270, 150), ability.desp, style);
            }


            if (ability.useDefaultEffect)
            {
                startY  = cachedY;
                startX += 300;
                Vector2 v2 = DrawAbilityEffect(ability.effect, startX, startY);
                startX -= 300;
                startY  = v2.y;
            }

            if (abilityList[selectID].prefab)
            {
                AbilityBehavior ab = abilityList[selectID].prefab.GetComponent <AbilityBehavior>();
                ab.ability = ability;

                EditorUtility.SetDirty(ab);
                EditorUtility.SetDirty(abilityList[selectID].prefab);
            }
            //UnitEditorWindow.DrawStat(ability.effect.stat, startX, startY, 700);


            float contWidth = spaceX + width;

            return(new Vector2(contWidth, startY + 700));
        }
        Vector2 DrawAbilityList(float startX, float startY)
        {
            float width = 260;

            if (minimiseList)
            {
                width = 60;
            }


            if (!minimiseList)
            {
                if (GUI.Button(new Rect(startX + 180, startY - 20, 40, 18), "up"))
                {
                    if (selectID > 0)
                    {
                        Ability ability = abilityList[selectID];
                        abilityList[selectID]     = abilityList[selectID - 1];
                        abilityList[selectID - 1] = ability;
                        selectID -= 1;

                        if (selectID * 35 < scrollPos1.y)
                        {
                            scrollPos1.y = selectID * 35;
                        }
                    }
                }
                if (GUI.Button(new Rect(startX + 222, startY - 20, 40, 18), "down"))
                {
                    if (selectID < abilityList.Count - 1)
                    {
                        Ability ability = abilityList[selectID];
                        abilityList[selectID]     = abilityList[selectID + 1];
                        abilityList[selectID + 1] = ability;
                        selectID += 1;

                        if (listVisibleRect.height - 35 < selectID * 35)
                        {
                            scrollPos1.y = (selectID + 1) * 35 - listVisibleRect.height + 5;
                        }
                    }
                }
            }


            listVisibleRect = new Rect(startX, startY, width + 15, window.position.height - startY - 5);
            listContentRect = new Rect(startX, startY, width, abilityList.Count * 35 + 5);

            GUI.color = new Color(.8f, .8f, .8f, 1f);
            GUI.Box(listVisibleRect, "");
            GUI.color = Color.white;

            scrollPos1 = GUI.BeginScrollView(listVisibleRect, scrollPos1, listContentRect);

            startY += 5; startX += 5;

            for (int i = 0; i < abilityList.Count; i++)
            {
                EditorUtilities.DrawSprite(new Rect(startX, startY + (i * 35), 30, 30), abilityList[i].icon);

                if (minimiseList)
                {
                    if (selectID == i)
                    {
                        GUI.color = new Color(0, 1f, 1f, 1f);
                    }
                    if (GUI.Button(new Rect(startX + 35, startY + (i * 35), 30, 30), ""))
                    {
                        SelectAbility(i);
                    }
                    GUI.color = Color.white;

                    continue;
                }



                if (selectID == i)
                {
                    GUI.color = new Color(0, 1f, 1f, 1f);
                }
                if (GUI.Button(new Rect(startX + 35, startY + (i * 35), 150, 30), abilityList[i].name))
                {
                    SelectAbility(i);
                }
                GUI.color = Color.white;

                if (deleteID == i)
                {
                    if (GUI.Button(new Rect(startX + 190, startY + (i * 35), 60, 15), "cancel"))
                    {
                        deleteID = -1;
                    }

                    GUI.color = Color.red;
                    if (GUI.Button(new Rect(startX + 190, startY + (i * 35) + 15, 60, 15), "confirm"))
                    {
                        if (selectID >= deleteID)
                        {
                            SelectAbility(Math.Max(0, selectID - 1));
                        }
                        abilityList.RemoveAt(deleteID);
                        deleteID = -1;
                    }
                    GUI.color = Color.white;
                }
                else
                {
                    if (GUI.Button(new Rect(startX + 190, startY + (i * 35), 60, 15), "remove"))
                    {
                        deleteID = i;
                    }
                }
            }

            GUI.EndScrollView();

            return(new Vector2(startX + width, startY));
        }
        void OnGUI()
        {
            if (window == null)
            {
                Init();
            }

            if (GUI.Button(new Rect(window.position.width - 120, 5, 100, 25), "Save"))
            {
                EditorUtility.SetDirty(prefab);
            }

            EditorGUI.LabelField(new Rect(250, 7, 150, 17), "Add new ability:");
            GameObject abilityPrefab = null;

            abilityPrefab = (GameObject)EditorGUI.ObjectField(new Rect(350, 7, 140, 17), abilityPrefab, typeof(GameObject), false);
            AddNewAbility(abilityPrefab);

            if (GUI.Button(new Rect(5, 5, 120, 25), "Create New"))
            {
                Ability newAbility = new Ability();

                int ID = GenerateNewID();
                abilityIDList.Add(ID);
                newAbility.ID   = ID;
                newAbility.name = "Ability " + ID;

                abilityList.Add(newAbility);
                SelectAbility(abilityList.Count - 1);

                GUI.changed = true;
            }
            if (abilityList.Count > 0 && GUI.Button(new Rect(130, 5, 100, 25), "Clone Selected"))
            {
                Ability newAbility = abilityList[selectID].Clone();

                int ID = GenerateNewID();
                abilityIDList.Add(ID);
                newAbility.ID    = ID;
                newAbility.name += " (Clone)";

                abilityList.Insert(selectID + 1, newAbility);
                SelectAbility(selectID + 1);

                GUI.changed = true;
            }


            float startX = 5;
            float startY = 55;


            if (minimiseList)
            {
                if (GUI.Button(new Rect(startX, startY - 20, 30, 18), ">>"))
                {
                    minimiseList = false;
                }
            }
            else
            {
                if (GUI.Button(new Rect(startX, startY - 20, 30, 18), "<<"))
                {
                    minimiseList = true;
                }
            }
            Vector2 v2 = DrawAbilityList(startX, startY);

            startX = v2.x + 25;

            if (abilityList.Count == 0)
            {
                return;
            }


            Rect visibleRect = new Rect(startX, startY, window.position.width - startX - 10, window.position.height - startY - 5);
            Rect contentRect = new Rect(startX, startY, contentWidth - startY, contentHeight);

            //~ GUI.color=new Color(.8f, .8f, .8f, 1f);
            //~ GUI.Box(visibleRect, "");
            //~ GUI.color=Color.white;

            scrollPos2 = GUI.BeginScrollView(visibleRect, scrollPos2, contentRect);

            //float cachedX=startX;
            v2 = DrawAbilityConfigurator(startX, startY, abilityList[selectID]);
            //contentWidth=v2.x+50;
            contentHeight = v2.y;

            GUI.EndScrollView();

            contentWidth = startX + 280;


            if (GUI.changed)
            {
                EditorUtility.SetDirty(prefab);

                foreach (Ability ab in prefab.abilityList)
                {
                    if (ab.prefab)
                    {
                        EditorUtility.SetDirty(ab.prefab);
                    }
                }
            }
        }