/* Mapping the best route across the floor to the hero will require: * 1. Initialize int array with same size as floor plan using CreateMapForMonsters() * a. First time, all values are 0 * b. If a tile is not walkable, mark the space as -1 * c. Each reset of the array will only reset values > 0 back to 0 using ResetPathFinder() * 2. Starting from hero (with value 1), cycle outward adding 1 to hop count in any space in the * array not containing a value > 0 (or already blocked by -1). This continues until each * frenzied monster has been identified with a value > 0 in the array (at which point there is no * need to continue any furthur). * a. To cycle outward, each point in the array should be ran through an outer loop, testing each space * around it for a value > 0. * b. When a value > 0 is detected, pick the lowest value found and add 1 for the current space. * 3. During a monster turn, each monster checks the points immediately around him to pick a * point with the smallest number to move to. If this point is the hero, then the attack commences. * 4. The pathCounters array must be reset and recalculated with each move of the hero if, and * only if any one monster is triggered to seek out the hero. * */ internal static void CalculateDistanceMap() { ResetPositiveValues(); // Ignores blocked tiles with value of -1 // Step 2, set space with hero to 1 if (GameConstants.DEBUG_MODE_WALK_THROUGH_WALLS && FloorGenerator.MovementBlockedByFloor(DungeonGameEngine.Hero.Location)) { // Setting hero's tile to 1 when he walks on a wall causes everything to freeze so we need to // abort drawing the distance map. Monsters will stop moving if chasing the hero is true. return; } else { pathCounters[DungeonGameEngine.Hero.Location.X, DungeonGameEngine.Hero.Location.Y] = 1; } int outerlayer = 1; // Actualy one higher than outer layer to avoid repeating math in the for loop or <= operator. int layer; do { outerlayer++; for (layer = 1; layer < outerlayer; layer++) { foreach (var checkPoint in PointsInLayer(layer, DungeonGameEngine.Hero.Location)) { Rectangle floorBounds = new Rectangle(0, 0, FloorGenerator.FloorWidth, FloorGenerator.FloorHeight); if (!floorBounds.Contains(checkPoint)) { continue; } // Skip space if it's already blocked if (pathCounters[checkPoint.X, checkPoint.Y] == -1) { if (GameConstants.DEBUG_MODE_DRAW_STEPS_TO_HERO) { pathCounterText[checkPoint.X, checkPoint.Y].Text = pathCounters[checkPoint.X, checkPoint.Y].ToString(); } continue; } // First, check to see if space is still unmapped if (pathCounters[checkPoint.X, checkPoint.Y] == unmappedValue) { // Check all spaces around current space to get smallest value > 0, then add one to it var lowestPosValue = FindLowestPositiveValue(checkPoint.X, checkPoint.Y); if (lowestPosValue > 0 && lowestPosValue < unmappedValue && lowestPosValue < pathCounters[checkPoint.X, checkPoint.Y] + 1) { pathCounters[checkPoint.X, checkPoint.Y] = lowestPosValue + 1; } // Added in case DEBUG_MODE_WALK_THROUGH_WALLS enabled to // close up the path left on the blocking tiles if (GameConstants.DEBUG_MODE_WALK_THROUGH_WALLS && !FloorGenerator.TileIsPassible(FloorGenerator.GetTileAt(checkPoint))) { pathCounters[checkPoint.X, checkPoint.Y] = -1; } } if (GameConstants.DEBUG_MODE_DRAW_STEPS_TO_HERO) { if (pathCounters[checkPoint.X, checkPoint.Y] > 99) { pathCounterText[checkPoint.X, checkPoint.Y].Text = "XX"; } else { pathCounterText[checkPoint.X, checkPoint.Y].Text = pathCounters[checkPoint.X, checkPoint.Y].ToString(); } } } } } while (!GridMapped(outerlayer)); }