fixed bugs with wrong X/Y access in element mask in MM engine
[rocksndiamonds.git] / src / game_mm / mm_game.c
index b21f119727e415b455afcdf9f477d23220c53949..bc72f5bd43c2169505ae7eaae1a1827c3437856e 100644 (file)
@@ -1209,14 +1209,10 @@ static void ScanLaser(void)
       break;
     }
 
-    boolean diagonally_adjacent_hit = FALSE;
-
     // handle special case of laser hitting two diagonally adjacent elements
     // (with or without a third corner element behind these two elements)
     if ((diag_1 || diag_2) && cross_x && cross_y)
     {
-      diagonally_adjacent_hit = TRUE;
-
       // compare the two diagonally adjacent elements
       int xoffset = 2;
       int yoffset = 2 * (diag_1 ? -1 : +1);
@@ -1332,29 +1328,6 @@ static void ScanLaser(void)
          break;
       }
     }
-    else if (IS_DF_SLOPE(element))
-    {
-      if (diagonally_adjacent_hit)
-      {
-       laser.overloaded = TRUE;
-
-       break;
-      }
-
-      if (hit_mask == HIT_MASK_LEFT ||
-         hit_mask == HIT_MASK_RIGHT ||
-         hit_mask == HIT_MASK_TOP ||
-         hit_mask == HIT_MASK_BOTTOM)
-      {
-       if (HitReflectingWalls(element, hit_mask))
-         break;
-      }
-      else
-      {
-       if (HitElement(element, hit_mask))
-         break;
-      }
-    }
     else
     {
       if (HitElement(element, hit_mask))
@@ -1711,6 +1684,39 @@ static boolean HitElement(int element, int hit_mask)
 {
   if (IS_DF_SLOPE(element))
   {
+    // check if laser scan has crossed element boundaries (not just mini tiles)
+    boolean cross_x = (getLevelFromLaserX(LX) != getLevelFromLaserX(LX + 2));
+    boolean cross_y = (getLevelFromLaserY(LY) != getLevelFromLaserY(LY + 2));
+
+    // check if wall (horizontal or vertical) side of slope was hit
+    if (hit_mask == HIT_MASK_LEFT ||
+       hit_mask == HIT_MASK_RIGHT ||
+       hit_mask == HIT_MASK_TOP ||
+       hit_mask == HIT_MASK_BOTTOM)
+    {
+      return HitReflectingWalls(element, hit_mask);
+    }
+
+    // check if an edge was hit while crossing element borders
+    if (cross_x && cross_y && get_number_of_bits(hit_mask) == 1)
+    {
+      // check both sides of potentially diagonal side of slope
+      int dx1 = (LX + XS) % TILEX;
+      int dy1 = (LY + YS) % TILEY;
+      int dx2 = (LX + XS + 2) % TILEX;
+      int dy2 = (LY + YS + 2) % TILEY;
+      int pos = getMaskFromElement(element);
+
+      // check if we are entering empty space area after hitting edge
+      if (mm_masks[pos][dy1 / 2][dx1 / 2] != 'X' &&
+         mm_masks[pos][dy2 / 2][dx2 / 2] != 'X')
+      {
+       // we already know that we hit an edge, but use this function to go on
+       if (HitOnlyAnEdge(hit_mask))
+         return FALSE;
+      }
+    }
+
     int mirrored_angle = get_mirrored_angle(laser.current_angle,
                                            get_element_angle(element));
     int opposite_angle = get_opposite_angle(laser.current_angle);
@@ -1718,9 +1724,6 @@ static boolean HitElement(int element, int hit_mask)
     // check if laser is reflected by slope by 180°
     if (mirrored_angle == opposite_angle)
     {
-      LX += XS;
-      LY += YS;
-
       AddDamagedField(LX / TILEX, LY / TILEY);
 
       laser.overloaded = TRUE;
@@ -1995,7 +1998,7 @@ static boolean HitElement(int element, int hit_mask)
          {
            int pos = getMaskFromElement(element_side);
 
-           if (mm_masks[pos][dx / 2][dy / 2] == 'X')
+           if (mm_masks[pos][dy / 2][dx / 2] == 'X')
              laser.overloaded = TRUE;
          }
        }