//Ability range
    public static HashSet <GridCell> GetAbilityRange(GridCell location, int minRange, int maxRange, bool los, bool linear, bool freeCell, bool ai = false)
    {
        GetGridCells();
        HashSet <GridCell> inRange = new HashSet <GridCell> ();
        HashSet <GridCell> canSee  = new HashSet <GridCell> ();
        HashSet <GridCell> retVal  = new HashSet <GridCell> ();

        //non linear
        if (!linear)
        {
            foreach (GridCell c in cells.Values)
            {
                if (location.CalcDistance(c) <= maxRange && location.CalcDistance(c) >= minRange)
                {
                    if (!inRange.Contains(c))
                    {
                        if (c.CanTarget(freeCell))
                        {
                            inRange.Add(c);
                        }
                    }
                }
            }
        }
        else
        {
            //linear
            for (int x = -maxRange; x <= maxRange; x++)
            {
                GridPos pos = new GridPos(location.gridPos.x - x, location.gridPos.y);
                if (cells.ContainsKey(pos))
                {
                    GridCell c = cells [pos];
                    if (c.CalcDistance(location) <= maxRange && c.CalcDistance(location) >= minRange)
                    {
                        if (c.CanTarget(freeCell))
                        {
                            inRange.Add(c);
                        }
                    }
                }
            }
            for (int y = -maxRange; y <= maxRange; y++)
            {
                GridPos pos = new GridPos(location.gridPos.x, location.gridPos.y - y);
                if (cells.ContainsKey(pos))
                {
                    GridCell c = cells [pos];
                    if (c.CalcDistance(location) <= maxRange && c.CalcDistance(location) >= minRange)
                    {
                        if (c.CanTarget(freeCell))
                        {
                            inRange.Add(c);
                        }
                    }
                }
            }
        }
        //Highlight
        //	if (!ai) {
        //		GameObject.FindGameObjectWithTag ("Battle Controller").GetComponent<GridHighlighter> ().HighlightNonVisibleCell (inRange);
        //	}

        //Check LoS
        if (los)
        {
            foreach (GridCell c in inRange)
            {
                GridCell hit = CheckLoS(location.gridPos.x, location.gridPos.y, c.gridPos.x, c.gridPos.y);
                if (hit.CanTarget(freeCell))
                {
                    if (!canSee.Contains(hit))
                    {
                        canSee.Add(hit);
                    }
                }
            }
        }
        else
        {
            return(inRange);
        }

        //Filter out range errors
        foreach (GridCell c in canSee)
        {
            if (location.CalcDistance(c) >= minRange)
            {
                retVal.Add(c);
            }
        }
        return(retVal);
    }
    public static HashSet <GridCell> GetAoE(GridCell target, GridCell start, eAreaType aoe, int size)
    {
        HashSet <GridCell> area = new HashSet <GridCell> ();

        GetGridCells();

        string facing = start.GetFacing(target);

        switch (aoe)
        {
        case eAreaType.SINGLE:
            area.Add(target);
            return(area);

        case eAreaType.CIRCLE:
            for (int x = -size; x <= size; x++)
            {
                for (int y = -size; y <= size; y++)
                {
                    GridPos p = new GridPos(target.gridPos.x - x, target.gridPos.y - y);
                    if (cells.ContainsKey(p))
                    {
                        if (target.CalcDistance(cells [p]) <= size)
                        {
                            if (!area.Contains(cells[p]))
                            {
                                area.Add(cells [p]);
                            }
                        }
                    }
                }
            }
            return(area);

        case eAreaType.CROSS:
            for (int x = -size; x <= size; x++)
            {
                GridPos p = new GridPos(target.gridPos.x - x, target.gridPos.y);
                if (cells.ContainsKey(p))
                {
                    if (!area.Contains(cells [p]))
                    {
                        area.Add(cells [p]);
                    }
                }
            }
            for (int y = -size; y <= size; y++)
            {
                GridPos p = new GridPos(target.gridPos.x, target.gridPos.y - y);
                if (cells.ContainsKey(p))
                {
                    if (!area.Contains(cells [p]))
                    {
                        area.Add(cells [p]);
                    }
                }
            }
            return(area);

        case eAreaType.V_LINE:
            if (facing == "NE")
            {
                for (int y = 0; y <= size; y++)
                {
                    GridPos p = new GridPos(target.gridPos.x, target.gridPos.y + y);
                    if (cells.ContainsKey(p))
                    {
                        if (!area.Contains(cells [p]))
                        {
                            area.Add(cells [p]);
                        }
                    }
                }
            }
            else if (facing == "SE")
            {
                for (int x = 0; x <= size; x++)
                {
                    GridPos p = new GridPos(target.gridPos.x + x, target.gridPos.y);
                    if (cells.ContainsKey(p))
                    {
                        if (!area.Contains(cells [p]))
                        {
                            area.Add(cells [p]);
                        }
                    }
                }
            }
            else if (facing == "SW")
            {
                for (int y = 0; y <= size; y++)
                {
                    GridPos p = new GridPos(target.gridPos.x, target.gridPos.y - y);
                    if (cells.ContainsKey(p))
                    {
                        if (!area.Contains(cells [p]))
                        {
                            area.Add(cells [p]);
                        }
                    }
                }
            }
            else if (facing == "NW")
            {
                for (int x = 0; x <= size; x++)
                {
                    GridPos p = new GridPos(target.gridPos.x - x, target.gridPos.y);
                    if (cells.ContainsKey(p))
                    {
                        if (!area.Contains(cells [p]))
                        {
                            area.Add(cells [p]);
                        }
                    }
                }
            }
            return(area);

        case eAreaType.H_LINE:

            return(area);
        }

        return(area);
    }
    public override void TargetSelect(GridCell origin, int level, int bonusRange, Ability_new ability)
    {
        Reset();

        int maxRange = ability.adjustableRange ? ability.maxRangePerLvl [level - 1] + bonusRange : ability.maxRangePerLvl[level - 1];

        if (maxRange < ability.minRange)
        {
            maxRange = ability.minRange;
        }

        bool requiresLoS = ability.requiresLoS;

        //non linear
        if (!ability.isLinear)
        {
            foreach (GridCell c in grid.Values)
            {
                if (origin.CalcDistance(c) <= maxRange && origin.CalcDistance(c) >= ability.minRange)
                {
                    if (!targetable.Contains(c) && !untargetable.Contains(c))
                    {
                        if (!untargetable.Contains(c))
                        {
                            untargetable.Add(c);
                        }

                        if (requiresLoS)
                        {
                            GridCell hit = CheckLoS(origin.gridPos.x, origin.gridPos.y, c.gridPos.x, c.gridPos.y);
                            if (!targetable.Contains(hit))
                            {
                                targetable.Add(hit);
                            }
                        }
                        else
                        {
                            if (!targetable.Contains(c))
                            {
                                targetable.Add(c);
                            }
                        }
                    }
                }
            }
        }
        else
        {
            //linear
            for (int x = -maxRange; x <= maxRange; x++)
            {
                GridPos pos = new GridPos(origin.gridPos.x - x, origin.gridPos.y);
                if (grid.ContainsKey(pos))
                {
                    GridCell c = grid [pos];
                    if (c.CalcDistance(origin) <= maxRange && c.CalcDistance(origin) >= ability.minRange)
                    {
                        if (!targetable.Contains(c) && !untargetable.Contains(c))
                        {
                            if (!untargetable.Contains(c))
                            {
                                untargetable.Add(c);
                            }

                            if (requiresLoS)
                            {
                                GridCell hit = CheckLoS(origin.gridPos.x, origin.gridPos.y, c.gridPos.x, c.gridPos.y);
                                if (!targetable.Contains(hit))
                                {
                                    targetable.Add(hit);
                                }
                            }
                            else
                            {
                                if (!targetable.Contains(c))
                                {
                                    targetable.Add(c);
                                }
                            }
                        }
                    }
                }
            }
            for (int y = -maxRange; y <= maxRange; y++)
            {
                GridPos pos = new GridPos(origin.gridPos.x, origin.gridPos.y - y);
                if (grid.ContainsKey(pos))
                {
                    GridCell c = grid [pos];
                    if (c.CalcDistance(origin) <= maxRange && c.CalcDistance(origin) >= ability.minRange)
                    {
                        if (!targetable.Contains(c) && !untargetable.Contains(c))
                        {
                            if (!untargetable.Contains(c))
                            {
                                untargetable.Add(c);
                            }

                            if (requiresLoS)
                            {
                                GridCell hit = CheckLoS(origin.gridPos.x, origin.gridPos.y, c.gridPos.x, c.gridPos.y);
                                if (!targetable.Contains(hit))
                                {
                                    targetable.Add(hit);
                                }
                            }
                            else
                            {
                                if (!targetable.Contains(c))
                                {
                                    targetable.Add(c);
                                }
                            }
                        }
                    }
                }
            }
        }
    }