Another version of BLA

From RogueBasin
Jump to navigation Jump to search
/* Adapted from the code displayed at RogueBasin's "Bresenham's Line
 * Algorithm" article, this function checks for an unobstructed line
 * of sight between two locations using Bresenham's line algorithm to
 * draw a line from one point to the other. Returns true if there is
 * line of sight, false if there is no line of sight. */
int los (int los_x_1, int los_y_1, int los_x_2, int
         los_y_2, int level) {
   int delta_x, delta_y, move_x, move_y, error;

   /* Calculate deltas. */
   delta_x = abs (los_x_2 - los_x_1) << 1;
   delta_y = abs (los_y_2 - los_y_1) << 1;

   /* Calculate signs. */
   move_x = los_x_2 >= los_x_1 ? 1 : -1;
   move_y = los_y_2 >= los_y_1 ? 1 : -1;

   /* There is an automatic line of sight, of course, between a
    * location and the same location or directly adjacent
    * locations. */
   if (abs (los_x_2 - los_x_1) < 2 && abs (los_y_2 - los_y_1) < 2) {
      /* Return. */
      return true;
   }

   /* Ensure that the line will not extend too long. */
   if (((los_x_2 - los_x_1) * (los_x_2 - los_x_1))
       + ((los_y_2 - los_y_1) * (los_y_2 -
                                 los_y_1)) >
       LOS_DISTANCE * LOS_DISTANCE) {
      /* Return. */
      return false;
   }

   /* "Draw" the line, checking for obstructions. */
   if (delta_x >= delta_y) {
      /* Calculate the error factor, which may go below zero. */
      error = delta_y - (delta_x >> 1);

      /* Search the line. */
      while (los_x_1 != los_x_2) {
         /* Check for an obstruction. If the obstruction can be "moved
          * around", it isn't really an obstruction. */
         if (feature_data
             (dungeon (los_x_1, los_y_1, level).feature).obstruction
             &&
             (((los_y_1 - move_y >= 1
                && los_y_1 - move_y <= DUNGEON_HEIGHT)
               &&
               feature_data (dungeon
                                    (los_x_1, los_y_1 - move_y,
                                     level).feature).obstruction)
              || (los_y_1 != los_y_2 || !(delta_y)))) {
            /* Return. */
            return false;
         }

         /* Update values. */
         if (error > 0) {
            if (error || (move_x > 0)) {
               los_y_1 += move_y;
               error -= delta_x;
            }
         }
         los_x_1 += move_x;
         error += delta_y;
      }
   }
   else {
      /* Calculate the error factor, which may go below zero. */
      error = delta_x - (delta_y >> 1);

      /* Search the line. */
      while (los_y_1 != los_y_2) {
         /* Check for an obstruction. If the obstruction can be "moved
          * around", it isn't really an obstruction. */
         if (feature_data
             (dungeon (los_x_1, los_y_1, level).feature).obstruction
             &&
             (((los_x_1 - move_x >= 1
                && los_x_1 - move_x <= DUNGEON_WIDTH)
               &&
               feature_data (dungeon
                                    (los_x_1 - move_x, los_y_1,
                                     level).feature).obstruction)
              || (los_x_1 != los_x_2 || !(delta_x)))) {
            /* Return. */
            return false;
         }

         /* Update values. */
         if (error > 0) {
            if (error || (move_y > 0)) {
               los_x_1 += move_x;
               error -= delta_y;
            }
         }
         los_y_1 += move_y;
         error += delta_x;
      }
   }

   /* Return. */
   return true;
}