Пример #1
0
        public void FieldOfViewUpdate()
        {
            //UInt16 range = _statsDerivative[(sbyte)StatDerivative.SightRange];
            UInt16 range = GetSightRange();

            //Map currentMap = this.InhabitedMap;

            if (range < 0)
            {
                return;
            }

            //REMOVE REDUNDANCY HERE
            BitArray[] update = new BitArray[_map.BoundX];
            for (int i = 0; i < _map.BoundX; ++i)
            {
                update[i] = new BitArray(_map.BoundY);
            }

            for (Int32 i = -range; i <= range; i++)
            {
                for (Int32 j = -range; j <= range; j++)
                {
                    Coords current = new Coords(CoordsType.Tile, _positionTile.X + i, _positionTile.Y + j);
                    if (
                        !this._map.CheckInBounds(current)
                        ||
                        (StaticMathFunctions.DistanceBetweenTwoCoordsHex(this._positionTile, current) > range)
                        )
                    {
                        continue;
                    }

                    bool val = _myVisibilityTracker.RayTracerVisibilityCheckTile(this._positionTile, current, true, range);

                    update[current.X][current.Y] = val;
                }
            }

            // determine values that were changed
            for (int i = 0; i < _map.BoundX; ++i)
            {
                update[i] = update[i].Xor(_fieldOfView[i]);
            }

            // update changes
            for (int i = 0; i < _map.BoundX; ++i)
            {
                for (int j = 0; j < _map.BoundY; ++j)
                {
                    if (update[i][j])
                    {
                        bool val = _fieldOfView[i][j];
                        _fieldOfView[i][j] = !val;
                        //_inhabitedMap.GetTile(i, j).VisibilityUpdate(this, !val);
                        _myVisibilityTracker.VisibilityUpdate(new Coords(CoordsType.Tile, i, j), this, !val);
                    }
                }
            }
        }
Пример #2
0
        public override bool Execute(Coords?_target)
        {
            if (_target == null)
            {
                throw new Exception("Basic Attack no target hex passed.");
            }

            _range = _agent.GetAttackRange();
            int distance = StaticMathFunctions.DistanceBetweenTwoCoordsHex(_agent.PositionGet(), _target.Value);

            if (distance > _range)
            {
                // target not in range; do nothing
                return(false);
            }

            Creature quarry = _map.TenancyMap[_target.Value.X, _target.Value.Y];

            if (quarry == null)
            {
                // no one to hit: do nothing.
                return(false);
            }

            Item weapon = _agent.InventoryEquipped.GetItem((sbyte)InventoryType.HandWeapon);

            if (weapon == null || (weapon.ItemFunctions[ItemProperty.Range] <= 1))
            {
                // weapon not of proper type; do nothing.
                return(false);
            }

            // determine damage
            int damage = (UInt16)Math.Max(_agent.GetAttackDamage() - quarry.GetArmor(), 1);

            // substract HP
//            quarry.AddToStatBasic(Creature.StatBasic.HP, -damage);
            quarry.EffectRegister(new EffectChangeStatBasic(_agent, 0, quarry, Creature.StatBasic.HP, -damage));

            // NOTE: AP substraction done at ActionUseSpell level.

            // Check if target is dead.
            //if (quarry.Dead)
            //{
            //    _agent.AddToStatBasic(Creature.StatBasic.XP, StaticMathFunctions.XPFormula(quarry));
            //}

            // Ranged attack anim
            // for now use arrow by default; later associate particle sprites to the various ranged weapons (slings?)
            _drawer.Animations.Add(new AnimProjectile(Constants.AnimProjectileArrowBaseSpeed * distance,
                                                      _drawer.Particles[(sbyte)SpriteParticle.ParticleArrow],
                                                      _interface.HexPosition(_agent.PositionGet()) + new Vector2(Constants.TileSize / 2, Constants.TileSize / 2),
                                                      _interface.HexPosition(_target.Value) + new Vector2(Constants.TileSize / 2, Constants.TileSize / 2)));

            // Floating message addition
            _drawer.FloatingMessages.Add(new FloatingMessage(Constants.FloatingTextDefaultTimer, "-" + damage.ToString() + "HP",
                                                             _interface.HexPosition(_target.Value) + new Vector2(Constants.TileSize / 2, Constants.TileSize / 2)));

            return(true);
        }
Пример #3
0
        public List<Direction> RetrieveRoute(Coords goal)
        {
            if (_owner.PositionGet() != _currentOrigin)
            {
                Update();
            }

            if (!_currentMap.CheckInBounds(goal) || !_rangeMap[goal.X][goal.Y])
            {
                return null;
            }

            List<Direction> returnList = new List<Direction>();

            Coords trackbackCoords = goal;
            while (trackbackCoords != _currentOrigin)
            {
                Direction newDirection = _directionMap[trackbackCoords.X, trackbackCoords.Y].Value;
                returnList.Add(newDirection);
                trackbackCoords = StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, trackbackCoords),
                    StaticMathFunctions.OppositeDirection(newDirection));
            }

            return returnList;
        }
Пример #4
0
        /// <summary>
        /// Returns list of possible moves, sorted by
        /// 1) amount of increase, 2) distance to influence map source
        /// THIS METHOD SHOULD BE IMPROVED
        /// </summary>
        public List <Direction> PossibleMoves(Coords currentPosition)
        {
            List <Direction> dirList = new List <Direction>();

            Tile currentTile = this._currentMap.GetTile(currentPosition);

            for (byte i = 1; i <= 8; i++)
            {
                Direction currentDir = (Direction)i;
                if (currentTile.AllowedMovesCheckInDirection(currentDir))
                {
                    dirList.Add(currentDir);
                }
            }

            dirList.Sort(
                delegate(Direction d1, Direction d2)
            {
                Coords c1 = StaticMathFunctions.CoordsNeighboringInDirection(currentPosition, d1);
                Coords c2 = StaticMathFunctions.CoordsNeighboringInDirection(currentPosition, d2);

                Int32 returnVal = (this._influenceMap[c1.X, c1.Y]).CompareTo(this._influenceMap[c2.X, c2.Y]);

                if (returnVal == 0)
                {
                    returnVal = (StaticMathFunctions.DistanceBetweenTwoCoordsEucledean(c1, currentPosition)).CompareTo
                                    (StaticMathFunctions.DistanceBetweenTwoCoordsEucledean(c2, currentPosition));
                }

                return(returnVal);
            }
                );

            return(dirList);
        }
Пример #5
0
        public override bool Execute(Coords?_target)
        {
            if (_target == null)
            {
                throw new Exception("Basic Attack no target hex passed.");
            }

            int distance = StaticMathFunctions.DistanceBetweenTwoCoordsHex(_agent.PositionGet(), _target.Value);

            if (distance > 1)
            {
                // target not in range; do nothing
                return(false);
            }

            Creature quarry = _map.TenancyMap[_target.Value.X, _target.Value.Y];

            if (quarry == null)
            {
                // no one to hit: do nothing.
                return(false);
            }

            Item weapon = _agent.InventoryEquipped.GetItem((sbyte)InventoryType.HandWeapon);

            if (weapon != null && (weapon.MyType != ItemType.Weapon || weapon.ItemFunctions[ItemProperty.Range] > 1))
            {
                // weapon not of proper type; do nothing.
                return(false);
            }

            // determine damage
            int damage = (UInt16)Math.Max(_agent.GetAttackDamage() - quarry.GetArmor(), 1);

            // substract HP
            //quarry.AddToStatBasic(Creature.StatBasic.HP, -damage);
            quarry.EffectRegister(new EffectChangeStatBasic(_agent, 0, quarry, Creature.StatBasic.HP, -damage));

            // Check if target is dead.
            //if (quarry.Dead)
            //{
            //    _agent.AddToStatBasic(Creature.StatBasic.XP, StaticMathFunctions.XPFormula(quarry));
            //}

            // NOTE: AP substraction done at ActionUseSpell level.

            // Melee slash anim
            if (weapon != null)
            {
                _drawer.Animations.Add(new AnimWeaponSlash(Constants.AnimWeaponSlashBaseDuration, _drawer.Items[(sbyte)weapon.ItemBitmap],
                                                           _interface.HexPosition(_target.Value) + new Vector2(Constants.TileSize / 2, Constants.TileSize / 2)));
            }

            // Floating message addition
            _drawer.FloatingMessages.Add(new FloatingMessage(Constants.FloatingTextDefaultTimer, "-" + damage.ToString() + "HP",
                                                             _interface.HexPosition(_target.Value) + new Vector2(Constants.TileSize / 2, Constants.TileSize / 2)));

            return(true);
        }
Пример #6
0
 private void CheckEnemyVanquished()
 {
     if (_target.Dead)
     {
         // target vanquished; apply XP gain to effect author (if appropriate).
         _author.AddToStatBasic(Creature.StatBasic.XP, StaticMathFunctions.XPFormula(_target));
     }
 }
Пример #7
0
        private void DrawCreatures(SpriteBatch spriteBatch)
        {
            int tilesize = Constants.TileSize;
            int offset   = tilesize / 4;

            // CREATURES
            foreach (KeyValuePair <UInt32, Creature> kvp in _currentMap.Menagerie)
            {
                Creature  tenant            = kvp.Value;
                Texture2D tenantBitmap      = _creatures[(sbyte)tenant.MyBitmap];
                Int32     i                 = tenant.PositionGet().X;
                Int32     j                 = tenant.PositionGet().Y;
                Int16     visibilityTracker = _currentMap.MyVisibilityTracker.VisibilityCheck(tenant.PositionGet(), _myGame.PlayerTeam);
                Vector2   pos               = new Vector2(i * tilesize + (j % 2) * (tilesize / 2), j * tilesize - j * offset) + _screenAnchor;
                Rectangle rectHex           = ZoomTransform(new Rectangle((int)pos.X, (int)pos.Y, tilesize, tilesize));
                Rectangle rectCreature      = ZoomTransform(new Rectangle((int)pos.X, (int)pos.Y, tenantBitmap.Width, tenantBitmap.Height));

                if (tenant != null && (tenant.Team == _myGame.PlayerTeam || visibilityTracker > 0))
                {
                    // if the tenant is selected, draw selection box
                    if (_myInterface.SelectedCreature == tenant)
                    {
                        spriteBatch.Draw(_tiles[(sbyte)SpriteTile.HexRed], rectHex, Color.White);
                    }

                    // if the tenant is an enemy and within range of a friendly selected creature, draw an indication
                    if (_myInterface.SelectedCreature != null && _myInterface.SelectedCreature.Team == _myGame.PlayerTeam &&
                        tenant.Team != _myGame.PlayerTeam && _myInterface.SelectedCreature.GetAttackRange() >=
                        StaticMathFunctions.DistanceBetweenTwoCoordsHex(_myInterface.SelectedCreature.PositionGet(), tenant.PositionGet()))
                    {
                        spriteBatch.Draw(_tiles[(sbyte)SpriteTile.HexRed], rectHex, Color.Red);
                    }

                    // If there is an active animation for the creature, draw it.
                    if (_creatureAnimations.ContainsKey(tenant.UniqueID))
                    {
                        List <AnimUnitMove> currentStack = _creatureAnimations[tenant.UniqueID];
                        AnimUnitMove        current      = currentStack.Last();
                        current.Draw(spriteBatch, _screenAnchor, Color.White, _zoom);
                    }
                    // Otherwise, draw static sprite of the creature.
                    else
                    {
                        spriteBatch.Draw(_creatures[(sbyte)tenant.MyBitmap], rectCreature, Color.White);

                        //HP bar:
                        float   hpRatio     = (float)tenant.GetHP() / (float)tenant.GetHPMax();
                        Vector2 barLocation = pos;
                        barLocation.X += 3 * Constants.TileSize / 4;
                        barLocation.Y += (1 - hpRatio) * Constants.TileSize;
                        Color drawColor = Color.Lerp(Color.Red, Color.Green, hpRatio);
                        drawColor.A = 64;
                        spriteBatch.Draw(_particles[(sbyte)SpriteParticle.ParticlePixel], ZoomTransform(new Rectangle((int)barLocation.X,
                                                                                                                      (int)barLocation.Y, Constants.TileSize / 12, (int)(hpRatio * Constants.TileSize))), drawColor);
                    }
                }
            }
        }
Пример #8
0
        public AnimProjectile(Int32 durationMax, Texture2D sprite, Vector2 origin, Vector2 goal)
            : base(durationMax, new Texture2D[] { sprite }, origin)
        {
            _goal    = goal;
            _delta   = (goal - origin);
            _delta.X = _delta.X / durationMax;
            _delta.Y = _delta.Y / durationMax;

            _angle = StaticMathFunctions.VectorToAngle(_delta);
        }
Пример #9
0
        /// <summary>
        ///  Analyzes and remembers tile accessibility. Starts at northwest corner and goes through the array,
        ///  checking east / southeast / south / southwest on the current tile and in case of accessibility
        ///  recording the result in both directions.
        /// </summary>
        public void AnalyzeTileAccessibility()
        {
            Tile currentTile;

            for (UInt16 i = 0; i < this._xMax; i++)
            {
                for (UInt16 j = 0; j < this._yMax; j++)
                {
                    Tile east, southEast, southWest;
                    currentTile = this._tiles[i, j];
                    if (Constants.APMoveCostsStandard[(sbyte)currentTile.MyTerrainType] == 0)
                    {
                        continue;
                    }

                    //_vacancyMap[i][j] = true;

                    _visibilityMap[i, j] = currentTile.VisibilityCoefficient;

                    // Sort of wasteful, hopefully compiler does this smartly
                    if (i < _xMax - 1)
                    {
                        east = this.GetTile(StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, i, j), Direction.East));
                        if (east.IsPassable())
                        {
                            currentTile.AllowedMovesSet(Direction.East, true);
                            east.AllowedMovesSet(Direction.West, true);
                        }
                    }

                    if ((i < _xMax - 1) & (j < _yMax - 1))
                    {
                        southEast = this.GetTile(StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, i, j), Direction.Southeast));
                        if (southEast.IsPassable())
                        {
                            currentTile.AllowedMovesSet(Direction.Southeast, true);
                            southEast.AllowedMovesSet(Direction.Northwest, true);
                        }
                    }

                    if ((i > 0) & (j < _yMax - 1))
                    {
                        southWest = this.GetTile(StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, i, j), Direction.Southwest));
                        if (southWest.IsPassable())
                        {
                            currentTile.AllowedMovesSet(Direction.Southwest, true);
                            southWest.AllowedMovesSet(Direction.Northeast, true);
                        }
                    }
                }
            }
        }
Пример #10
0
 public Int32 DistanceTo(Coords c)
 {
     return(StaticMathFunctions.DistanceBetweenTwoCoordsHex(this, c));
 }
Пример #11
0
        private List<Direction> _PathfinderAStar(Coords start, Coords endTopLeft, Coords endBottomRight, BitArray[] _passabilityMap, hFunction h)
        {
            // NOTE: Should later implemented a collision predictor mechanic to work in tandem
            // with the path-finder to provide better agent behavior.
            // NOTE: Consider returning the number of tiles scanned in case no path is found.
            // This will alert a boxed-in creature of its predicament.
            // NOTE: Introduce a flag for a straight-line initial check(for outdoors environmens and
            // for when the goal is near).

            Int32 rangeX = _passabilityMap.Length;
            Int32 rangeY = _passabilityMap[0].Count;

            NodeAStar?[,] nodeArray = new NodeAStar?[rangeX, rangeY];

            NodeAStar startNode = new NodeAStar();
            startNode.costSoFar = 0;
            startNode.estimatedTotalCost = h(start);

            nodeArray[start.X, start.Y] = startNode;

            List<Coords> ListOpen = new List<Coords>();
            ListOpen.Add(start);
            while (ListOpen.Count > 0)
            {
                // I have to use this bool the way I've implemented the algo. Consider rewriting.
                bool resortList = false;

                Coords currentCoords = ListOpen.First();
                // Check to see if goal is reached.
                //if (currentCoords.Equals(endTopLeft))
                if (StaticMathFunctions.CoordinateIsInBox(currentCoords, endTopLeft, endBottomRight))
                {
                    break;
                }

                NodeAStar currentNode = nodeArray[currentCoords.X, currentCoords.Y].Value;
                for (byte i = 0; i <= 5; ++i)
                {
                    Direction currentDir = (Direction)(i);
                    //Coords dirCoords = StaticMathFunctions.DirectionToCoords(currentDir);
                    Coords potential = StaticMathFunctions.CoordsNeighboringInDirection(currentCoords, currentDir);
                    // check if move in dir is allowed
                    if (potential.X >= 0 && potential.X < rangeX && potential.Y >= 0 && potential.Y < rangeY // bounds check
                        && _passabilityMap[potential.X][potential.Y]) // passability check
                    {
                        // Using the simplest cost function possible. Can be easily updated
                        // once tile walkability coefficients are added.
                        //Coords newNodePosition = new Coords(CoordsType.General, currentCoords.X + dirCoords.X, currentCoords.Y + dirCoords.Y);
                        Coords newNodePosition = potential;
                        float accruedCost = currentNode.costSoFar + 1;

                        // Straight line correction
                        if (currentDir == nodeArray[currentCoords.X, currentCoords.Y].Value.connection)
                        {
                            accruedCost -= Constants.PathfinderStraightPathCorrection;
                        }

                        // Check to see if the node under examination is in the closed list.
                        //NodeAStar? oldNode = nodeArray[newNodePosition.X, newNodePosition.Y];
                        if (nodeArray[newNodePosition.X, newNodePosition.Y] != null)
                        {
                            // If node is in closed list, see if it needs updating.
                            if (nodeArray[newNodePosition.X, newNodePosition.Y].Value.costSoFar > accruedCost)
                            {
                                float expectedAdditionalCost =
                                    nodeArray[newNodePosition.X, newNodePosition.Y].Value.estimatedTotalCost -
                                    nodeArray[newNodePosition.X, newNodePosition.Y].Value.costSoFar;
                                NodeAStar nodeToAdd =
                                    new NodeAStar(currentDir, accruedCost, accruedCost + expectedAdditionalCost);
                                nodeArray[newNodePosition.X, newNodePosition.Y] = nodeToAdd;
                                ListOpen.Add(newNodePosition);
                                resortList = true;
                            }
                        }
                        // Node is in open list. Process it.
                        else
                        {
                            float expectedAdditionalCost = h(newNodePosition);
                            NodeAStar nodeToAdd =
                                new NodeAStar(currentDir, accruedCost, accruedCost + expectedAdditionalCost);
                            nodeArray[newNodePosition.X, newNodePosition.Y] = nodeToAdd;
                            ListOpen.Add(newNodePosition);
                            resortList = true;
                        }
                    }
                }

                ListOpen.RemoveAt(0);
                if (resortList)
                {
                    ListOpen.Sort(
                        delegate(Coords c1, Coords c2)
                        {
                            float difference = nodeArray[c1.X, c1.Y].Value.estimatedTotalCost -
                                nodeArray[c2.X, c2.Y].Value.estimatedTotalCost;

                            Int32 returnValue = 0;
                            if (difference > 0)
                            {
                                returnValue = 1;
                            }
                            else if (difference < 0)
                            {
                                returnValue = -1;
                            }
                            return returnValue;
                        }
                    );
                }
            }

            List<Direction> ListRoute = new List<Direction>();

            // Return empty route if the open list is empty, i.e. there is no path to the target
            // Ideally, the game logic should be fixed so that the search isn't even attempted
            // if there is no path between the two points.
            if (ListOpen.Count == 0)
            {
                return ListRoute;
            }

            Coords trackbackCoords = endTopLeft;
            while (trackbackCoords != start)
            {
                Direction newDirection = nodeArray[trackbackCoords.X, trackbackCoords.Y].Value.connection;
                ListRoute.Add(newDirection);
                trackbackCoords = StaticMathFunctions.CoordsNeighboringInDirection(new Coords(CoordsType.Tile, trackbackCoords),
                    StaticMathFunctions.OppositeDirection(newDirection));
            }

            // Might be faster without reversing
            //ListRoute.Reverse();

            // We skip the reversal, so pick directions from the END of the list.
            return ListRoute;
        }
Пример #12
0
        private void CalculateMoveRange(Coords origin, UInt16[] moveCosts, UInt16 availableAP)
        {
            _currentOrigin = origin;

            for (int i = 0; i < _currentMap.BoundX; ++i)
            {
                for (int j = 0; j < _currentMap.BoundY; ++j)
                {
                    _APCount[i, j] = -1;
                    _directionMap[i, j] = null;
                }
            }

            _APCount[origin.X, origin.Y] = availableAP;

            // WARNING: Code repetition with influence maps / A*

            Queue<Coords> currentQueue = new Queue<Coords>();
            Queue<Coords> nextQueue = new Queue<Coords>();

            currentQueue.Enqueue(origin);

            UInt32 currentDistance = 0;

            // main loop
            // Stopping conditions: the two queues are exhausted, OR InfluenceMapMaxDistance is reached
            while
                (
                ((currentQueue.Count > 0) & (nextQueue.Count > 0))
                |
                (currentDistance < Constants.InfluenceMapMaxDistance)
                )
            {
                // Checks if it's time to start the next pass
                if (currentQueue.Count == 0)
                {
                    currentQueue = nextQueue;
                    nextQueue = new Queue<Coords>();
                    currentDistance++;
                    continue;
                }

                Coords currentCoords = currentQueue.Peek();
                //Coords delta1 = currentCoords - origin;
                Tile currentTile = _currentMap.GetTile(currentCoords);

                // Analyzes the neighbors of the current Tile for possible additions to nextQueue
                for (byte i = 0; i < 6; i++)
                {
                    Direction currentDir = (Direction)i;
                    Coords toCheck = StaticMathFunctions.CoordsNeighboringInDirection(currentCoords, currentDir);
                    if (_currentMap.CheckInBounds(toCheck))
                    {
                        Tile targetTile = _currentMap.GetTile(toCheck);
                        UInt16 cost = moveCosts[(sbyte)targetTile.MyTerrainType];

                        if (cost > 0 && _currentMap.TenancyMap[toCheck.X, toCheck.Y] == null) // ignore impassable terrain and ignore occupied tiles
                        {
                            // checks if this approach is cheaper than the best approach so far
                            Int32 currentAPleft = _APCount[toCheck.X, toCheck.Y];
                            Int32 potentialAPleft = _APCount[currentCoords.X, currentCoords.Y] - cost;
                            if (currentAPleft < potentialAPleft)
                            {
                                _APCount[toCheck.X, toCheck.Y] = (UInt16)potentialAPleft;
                                _directionMap[toCheck.X, toCheck.Y] = currentDir;
                                nextQueue.Enqueue(toCheck);
                            }
                        }
                    }
                }

                currentQueue.Dequeue();
            }


            for (int i = 0; i < _currentMap.BoundX; ++i)
            {
                for (int j = 0; j < _currentMap.BoundY; ++j)
                {
                    _rangeMap[i][j] = _APCount[i, j] >= 0;
                }
            }

            //return rangeMap;
        }
Пример #13
0
 /// <summary>
 /// Tile-level (coarse) A* pathfinding.
 /// </summary>
 /// <param name="start"> Start Coords </param>
 /// <param name="endTopLeft"> Goal-box TopLeft Coords </param>
 /// <param name="endBottomRight"> Goal-box BottomRight Coords </param>
 /// <param name="h"> Heuristic function </param>
 /// <returns> Route to goal, as a list of Directions </returns>
 public List<Direction> PathfinderAStarCoarse(Coords start, Coords endTopLeft, Coords endBottomRight, HeuristicFunction h)
 {
     return this._PathfinderAStar(new Coords(CoordsType.General, start), new Coords(CoordsType.General, endTopLeft), new Coords(CoordsType.General, endBottomRight), this._passabilityMap,
         delegate(Coords c) { return h(c, StaticMathFunctions.CoordsAverage(endTopLeft, endBottomRight)); });
 }
Пример #14
0
        /// Generates the influence map.
        /// Uses a silly recursive algorithm.
        /// Stopping conditions: Let's use two, to avoid stupid infinite loops.
        /// One is a distance threshold check.
        // Second is a min influence threshold check.

        /// <summary>
        /// Generates the influence map.
        /// Uses a silly recursive algorithm.
        /// Stopping conditions: Let's use two, to avoid stupid infinite loops.
        /// One is a distance threshold check.
        /// Second is a min influence threshold check.
        /// </summary>
        public void GenerateInfluenceMap()
        {
            // boolean array to keep note of which tiles have been processed
            //BitArray[,] takenCareOf = new BitArray[_currentMap.BoundX, _currentMap.BoundY];
            BitArray[] takenCareOf = new BitArray[_currentMap.BoundX];
            for (int i = 0; i < _currentMap.BoundX; ++i)
            {
                takenCareOf[i] = new BitArray(_currentMap.BoundY);
            }
            takenCareOf[Source.X][Source.Y] = true;

            // sets up two queues - one for the current pass, one for the next one
            // distance increments by one at each pass
            // if too slow, the process should be broken up so it does a number of passes each tick
            Queue <Coords> currentQueue = new Queue <Coords>();
            Queue <Coords> nextQueue    = new Queue <Coords>();

            currentQueue.Enqueue(_source);

            UInt32 currentDistance = 0;

            // main loop
            // Stopping conditions: the two queues are exhausted, OR InfluenceMapMaxDistance is reached
            while
            (
                ((currentQueue.Count > 0) & (nextQueue.Count > 0))
                |
                (currentDistance < Constants.InfluenceMapMaxDistance)
            )
            {
                // Checks if it's time to start the next pass
                if (currentQueue.Count == 0)
                {
                    currentQueue = nextQueue;
                    nextQueue    = new Queue <Coords>();
                    currentDistance++;
                    continue;
                }

                Coords currentCoords = currentQueue.Peek();
                Tile   currentTile   = CurrentMap.GetTile(currentCoords);

                // Analyzes the neighbors of the current Tile for possible additions to nextQueue
                for (byte i = 0; i < 6; i++)
                {
                    Direction currentDir = (Direction)i;
                    if (currentTile.AllowedMovesCheckInDirection(currentDir))
                    {
                        Coords toCheck = StaticMathFunctions.CoordsNeighboringInDirection(currentCoords, currentDir);
                        if (!takenCareOf[toCheck.X][toCheck.Y])
                        {
                            nextQueue.Enqueue(toCheck);
                            takenCareOf[toCheck.X][toCheck.Y] = true;
                        }
                    }
                }

                float newVal = _f(currentDistance);

                // Check to avert infnite / excessively deep loop
                if (newVal > _lowTreshold)
                {
                    this.SetMapValue(currentCoords, newVal);
                }

                currentQueue.Dequeue();
            }
        }