fixed several bugs with shared playfield bitmap in MM game engine
[rocksndiamonds.git] / src / game_mm / mm_game.c
index 4b864e6937ace2acfb7f8fffe0d073fffca2ae42..c5cfa1d562c738c32adbd5c5d6ec84cdc8d8c61b 100644 (file)
@@ -364,7 +364,7 @@ static void DrawLaserLines(struct XY *points, int num_points, int mode)
   Pixel pixel_drawto = (mode == DL_LASER_ENABLED ? pen_ray     : pen_bg);
   Pixel pixel_buffer = (mode == DL_LASER_ENABLED ? WHITE_PIXEL : BLACK_PIXEL);
 
-  DrawLines(drawto, points, num_points, pixel_drawto);
+  DrawLines(drawto_mm, points, num_points, pixel_drawto);
 
   BEGIN_NO_HEADLESS
   {
@@ -570,6 +570,8 @@ static void InitField(int x, int y, boolean init_game)
           game_mm.laser_green = native_mm_level.df_laser_green;
           game_mm.laser_blue  = native_mm_level.df_laser_blue;
         }
+
+       game_mm.has_mcduffin = (IS_MCDUFFIN(element));
       }
 
       break;
@@ -642,8 +644,8 @@ void InitGameEngine_MM(void)
   BEGIN_NO_HEADLESS
   {
     // initialize laser bitmap to current playfield (screen) size
-    ReCreateBitmap(&laser_bitmap, drawto->width, drawto->height);
-    ClearRectangle(laser_bitmap, 0, 0, drawto->width, drawto->height);
+    ReCreateBitmap(&laser_bitmap, drawto_mm->width, drawto_mm->height);
+    ClearRectangle(laser_bitmap, 0, 0, drawto_mm->width, drawto_mm->height);
   }
   END_NO_HEADLESS
 
@@ -662,10 +664,12 @@ void InitGameEngine_MM(void)
   game_mm.laser_red = FALSE;
   game_mm.laser_green = FALSE;
   game_mm.laser_blue = TRUE;
+  game_mm.has_mcduffin = TRUE;
 
   game_mm.level_solved = FALSE;
   game_mm.game_over = FALSE;
   game_mm.game_over_cause = 0;
+  game_mm.game_over_message = NULL;
 
   game_mm.laser_overload_value = 0;
   game_mm.laser_enabled = FALSE;
@@ -758,7 +762,7 @@ void InitGameActions_MM(void)
 
     DrawLevel_MM();
 
-    BackToFront();
+    BackToFront_MM();
 
 #ifdef DEBUG
     if (setup.quick_doors)
@@ -791,7 +795,7 @@ static void FadeOutLaser(void)
 
     DrawLaser(0, DL_LASER_ENABLED);
 
-    BackToFront();
+    BackToFront_MM();
     Delay_WithScreenUpdates(50);
   }
 
@@ -802,25 +806,23 @@ static void FadeOutLaser(void)
 
 static void GameOver_MM(int game_over_cause)
 {
-  // do not handle game over if request dialog is already active
-  if (game.request_active)
-    return;
-
   game_mm.game_over = TRUE;
   game_mm.game_over_cause = game_over_cause;
-
-  // do not ask to play again if game was never actually played
-  if (!game.GamePlayed)
-    return;
-
-  if (setup.ask_on_game_over)
-    game.restart_game_message = (game_over_cause == GAME_OVER_BOMB ?
-                                "Bomb killed Mc Duffin! Play it again?" :
-                                game_over_cause == GAME_OVER_NO_ENERGY ?
-                                "Out of magic energy! Play it again?" :
-                                game_over_cause == GAME_OVER_OVERLOADED ?
-                                "Magic spell hit Mc Duffin! Play it again?" :
-                                NULL);
+  game_mm.game_over_message = (game_mm.has_mcduffin ?
+                              (game_over_cause == GAME_OVER_BOMB ?
+                               "Bomb killed Mc Duffin!" :
+                               game_over_cause == GAME_OVER_NO_ENERGY ?
+                               "Out of magic energy!" :
+                               game_over_cause == GAME_OVER_OVERLOADED ?
+                               "Magic spell hit Mc Duffin!" :
+                               NULL) :
+                              (game_over_cause == GAME_OVER_BOMB ?
+                               "Bomb destroyed laser cannon!" :
+                               game_over_cause == GAME_OVER_NO_ENERGY ?
+                               "Out of laser energy!" :
+                               game_over_cause == GAME_OVER_OVERLOADED ?
+                               "Laser beam hit laser cannon!" :
+                               NULL));
 
   SetTileCursorActive(FALSE);
 }
@@ -913,6 +915,26 @@ static int ScanPixel(void)
     }
 #endif
 
+    // check if laser scan has crossed element boundaries (not just mini tiles)
+    boolean cross_x = (LX / TILEX != (LX + 2) / TILEX);
+    boolean cross_y = (LY / TILEY != (LY + 2) / TILEY);
+
+    if (cross_x && cross_y)
+    {
+      int elx1 = (LX - XS) / TILEX;
+      int ely1 = (LY + YS) / TILEY;
+      int elx2 = (LX + XS) / TILEX;
+      int ely2 = (LY - YS) / TILEY;
+
+      // add element corners left and right from the laser beam to damage list
+
+      if (IN_LEV_FIELD(elx1, ely1) && Tile[elx1][ely1] != EL_EMPTY)
+       AddDamagedField(elx1, ely1);
+
+      if (IN_LEV_FIELD(elx2, ely2) && Tile[elx2][ely2] != EL_EMPTY)
+       AddDamagedField(elx2, ely2);
+    }
+
     for (i = 0; i < 4; i++)
     {
       int px = LX + (i % 2) * 2;
@@ -2006,10 +2028,16 @@ static boolean HitPolarizer(int element, int hit_mask)
   }
   else if (IS_GRID_STEEL(element))
   {
+    // may be required if graphics for steel grid redefined
+    AddDamagedField(ELX, ELY);
+
     return HitReflectingWalls(element, hit_mask);
   }
   else // IS_GRID_WOOD
   {
+    // may be required if graphics for wooden grid redefined
+    AddDamagedField(ELX, ELY);
+
     return HitAbsorbingWalls(element, hit_mask);
   }
 
@@ -2539,7 +2567,7 @@ static void OpenGrayBall(int x, int y)
       DrawWalls_MM(x, y, Store[x][y]);
 
       // copy wall tile to spare bitmap for "melting" animation
-      BlitBitmap(drawto, bitmap_db_field, cSX + x * TILEX, cSY + y * TILEY,
+      BlitBitmap(drawto_mm, bitmap_db_field, cSX + x * TILEX, cSY + y * TILEY,
                 TILEX, TILEY, x * TILEX, y * TILEY);
 
       DrawElement_MM(x, y, EL_GRAY_BALL);
@@ -2572,7 +2600,7 @@ static void OpenGrayBall(int x, int y)
        getGraphicSource(graphic, 0, &bitmap, &gx, &gy);
       }
 
-      BlitBitmap(bitmap, drawto, gx + dx, gy + dy, 6, 6,
+      BlitBitmap(bitmap, drawto_mm, gx + dx, gy + dy, 6, 6,
                 cSX + x * TILEX + dx, cSY + y * TILEY + dy);
 
       laser.redraw = TRUE;
@@ -2625,7 +2653,7 @@ static void OpenEnvelope(int x, int y)
 
       ScanLaser();
 
-      ShowEnvelope_MM(nr);
+      ShowEnvelope(nr);
     }
   }
 }
@@ -2804,11 +2832,9 @@ static void Explode_MM(int x, int y, int phase, int mode)
 
       Bang_MM(laser.start_edge.x, laser.start_edge.y);
 
-      GameOver_MM(GAME_OVER_DELAYED);
-
       laser.overloaded = FALSE;
     }
-    else if (IS_MCDUFFIN(center_element))
+    else if (IS_MCDUFFIN(center_element) || IS_LASER(center_element))
     {
       GameOver_MM(GAME_OVER_BOMB);
     }
@@ -3724,7 +3750,7 @@ static void GameActions_MM_Ext(void)
 
       UpdateAndDisplayGameControlValues();
 
-      BackToFront();
+      BackToFront_MM();
     }
 
     Tile[ELX][ELY] = laser.dest_element = EL_FUEL_EMPTY;
@@ -3823,7 +3849,7 @@ static void MovePacMen(void)
     }
 
     DrawField_MM(nx, ny);
-    BackToFront();
+    BackToFront_MM();
 
     if (!laser.fuse_off)
     {