added description files for Mirror Magic (and Deflektor) game elements
[rocksndiamonds.git] / src / game.c
index 8ef02b4f830bf00a40337b6e32a91a3636a37905..13f264e8614f3c3a9cde745e95c2de62096dae69 100644 (file)
@@ -1052,6 +1052,7 @@ static void PlayLevelSoundElementActionIfLoop(int, int, int, int);
 static void PlayLevelSoundActionIfLoop(int, int, int);
 static void StopLevelSoundActionIfLoop(int, int, int);
 static void PlayLevelMusic();
+static void FadeLevelSoundsAndMusic();
 
 static void HandleGameButtons(struct GadgetInfo *);
 
@@ -2701,6 +2702,9 @@ static void InitGameEngine()
   game_em.use_single_button =
     (game.engine_version > VERSION_IDENT(4,0,0,2));
 
+  game_em.use_snap_key_bug =
+    (game.engine_version < VERSION_IDENT(4,0,1,0));
+
   /* ---------------------------------------------------------------------- */
 
   /* set maximal allowed number of custom element changes per game frame */
@@ -3056,6 +3060,11 @@ static void InitGameEngine()
      strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_COLLECT) ?
      SNAPSHOT_MODE_EVERY_COLLECT : SNAPSHOT_MODE_OFF);
   game.snapshot.save_snapshot = FALSE;
+
+  /* ---------- initialize level time for Supaplex engine ------------------- */
+  /* Supaplex levels with time limit currently unsupported -- should be added */
+  if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+    level.time = 0;
 }
 
 int get_num_special_action(int element, int action_first, int action_last)
@@ -3118,7 +3127,7 @@ void InitGame()
   if (CheckIfGlobalBorderHasChanged())
     fade_mask = REDRAW_ALL;
 
-  FadeSoundsAndMusic();
+  FadeLevelSoundsAndMusic();
 
   ExpireSoundLoops(TRUE);
 
@@ -3224,6 +3233,8 @@ void InitGame()
     player->was_snapping = FALSE;
     player->was_dropping = FALSE;
 
+    player->force_dropping = FALSE;
+
     player->frame_counter_bored = -1;
     player->frame_counter_sleeping = -1;
 
@@ -4593,6 +4604,10 @@ void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
 
 static void ResetGfxFrame(int x, int y)
 {
+  // profiling showed that "autotest" spends 10~20% of its time in this function
+  if (DrawingDeactivatedField())
+    return;
+
   int element = Feld[x][y];
   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
 
@@ -10714,7 +10729,9 @@ static void CheckSingleStepMode(struct PlayerInfo *player)
   {
     /* as it is called "single step mode", just return to pause mode when the
        player stopped moving after one tile (or never starts moving at all) */
-    if (!player->is_moving && !player->is_pushing)
+    if (!player->is_moving &&
+       !player->is_pushing &&
+       !player->is_dropping_pressed)
     {
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
       SnapField(player, 0, 0);                 /* stop snapping */
@@ -11208,7 +11225,7 @@ void GameActionsExt()
 
   AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
 
-  if (options.debug)                   /* calculate frames per second */
+  if (global.show_frames_per_second)
   {
     static unsigned int fps_counter = 0;
     static int fps_frames = 0;
@@ -11216,15 +11233,20 @@ void GameActionsExt()
 
     fps_frames++;
 
-    if (fps_delay_ms >= 500)   /* calculate fps every 0.5 seconds */
+    if (fps_delay_ms >= 500)   /* calculate FPS every 0.5 seconds */
     {
       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
 
       fps_frames = 0;
       fps_counter = Counter();
+
+      /* always draw FPS to screen after FPS value was updated */
+      redraw_mask |= REDRAW_FPS;
     }
 
-    redraw_mask |= REDRAW_FPS;
+    /* only draw FPS if no screen areas are deactivated (invisible warp mode) */
+    if (GetDrawDeactivationMask() == REDRAW_NONE)
+      redraw_mask |= REDRAW_FPS;
   }
 }
 
@@ -11268,6 +11290,14 @@ void GameActions_SP_Main()
     effective_action[i] = stored_player[i].effective_action;
 
   GameActions_SP(effective_action, warp_mode);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (stored_player[i].force_dropping)
+      stored_player[i].action |= KEY_BUTTON_DROP;
+
+    stored_player[i].force_dropping = FALSE;
+  }
 }
 
 void GameActions_RND_Main()
@@ -13979,8 +14009,6 @@ static boolean DropElement(struct PlayerInfo *player)
   int drop_side = drop_direction;
   int drop_element = get_next_dropped_element(player);
 
-  player->is_dropping_pressed = TRUE;
-
   /* do not drop an element on top of another element; when holding drop key
      pressed without moving, dropped element must move away before the next
      element can be dropped (this is especially important if the next element
@@ -14008,6 +14036,9 @@ static boolean DropElement(struct PlayerInfo *player)
   if (new_element == EL_UNDEFINED)
     return FALSE;
 
+  /* only set if player has anything that can be dropped */
+  player->is_dropping_pressed = TRUE;
+
   /* check if drop key was pressed long enough for EM style dynamite */
   if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40)
     return FALSE;
@@ -14214,12 +14245,43 @@ static void StopLevelSoundActionIfLoop(int x, int y, int action)
     StopSound(sound_effect);
 }
 
-static void PlayLevelMusic()
+static int getLevelMusicNr()
 {
   if (levelset.music[level_nr] != MUS_UNDEFINED)
-    PlayMusic(levelset.music[level_nr]);       /* from config file */
+    return levelset.music[level_nr];           /* from config file */
   else
-    PlayMusic(MAP_NOCONF_MUSIC(level_nr));     /* from music dir */
+    return MAP_NOCONF_MUSIC(level_nr);         /* from music dir */
+}
+
+static void FadeLevelSounds()
+{
+  FadeSounds();
+}
+
+static void FadeLevelMusic()
+{
+  int music_nr = getLevelMusicNr();
+  char *curr_music = getCurrentlyPlayingMusicFilename();
+  char *next_music = getMusicInfoEntryFilename(music_nr);
+
+  if (!strEqual(curr_music, next_music))
+    FadeMusic();
+}
+
+void FadeLevelSoundsAndMusic()
+{
+  FadeLevelSounds();
+  FadeLevelMusic();
+}
+
+static void PlayLevelMusic()
+{
+  int music_nr = getLevelMusicNr();
+  char *curr_music = getCurrentlyPlayingMusicFilename();
+  char *next_music = getMusicInfoEntryFilename(music_nr);
+
+  if (!strEqual(curr_music, next_music))
+    PlayMusic(music_nr);
 }
 
 void PlayLevelSound_EM(int xx, int yy, int element_em, int sample)