removed unneeded delayed screen update when overloading laser (MM engine)
[rocksndiamonds.git] / src / game_mm / mm_game.c
index fbd23b43498a2120609cd6c3496920bffa3500ef..192dbf585aada246cfb17f0dd7fe484f5ed69430 100644 (file)
 #define DL_LASER_ENABLED       1
 
 /* values for 'click_delay_value' in ClickElement() */
-#define CLICK_DELAY_SHORT      125
-#define CLICK_DELAY_LONG       250
-#define AUTO_ROTATE_DELAY      CLICK_DELAY_SHORT
+#define CLICK_DELAY_FIRST      12      /* delay (frames) after first click */
+#define CLICK_DELAY            6       /* delay (frames) for pressed butten */
+
+#define AUTO_ROTATE_DELAY      CLICK_DELAY
+#define INIT_GAME_ACTIONS_DELAY        (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
+#define NUM_INIT_CYCLE_STEPS   16
+#define PACMAN_MOVE_DELAY      12
+#define ENERGY_DELAY           (4 * ONE_SECOND_DELAY / GAME_FRAME_DELAY)
+#define HEALTH_DEC_DELAY       3
+#define HEALTH_INC_DELAY       9
+#define HEALTH_DELAY(x)                ((x) ? HEALTH_DEC_DELAY : HEALTH_INC_DELAY)
 
 /* forward declaration for internal use */
 static int MovingOrBlocked2Element_MM(int, int);
@@ -215,41 +223,28 @@ static void InitField(int x, int y, boolean init_game)
   }
 }
 
-static void InitCycleElements()
+static void InitCycleElements_RotateSingleStep()
 {
-  int i, j;
+  int i;
 
   if (game_mm.num_cycle == 0)  /* no elements to cycle */
     return;
 
-  for (i = 0; i < 16; i++)
+  for (i = 0; i < game_mm.num_cycle; i++)
   {
-    for (j = 0; j < game_mm.num_cycle; j++)
-    {
-      int x = game_mm.cycle[j].x;
-      int y = game_mm.cycle[j].y;
-      int step = SIGN(game_mm.cycle[j].steps);
-      int last_element = Feld[x][y];
-      int next_element = get_rotated_element(last_element, step);
-
-      if (!game_mm.cycle[j].steps)
-       continue;
-
-      Feld[x][y] = next_element;
-
-      DrawField_MM(x, y);
-      game_mm.cycle[j].steps -= step;
-    }
-
-    BackToFront();
-    ColorCycling();
+    int x = game_mm.cycle[i].x;
+    int y = game_mm.cycle[i].y;
+    int step = SIGN(game_mm.cycle[i].steps);
+    int last_element = Feld[x][y];
+    int next_element = get_rotated_element(last_element, step);
 
-#ifdef DEBUG
-    if (setup.quick_doors)
+    if (!game_mm.cycle[i].steps)
       continue;
-#endif
 
-    Delay(AUTO_ROTATE_DELAY);
+    Feld[x][y] = next_element;
+
+    DrawField_MM(x, y);
+    game_mm.cycle[i].steps -= step;
   }
 }
 
@@ -292,15 +287,12 @@ void InitGameEngine_MM()
 {
   int i, x, y;
 
-  /* set global editor control values */
-  editor.draw_walls_masked = FALSE;
-
   /* set global game control values */
   game_mm.num_cycle = 0;
   game_mm.num_pacman = 0;
 
   game_mm.score = 0;
-  game_mm.energy_left = native_mm_level.time;
+  game_mm.energy_left = 0;     // later set to "native_mm_level.time"
   game_mm.kettles_still_needed =
     (native_mm_level.auto_count_kettles ? 0 : native_mm_level.kettles_needed);
   game_mm.lights_still_needed = 0;
@@ -310,6 +302,8 @@ void InitGameEngine_MM()
   game_mm.game_over = FALSE;
   game_mm.game_over_cause = 0;
 
+  game_mm.laser_overload_value = 0;
+
   /* set global laser control values (must be set before "InitLaser()") */
   laser.start_edge.x = 0;
   laser.start_edge.y = 0;
@@ -351,9 +345,12 @@ void InitGameEngine_MM()
   DrawLevel_MM();
 }
 
-void InitGameEngine_MM_AfterFadingIn()
+void InitGameActions_MM()
 {
-  InitCycleElements();
+  int num_init_game_frames = INIT_GAME_ACTIONS_DELAY;
+  int cycle_steps_done = 0;
+  int i;
+
   InitLaser();
 
 #if 0
@@ -386,24 +383,26 @@ void InitGameEngine_MM_AfterFadingIn()
   OpenDoor(DOOR_OPEN_ALL);
 #endif
 
-  if (setup.sound_loops)
-    PlaySoundExt(SND_FUEL, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT, SND_CTRL_PLAY_LOOP);
-
-#if 0 // !!! TEMPORARILY DISABLED !!!
-  for (i = 0; i <= game_mm.energy_left; i += 2)
+  for (i = 0; i <= num_init_game_frames; i++)
   {
-    if (!setup.sound_loops)
-      PlaySoundStereo(SND_FUEL, SOUND_MAX_RIGHT);
+    if (i == num_init_game_frames)
+      StopSound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+    else if (setup.sound_loops)
+      PlaySoundLoop_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+    else
+      PlaySound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
 
-#if 0
-    BlitBitmap(pix[PIX_DOOR], drawto,
-              DOOR_GFX_PAGEX4 + XX_ENERGY,
-              DOOR_GFX_PAGEY1 + YY_ENERGY + ENERGY_YSIZE - i,
-              ENERGY_XSIZE, i,
-              DX_ENERGY, DY_ENERGY + ENERGY_YSIZE - i);
-#endif
+    game_mm.energy_left = native_mm_level.time * i / num_init_game_frames;
+
+    UpdateAndDisplayGameControlValues();
+
+    while (cycle_steps_done < NUM_INIT_CYCLE_STEPS * i / num_init_game_frames)
+    {
+      InitCycleElements_RotateSingleStep();
+
+      cycle_steps_done++;
+    }
 
-    redraw_mask |= REDRAW_DOOR_1;
     BackToFront();
 
     ColorCycling();
@@ -412,14 +411,8 @@ void InitGameEngine_MM_AfterFadingIn()
     if (setup.quick_doors)
       continue;
 #endif
-
-    Delay(20);
   }
 
-  if (setup.sound_loops)
-    StopSound(SND_FUEL);
-#endif
-
 #if 0
   if (setup.sound_music && num_bg_loops)
     PlayMusic(level_nr % num_bg_loops);
@@ -1087,7 +1080,7 @@ boolean HitElement(int element, int hit_mask)
       ((element - EL_POLAR_START) % 2 ||
        (element - EL_POLAR_START) / 2 != laser.current_angle % 8))
   {
-    PlaySoundStereo(SND_KINK, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     laser.num_damages--;
 
@@ -1097,7 +1090,7 @@ boolean HitElement(int element, int hit_mask)
   if (IS_POLAR_CROSS(element) &&
       (element - EL_POLAR_CROSS_START) != laser.current_angle % 4)
   {
-    PlaySoundStereo(SND_KINK, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     laser.num_damages--;
 
@@ -1175,7 +1168,7 @@ boolean HitElement(int element, int hit_mask)
 
     if ((!IS_POLAR(element) && !IS_POLAR_CROSS(element)) &&
        current_angle != laser.current_angle)
-      PlaySoundStereo(SND_LASER, ST(ELX));
+      PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     laser.overloaded =
       (get_opposite_angle(laser.current_angle) ==
@@ -1193,7 +1186,7 @@ boolean HitElement(int element, int hit_mask)
 
   if (element == EL_BOMB || element == EL_MINE)
   {
-    PlaySoundStereo(SND_KINK, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     if (element == EL_MINE)
       laser.overloaded = TRUE;
@@ -1221,6 +1214,7 @@ boolean HitElement(int element, int hit_mask)
 
       if (game_mm.kettles_still_needed == 0)
       {
+       int exit_element = (element == EL_KETTLE ? EL_EXIT_OPEN : EL_RECEIVER);
        int x, y;
        static int xy[4][2] =
        {
@@ -1230,7 +1224,7 @@ boolean HitElement(int element, int hit_mask)
          {  0, +1 }
        };
 
-        PlaySoundStereo(SND_KLING, ST(ELX));
+       PlayLevelSound_MM(ELX, ELY, exit_element, MM_ACTION_OPENING);
 
        for (y = 0; y < lev_fieldy; y++)
        {
@@ -1281,7 +1275,7 @@ boolean HitElement(int element, int hit_mask)
 
   if (element == EL_LIGHTBULB_OFF || element == EL_LIGHTBULB_ON)
   {
-    PlaySoundStereo(SND_KINK, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     DrawLaser(0, DL_LASER_ENABLED);
 
@@ -1638,13 +1632,14 @@ boolean HitBlock(int element, int hit_mask)
 
 boolean HitLaserSource(int element, int hit_mask)
 {
-   if (HitOnlyAnEdge(element, hit_mask))
-     return FALSE;
+  if (HitOnlyAnEdge(element, hit_mask))
+    return FALSE;
+
+  PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
-   PlaySoundStereo(SND_AUTSCH, ST(ELX));
-   laser.overloaded = TRUE;
+  laser.overloaded = TRUE;
 
-   return TRUE;
+  return TRUE;
 }
 
 boolean HitLaserDestination(int element, int hit_mask)
@@ -1657,7 +1652,8 @@ boolean HitLaserDestination(int element, int hit_mask)
        game_mm.kettles_still_needed == 0 &&
        laser.current_angle == get_opposite_angle(get_element_angle(element))))
   {
-    PlaySoundStereo(SND_HOLZ, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
+
     return TRUE;
   }
 
@@ -1696,7 +1692,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
                                            hit_mask == HIT_MASK_RIGHT ||
                                            hit_mask == HIT_MASK_BOTTOM))
   {
-    PlaySoundStereo(SND_HUI, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     LX -= XS;
     LY -= YS;
@@ -1795,7 +1791,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
        (hit_mask == HIT_MASK_TOPRIGHT || hit_mask == HIT_MASK_BOTTOMLEFT ?
         ANG_MIRROR_135 : ANG_MIRROR_45);
 
-      PlaySoundStereo(SND_HUI, ST(ELX));
+      PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
       AddDamagedField(ELX, ELY);
       AddLaserEdge(LX, LY);
@@ -1831,7 +1827,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
         hit_mask == (HIT_MASK_ALL ^ HIT_MASK_TOPRIGHT) ?
         ANG_MIRROR_135 : ANG_MIRROR_45);
 
-      PlaySoundStereo(SND_HUI, ST(ELX));
+      PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
       /*
       AddDamagedField(ELX, ELY);
@@ -1924,7 +1920,7 @@ boolean HitAbsorbingWalls(int element, int hit_mask)
       element == EL_BLOCK_WOOD ||
       element == EL_GATE_WOOD)
   {
-    PlaySoundStereo(SND_HOLZ, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
     return TRUE;
   }
@@ -2277,13 +2273,13 @@ static void Bang_MM(int x, int y)
   }
 
   if (IS_PACMAN(element))
-    PlaySoundStereo(SND_QUIEK, ST(x));
+    PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
   else if (element == EL_BOMB || IS_MCDUFFIN(element))
-    PlaySoundStereo(SND_ROAAAR, ST(x));
+    PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
   else if (element == EL_KEY)
-    PlaySoundStereo(SND_KLING, ST(x));
+    PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
   else
-    PlaySoundStereo((mode == EX_SHORT ? SND_WHOOSH : SND_KABUMM), ST(x));
+    PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
 
   Explode_MM(x, y, EX_PHASE_START, mode);
 }
@@ -2440,13 +2436,12 @@ static void ContinueMoving_MM(int x, int y)
   laser.redraw = TRUE;
 }
 
-void ClickElement(int mx, int my, int button)
+void ClickElement(int x, int y, int button)
 {
   static unsigned int click_delay = 0;
-  static int click_delay_value = CLICK_DELAY_SHORT;
+  static int click_delay_value = CLICK_DELAY;
   static boolean new_button = TRUE;
   int element;
-  int x = (mx - SX) / TILEX, y = (my - SY) / TILEY;
 
   /* do not rotate objects hit by the laser after the game was solved */
   if (game_mm.level_solved && Hit[x][y])
@@ -2455,7 +2450,7 @@ void ClickElement(int mx, int my, int button)
   if (button == MB_RELEASED)
   {
     new_button = TRUE;
-    click_delay_value = CLICK_DELAY_SHORT;
+    click_delay_value = CLICK_DELAY;
 
     /* release eventually hold auto-rotating mirror */
     RotateMirror(x, y, MB_RELEASED);
@@ -2463,13 +2458,13 @@ void ClickElement(int mx, int my, int button)
     return;
   }
 
-  if (!DelayReached(&click_delay, click_delay_value) && !new_button)
+  if (!FrameReached(&click_delay, click_delay_value) && !new_button)
     return;
 
   if (button == MB_MIDDLEBUTTON)       /* middle button has no function */
     return;
 
-  if (!IN_PIX_FIELD(mx - SX, my - SY))
+  if (!IN_LEV_FIELD(x, y))
     return;
 
   if (Feld[x][y] == EL_EMPTY)
@@ -2540,7 +2535,7 @@ void ClickElement(int mx, int my, int button)
     DrawLaser(0, DL_LASER_ENABLED);
   }
 
-  click_delay_value = (new_button ? CLICK_DELAY_LONG : CLICK_DELAY_SHORT);
+  click_delay_value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
   new_button = FALSE;
 }
 
@@ -2646,7 +2641,7 @@ void AutoRotateMirrors()
   static unsigned int rotate_delay = 0;
   int x, y;
 
-  if (!DelayReached(&rotate_delay, AUTO_ROTATE_DELAY))
+  if (!FrameReached(&rotate_delay, AUTO_ROTATE_DELAY))
     return;
 
   for (x = 0; x < lev_fieldx; x++)
@@ -2772,9 +2767,8 @@ void ColorCycling(void)
   }
 }
 
-static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
+static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 {
-  static unsigned int action_delay = 0;
   static unsigned int pacman_delay = 0;
   static unsigned int energy_delay = 0;
   static unsigned int overload_delay = 0;
@@ -2783,8 +2777,6 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
 
   int r, d;
 
-  WaitUntilDelayReached(&action_delay, GameFrameDelay);
-
   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
     Stop[x][y] = FALSE;
 
@@ -2821,7 +2813,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
 
   CT = Counter();
 
-  if (game_mm.num_pacman && DelayReached(&pacman_delay, 250))
+  if (game_mm.num_pacman && FrameReached(&pacman_delay, PACMAN_MOVE_DELAY))
   {
     MovePacMen();
 
@@ -2832,7 +2824,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
     }
   }
 
-  if (DelayReached(&energy_delay, 4000))
+  if (FrameReached(&energy_delay, ENERGY_DELAY))
   {
     game_mm.energy_left--;
     if (game_mm.energy_left >= 0)
@@ -2864,7 +2856,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
        Delay(50);
       }
 
-      StopSound(SND_WARNTON);
+      StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
       FadeMusic();
 
       DrawLaser(0, DL_LASER_DISABLED);
@@ -2912,7 +2904,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
 
   if (((laser.overloaded && laser.overload_value < MAX_LASER_OVERLOAD) ||
        (!laser.overloaded && laser.overload_value > 0)) &&
-      DelayReached(&overload_delay, 60 + !laser.overloaded * 120))
+      FrameReached(&overload_delay, HEALTH_DELAY(laser.overloaded)))
   {
     if (laser.overloaded)
       laser.overload_value++;
@@ -2925,6 +2917,8 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
       laser.overload_value = 0;
     }
 
+    game_mm.laser_overload_value = laser.overload_value;
+
     if (laser.overload_value < MAX_LASER_OVERLOAD - 8)
     {
       int color_up = 0xFF * laser.overload_value / MAX_LASER_OVERLOAD;
@@ -2941,20 +2935,17 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
                        (native_mm_level.laser_blue  ? color_down : 0x00));
 
       DrawLaser(0, DL_LASER_ENABLED);
+#if 0
       BackToFront();
-    }
-
-    if (laser.overloaded)
-    {
-      if (setup.sound_loops)
-       PlaySoundExt(SND_WARNTON, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
-                    SND_CTRL_PLAY_LOOP);
-      else
-       PlaySoundStereo(SND_WARNTON, SOUND_MAX_RIGHT);
+#endif
     }
 
     if (!laser.overloaded)
-      StopSound(SND_WARNTON);
+      StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
+    else if (setup.sound_loops)
+      PlaySoundLoop_MM(SND_MM_GAME_HEALTH_CHARGING);
+    else
+      PlaySound_MM(SND_MM_GAME_HEALTH_CHARGING);
 
     if (laser.overloaded)
     {
@@ -3193,7 +3184,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
 
   if (IS_WALL_ICE(element) && CT > 1000)
   {
-    PlaySoundStereo(SND_SLURP, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_SHRINKING);
 
     {
       Feld[ELX][ELY] = Feld[ELX][ELY] - EL_WALL_ICE + EL_WALL_CHANGING;
@@ -3331,7 +3322,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
       ScanLaser();
       DrawLaser(0, DL_LASER_ENABLED);
 
-      PlaySoundStereo(SND_AMOEBE, ST(dx));
+      PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
 
       Feld[x][y] = Feld[x][y] - EL_WALL_AMOEBA + EL_WALL_CHANGING;
       Store[x][y] = EL_WALL_AMOEBA;
@@ -3345,7 +3336,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
     ScanLaser();
     DrawLaser(0, DL_LASER_ENABLED);
 
-    PlaySoundStereo(SND_AMOEBE, ST(dx));
+    PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
 
     for (i = 4; i >= 0; i--)
     {
@@ -3399,7 +3390,7 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
       return;
     }
 
-    PlaySoundStereo(SND_BONG, ST(ELX));
+    PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_PUSHING);
 
     Feld[ELX][ELY] = 0;
     Feld[x][y] = element;
@@ -3448,10 +3439,9 @@ static void GameActions_MM_Ext(byte action[MAX_PLAYERS], boolean warp_mode)
   return;
 }
 
-void GameActions_MM(byte action[MAX_PLAYERS], boolean warp_mode)
+void GameActions_MM(struct MouseActionInfo action, boolean warp_mode)
 {
-  if (!button_status)
-    ClickElement(0, 0, MB_NOT_PRESSED);
+  ClickElement(action.lx, action.ly, action.button);
 
   GameActions_MM_Ext(action, warp_mode);
 }