added support for custom graphics for many elements of MM game engine
[rocksndiamonds.git] / src / game_mm / mm_game.c
index a15772850bacab0182ca5581a28cf2a9fb28eff8..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)
     {
@@ -3119,7 +3134,7 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
       redraw_mask |= REDRAW_DOOR_1;
     }
-    else if (setup.time_limit && !game_mm.game_over)
+    else if (game.time_limit && !game_mm.game_over)
     {
       int i;
 
@@ -3151,19 +3166,6 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
       game.restart_game_message = "Out of magic energy! Play it again?";
 
-#if 0
-      if (Request("Out of magic energy! Play it again?",
-                 REQ_ASK | REQ_STAY_CLOSED))
-      {
-       InitGame();
-      }
-      else
-      {
-       game_status = MAINMENU;
-       DrawMainMenu();
-      }
-#endif
-
       return;
     }
   }
@@ -3190,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++;
@@ -3284,19 +3288,6 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
       game.restart_game_message = "Magic spell hit Mc Duffin! Play it again?";
 
-#if 0
-      if (Request("Magic spell hit Mc Duffin! Play it again?",
-                 REQ_ASK | REQ_STAY_CLOSED))
-      {
-       InitGame();
-      }
-      else
-      {
-       game_status = MAINMENU;
-       DrawMainMenu();
-      }
-#endif
-
       return;
     }
   }
@@ -3311,36 +3302,10 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     if (game_mm.cheat_no_explosion)
       return;
 
-#if 0
-    laser.num_damages--;
-    DrawLaser(0, DL_LASER_DISABLED);
-    laser.num_edges = 0;
-#endif
-
     Bang_MM(ELX, ELY);
 
     laser.dest_element = EL_EXPLODING_OPAQUE;
 
-#if 0
-    Bang_MM(ELX, ELY);
-    laser.num_damages--;
-    DrawLaser(0, DL_LASER_DISABLED);
-
-    laser.num_edges = 0;
-    Bang_MM(laser.start_edge.x, laser.start_edge.y);
-
-    if (Request("Bomb killed Mc Duffin! Play it again?",
-               REQ_ASK | REQ_STAY_CLOSED))
-    {
-      InitGame();
-    }
-    else
-    {
-      game_status = MAINMENU;
-      DrawMainMenu();
-    }
-#endif
-
     return;
   }
 
@@ -3724,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);
 }
@@ -3839,182 +3804,6 @@ void MovePacMen(void)
   }
 }
 
-void GameWon_MM(void)
-{
-  int hi_pos;
-  boolean raise_level = FALSE;
-
-#if 0
-  if (local_player->MovPos)
-    return;
-
-  local_player->LevelSolved = FALSE;
-#endif
-
-  if (game_mm.energy_left)
-  {
-    if (setup.sound_loops)
-      PlaySoundExt(SND_SIRR, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
-                  SND_CTRL_PLAY_LOOP);
-
-    while (game_mm.energy_left > 0)
-    {
-      if (!setup.sound_loops)
-       PlaySoundStereo(SND_SIRR, SOUND_MAX_RIGHT);
-
-      /*
-      if (game_mm.energy_left > 0 && !(game_mm.energy_left % 10))
-       RaiseScore_MM(native_mm_level.score[SC_ZEITBONUS]);
-      */
-
-      RaiseScore_MM(5);
-
-      game_mm.energy_left--;
-      if (game_mm.energy_left >= 0)
-      {
-#if 0
-       BlitBitmap(pix[PIX_DOOR], drawto,
-                  DOOR_GFX_PAGEX5 + XX_ENERGY, DOOR_GFX_PAGEY1 + YY_ENERGY,
-                  ENERGY_XSIZE, ENERGY_YSIZE - game_mm.energy_left,
-                  DX_ENERGY, DY_ENERGY);
-#endif
-       redraw_mask |= REDRAW_DOOR_1;
-      }
-
-      BackToFront();
-      Delay_WithScreenUpdates(10);
-    }
-
-    if (setup.sound_loops)
-      StopSound(SND_SIRR);
-  }
-  else if (native_mm_level.time == 0)          // level without time limit
-  {
-    if (setup.sound_loops)
-      PlaySoundExt(SND_SIRR, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
-                  SND_CTRL_PLAY_LOOP);
-
-    while (TimePlayed < 999)
-    {
-      if (!setup.sound_loops)
-       PlaySoundStereo(SND_SIRR, SOUND_MAX_RIGHT);
-      if (TimePlayed < 999 && !(TimePlayed % 10))
-       RaiseScore_MM(native_mm_level.score[SC_TIME_BONUS]);
-      if (TimePlayed < 900 && !(TimePlayed % 10))
-       TimePlayed += 10;
-      else
-       TimePlayed++;
-
-      /*
-      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
-      */
-
-      BackToFront();
-      Delay_WithScreenUpdates(10);
-    }
-
-    if (setup.sound_loops)
-      StopSound(SND_SIRR);
-  }
-
-  CloseDoor(DOOR_CLOSE_1);
-
-  Request("Level solved!", REQ_CONFIRM);
-
-  if (level_nr == leveldir_current->handicap_level)
-  {
-    leveldir_current->handicap_level++;
-    SaveLevelSetup_SeriesInfo();
-  }
-
-  if (level_editor_test_game)
-    game_mm.score = -1;                // no highscore when playing from editor
-  else if (level_nr < leveldir_current->last_level)
-    raise_level = TRUE;                // advance to next level
-
-  if ((hi_pos = NewHiScore_MM()) >= 0)
-  {
-    game_status = HALLOFFAME;
-
-    // DrawHallOfFame(hi_pos);
-
-    if (raise_level)
-      level_nr++;
-  }
-  else
-  {
-    game_status = MAINMENU;
-
-    if (raise_level)
-      level_nr++;
-
-    // DrawMainMenu();
-  }
-
-  BackToFront();
-}
-
-int NewHiScore_MM(void)
-{
-  int k, l;
-  int position = -1;
-
-  // LoadScore(level_nr);
-
-  if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
-      game_mm.score < highscore[MAX_SCORE_ENTRIES - 1].Score)
-    return -1;
-
-  for (k = 0; k < MAX_SCORE_ENTRIES; k++)
-  {
-    if (game_mm.score > highscore[k].Score)
-    {
-      // player has made it to the hall of fame
-
-      if (k < MAX_SCORE_ENTRIES - 1)
-      {
-       int m = MAX_SCORE_ENTRIES - 1;
-
-#ifdef ONE_PER_NAME
-       for (l = k; l < MAX_SCORE_ENTRIES; l++)
-         if (!strcmp(setup.player_name, highscore[l].Name))
-           m = l;
-       if (m == k)     // player's new highscore overwrites his old one
-         goto put_into_list;
-#endif
-
-       for (l = m; l>k; l--)
-       {
-         strcpy(highscore[l].Name, highscore[l - 1].Name);
-         highscore[l].Score = highscore[l - 1].Score;
-       }
-      }
-
-#ifdef ONE_PER_NAME
-      put_into_list:
-#endif
-      strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
-      highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
-      highscore[k].Score = game_mm.score;
-      position = k;
-
-      break;
-    }
-
-#ifdef ONE_PER_NAME
-    else if (!strncmp(setup.player_name, highscore[k].Name,
-                     MAX_PLAYER_NAME_LEN))
-      break;   // player already there with a higher score
-#endif
-
-  }
-
-  // if (position >= 0)
-  //   SaveScore(level_nr);
-
-  return position;
-}
-
 static void InitMovingField_MM(int x, int y, int direction)
 {
   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
@@ -4189,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;