added support for custom graphics for many elements of MM game engine
[rocksndiamonds.git] / src / game_mm / mm_game.c
index c97a7d3b09f0583080681e20d6bf168b080d077d..1ef6339e826957c521ef5d79efc81935cbd8ebba 100644 (file)
@@ -111,10 +111,10 @@ static int hold_x = -1, hold_y = -1;
 static int pacman_nr = -1;
 
 // various game engine delay counters
-static unsigned int rotate_delay = 0;
-static unsigned int pacman_delay = 0;
-static unsigned int energy_delay = 0;
-static unsigned int overload_delay = 0;
+static DelayCounter rotate_delay = { AUTO_ROTATE_DELAY };
+static DelayCounter pacman_delay = { PACMAN_MOVE_DELAY };
+static DelayCounter energy_delay = { ENERGY_DELAY };
+static DelayCounter overload_delay = { 0 };
 
 // element masks for scanning pixels of MM elements
 static const char mm_masks[10][16][16 + 1] =
@@ -436,7 +436,7 @@ static void InitMovDir_MM(int x, int y)
   }
 }
 
-static void InitField(int x, int y, boolean init_game)
+static void InitField(int x, int y)
 {
   int element = Tile[x][y];
 
@@ -537,7 +537,6 @@ static void InitCycleElements_RotateSingleStep(void)
 
     Tile[x][y] = next_element;
 
-    DrawField_MM(x, y);
     game_mm.cycle[i].steps -= step;
   }
 }
@@ -637,10 +636,10 @@ void InitGameEngine_MM(void)
 
   CT = Ct = 0;
 
-  rotate_delay = 0;
-  pacman_delay = 0;
-  energy_delay = 0;
-  overload_delay = 0;
+  rotate_delay.count = 0;
+  pacman_delay.count = 0;
+  energy_delay.count = 0;
+  overload_delay.count = 0;
 
   ClickElement(-1, -1, -1);
 
@@ -656,7 +655,7 @@ void InitGameEngine_MM(void)
       Frame[x][y] = 0;
       Stop[x][y] = FALSE;
 
-      InitField(x, y, TRUE);
+      InitField(x, y);
     }
   }
 
@@ -691,6 +690,11 @@ void InitGameActions_MM(void)
       cycle_steps_done++;
     }
 
+    AdvanceFrameCounter();
+    AdvanceGfxFrame();
+
+    DrawLevel_MM();
+
     BackToFront();
 
     ColorCycling();
@@ -945,7 +949,7 @@ void ScanLaser(void)
 
     if (element == EL_EMPTY)
     {
-      if (!HitOnlyAnEdge(element, hit_mask))
+      if (!HitOnlyAnEdge(hit_mask))
        break;
     }
     else if (element == EL_FUSE_ON)
@@ -1315,7 +1319,7 @@ void DrawLaser_MM(void)
 
 boolean HitElement(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (IS_MOVING(ELX, ELY) || IS_BLOCKED(ELX, ELY))
@@ -1638,7 +1642,7 @@ boolean HitElement(int element, int hit_mask)
   return TRUE;
 }
 
-boolean HitOnlyAnEdge(int element, int hit_mask)
+boolean HitOnlyAnEdge(int hit_mask)
 {
   // check if the laser hit only the edge of an element and, if so, go on
 
@@ -1697,7 +1701,7 @@ boolean HitOnlyAnEdge(int element, int hit_mask)
 
 boolean HitPolarizer(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (IS_DF_GRID(element))
@@ -1895,7 +1899,7 @@ boolean HitBlock(int element, int hit_mask)
 
 boolean HitLaserSource(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
@@ -1907,7 +1911,7 @@ boolean HitLaserSource(int element, int hit_mask)
 
 boolean HitLaserDestination(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (element != EL_EXIT_OPEN &&
@@ -2143,7 +2147,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
     }
   }
 
-  if (!HitOnlyAnEdge(element, hit_mask))
+  if (!HitOnlyAnEdge(hit_mask))
   {
     laser.overloaded = TRUE;
 
@@ -2155,7 +2159,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
 
 boolean HitAbsorbingWalls(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (ABS(XS) == 4 &&
@@ -2398,6 +2402,16 @@ static void GrowAmoeba(int x, int y)
   }
 }
 
+static void DrawFieldAnimated_MM(int x, int y)
+{
+  if (IS_BLOCKED(x, y))
+    return;
+
+  DrawField_MM(x, y);
+
+  laser.redraw = TRUE;
+}
+
 static void Explode_MM(int x, int y, int phase, int mode)
 {
   int num_phase = 9, delay = 2;
@@ -2470,7 +2484,7 @@ static void Explode_MM(int x, int y, int phase, int mode)
     Store[x][y] = Store2[x][y] = 0;
     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
 
-    InitField(x, y, FALSE);
+    InitField(x, y);
     DrawField_MM(x, y);
   }
   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
@@ -2709,8 +2723,7 @@ static void ContinueMoving_MM(int x, int y)
 
 boolean ClickElement(int x, int y, int button)
 {
-  static unsigned int click_delay = 0;
-  static int click_delay_value = CLICK_DELAY;
+  static DelayCounter click_delay = { CLICK_DELAY };
   static boolean new_button = TRUE;
   boolean element_clicked = FALSE;
   int element;
@@ -2718,8 +2731,8 @@ boolean ClickElement(int x, int y, int button)
   if (button == -1)
   {
     // initialize static variables
-    click_delay = 0;
-    click_delay_value = CLICK_DELAY;
+    click_delay.count = 0;
+    click_delay.value = CLICK_DELAY;
     new_button = TRUE;
 
     return FALSE;
@@ -2732,7 +2745,7 @@ boolean ClickElement(int x, int y, int button)
   if (button == MB_RELEASED)
   {
     new_button = TRUE;
-    click_delay_value = CLICK_DELAY;
+    click_delay.value = CLICK_DELAY;
 
     // release eventually hold auto-rotating mirror
     RotateMirror(x, y, MB_RELEASED);
@@ -2740,7 +2753,7 @@ boolean ClickElement(int x, int y, int button)
     return FALSE;
   }
 
-  if (!FrameReached(&click_delay, click_delay_value) && !new_button)
+  if (!FrameReached(&click_delay) && !new_button)
     return FALSE;
 
   if (button == MB_MIDDLEBUTTON)       // middle button has no function
@@ -2827,7 +2840,7 @@ boolean ClickElement(int x, int y, int button)
     element_clicked = TRUE;
   }
 
-  click_delay_value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
+  click_delay.value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
   new_button = FALSE;
 
   return element_clicked;
@@ -2932,7 +2945,7 @@ static void AutoRotateMirrors(void)
 {
   int x, y;
 
-  if (!FrameReached(&rotate_delay, AUTO_ROTATE_DELAY))
+  if (!FrameReached(&rotate_delay))
     return;
 
   for (x = 0; x < lev_fieldx; x++)
@@ -3057,7 +3070,7 @@ void ColorCycling(void)
   }
 }
 
-static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
+static void GameActions_MM_Ext(void)
 {
   int element;
   int x, y, i;
@@ -3085,6 +3098,8 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
       MeltIce(x, y);
     else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA)
       GrowAmoeba(x, y);
+    else
+      DrawFieldAnimated_MM(x, y);
   }
 
   AutoRotateMirrors();
@@ -3100,7 +3115,7 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
   CT = FrameCounter;
 
-  if (game_mm.num_pacman && FrameReached(&pacman_delay, PACMAN_MOVE_DELAY))
+  if (game_mm.num_pacman && FrameReached(&pacman_delay))
   {
     MovePacMen();
 
@@ -3111,7 +3126,7 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     }
   }
 
-  if (FrameReached(&energy_delay, ENERGY_DELAY))
+  if (FrameReached(&energy_delay))
   {
     if (game_mm.energy_left > 0)
     {
@@ -3177,9 +3192,11 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
       !IS_WALL_AMOEBA(element))
     return;
 
+  overload_delay.value = HEALTH_DELAY(laser.overloaded);
+
   if (((laser.overloaded && laser.overload_value < MAX_LASER_OVERLOAD) ||
        (!laser.overloaded && laser.overload_value > 0)) &&
-      FrameReached(&overload_delay, HEALTH_DELAY(laser.overloaded)))
+      FrameReached(&overload_delay))
   {
     if (laser.overloaded)
       laser.overload_value++;
@@ -3672,12 +3689,12 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
   return;
 }
 
-void GameActions_MM(struct MouseActionInfo action, boolean warp_mode)
+void GameActions_MM(struct MouseActionInfo action)
 {
   boolean element_clicked = ClickElement(action.lx, action.ly, action.button);
   boolean button_released = (action.button == MB_RELEASED);
 
-  GameActions_MM_Ext(action, warp_mode);
+  GameActions_MM_Ext();
 
   CheckSingleStepMode_MM(element_clicked, button_released);
 }
@@ -3961,7 +3978,7 @@ void RaiseScoreElement_MM(int element)
 // Mirror Magic game engine snapshot handling functions
 // ----------------------------------------------------------------------------
 
-void SaveEngineSnapshotValues_MM(ListNode **buffers)
+void SaveEngineSnapshotValues_MM(void)
 {
   int x, y;