rnd-20100309-1-src
[rocksndiamonds.git] / src / tape.c
index d3fdd45729a3bbd03f34a80020b7b281ffe965d2..88f0f5a0300e4e0799ff9abf40cda0e138d3fd51 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-* (c) 1995-2002 Artsoft Entertainment                      *
+* (c) 1995-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
@@ -345,102 +345,6 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     },
   };
 
-#if 0
-  if (state & VIDEO_STATE_FFWD_OFF)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_LABEL_XPOS,
-                cy + VIDEO_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX3;
-    cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_FFWD_SYMBOL_XSIZE,
-                VIDEO_FFWD_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              cy + VIDEO_PLAY_SYMBOL_YPOS,
-              VIDEO_PLAY_SYMBOL_XSIZE - 2,
-              VIDEO_PLAY_SYMBOL_YSIZE,
-              VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              VY + VIDEO_PLAY_SYMBOL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_PBEND_OFF)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_LABEL_XPOS,
-                cy + VIDEO_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX3;
-    cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_PBEND_SYMBOL_XSIZE,
-                VIDEO_PBEND_SYMBOL_YSIZE,
-                VX + VIDEO_PBEND_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_REC_LABEL_XPOS,
-              cy + VIDEO_REC_LABEL_YPOS,
-              VIDEO_PBEND_LABEL_XSIZE,
-              VIDEO_PBEND_LABEL_YSIZE,
-              VX + VIDEO_REC_LABEL_XPOS,
-              VY + VIDEO_REC_LABEL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_1STEP_OFF)
-  {
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_1STEP_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_1STEP_SYMBOL_XSIZE,
-                VIDEO_1STEP_SYMBOL_YSIZE,
-                VX + VIDEO_1STEP_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-  }
-#endif
-
   for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++)       /* on or off states */
   {
     for (i = 0; i < NUM_TAPE_FUNCTIONS; i++)           /* record, play, ... */
@@ -476,102 +380,6 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     }
   }
 
-#if 0
-  if (state & VIDEO_STATE_FFWD_ON)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_LABEL_XPOS,
-                cy + VIDEO_FFWD_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX6;
-    cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_SYMBOL_XPOS,
-                cy + VIDEO_FFWD_SYMBOL_YPOS,
-                VIDEO_FFWD_SYMBOL_XSIZE,
-                VIDEO_FFWD_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PLAY_SYMBOL_XPOS,
-              cy + VIDEO_PLAY_SYMBOL_YPOS,
-              VIDEO_PLAY_SYMBOL_XSIZE - 2,
-              VIDEO_PLAY_SYMBOL_YSIZE,
-              VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              VY + VIDEO_PLAY_SYMBOL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_PBEND_ON)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_LABEL_XPOS,
-                cy + VIDEO_PBEND_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX6;
-    cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_SYMBOL_XPOS,
-                cy + VIDEO_PBEND_SYMBOL_YPOS,
-                VIDEO_PBEND_SYMBOL_XSIZE,
-                VIDEO_PBEND_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PBEND_LABEL_XPOS,
-              cy + VIDEO_PBEND_LABEL_YPOS,
-              VIDEO_PBEND_LABEL_XSIZE,
-              VIDEO_PBEND_LABEL_YSIZE,
-              VX + VIDEO_REC_LABEL_XPOS,
-              VY + VIDEO_REC_LABEL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_1STEP_ON)
-  {
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_1STEP_SYMBOL_XPOS,
-                cy + VIDEO_1STEP_SYMBOL_YPOS,
-                VIDEO_1STEP_SYMBOL_XSIZE,
-                VIDEO_1STEP_SYMBOL_YSIZE,
-                VX + VIDEO_1STEP_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-  }
-#endif
-
   if (state & VIDEO_STATE_DATE_ON)
   {
     int tag = value % 100;
@@ -597,16 +405,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
             int2str(sec, 2), FONT_TAPE_RECORDER);
   }
 
-#if 1
   redraw_mask |= REDRAW_DOOR_2;
-#else
-  if (state & VIDEO_STATE_DATE)
-    redraw_mask |= REDRAW_VIDEO_1;
-  if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
-    redraw_mask |= REDRAW_VIDEO_2;
-  if (state & VIDEO_PRESS)
-    redraw_mask |= REDRAW_VIDEO_3;
-#endif
 }
 
 void DrawCompleteVideoDisplay()
@@ -654,12 +453,16 @@ void TapeDeactivateDisplayOff(boolean redraw_display)
 /* tape control functions                                                    */
 /* ========================================================================= */
 
-static void TapeSetDate()
+void TapeSetDateFromEpochSeconds(time_t epoch_seconds)
 {
-  time_t epoch_seconds = time(NULL);
-  struct tm *now = localtime(&epoch_seconds);
+  struct tm *lt = localtime(&epoch_seconds);
 
-  tape.date = 10000 * (now->tm_year % 100) + 100 * now->tm_mon + now->tm_mday;
+  tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday;
+}
+
+void TapeSetDateFromNow()
+{
+  TapeSetDateFromEpochSeconds(time(NULL));
 }
 
 void TapeErase()
@@ -676,21 +479,19 @@ void TapeErase()
   tape.pos[tape.counter].delay = 0;
   tape.changed = TRUE;
 
-  tape.random_seed = InitRND(NEW_RANDOMIZE);
+  tape.random_seed = InitRND(level.random_seed);
 
   tape.file_version = FILE_VERSION_ACTUAL;
   tape.game_version = GAME_VERSION_ACTUAL;
   tape.engine_version = level.game_version;
 
-  TapeSetDate();
-
-#if 0
-  printf("::: tape.engine_version = level.game_version = %d \n",
-        level.game_version);
-#endif
+  TapeSetDateFromNow();
 
   for (i = 0; i < MAX_PLAYERS; i++)
     tape.player_participates[i] = FALSE;
+
+  tape.centered_player_nr_next = -1;
+  tape.set_centered_player = FALSE;
 }
 
 static void TapeRewind()
@@ -708,16 +509,25 @@ static void TapeRewind()
   tape.quick_resume = FALSE;
   tape.single_step = FALSE;
 
+  tape.centered_player_nr_next = -1;
+  tape.set_centered_player = FALSE;
+
   InitRND(tape.random_seed);
 }
 
-void TapeStartRecording()
+static void TapeSetRandomSeed(long random_seed)
+{
+  tape.random_seed = InitRND(random_seed);
+}
+
+void TapeStartRecording(long random_seed)
 {
   if (!TAPE_IS_STOPPED(tape))
     TapeStop();
 
   TapeErase();
   TapeRewind();
+  TapeSetRandomSeed(random_seed);
 
   tape.recording = TRUE;
 
@@ -732,18 +542,18 @@ void TapeStartRecording()
 
 static void TapeStartGameRecording()
 {
-  TapeStartRecording();
+  TapeStartRecording(level.random_seed);
 
 #if defined(NETWORK_AVALIABLE)
   if (options.network)
-    SendToServer_StartPlaying();
-  else
-#endif
   {
-    game_status = GAME_MODE_PLAYING;
-    StopAnimation();
-    InitGame();
+    SendToServer_StartPlaying();
+
+    return;
   }
+#endif
+
+  InitGame();
 }
 
 static void TapeAppendRecording()
@@ -756,10 +566,14 @@ static void TapeAppendRecording()
   tape.recording = TRUE;
   tape.changed = TRUE;
 
-  TapeSetDate();
+  TapeSetDateFromNow();
 
   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0);
+
+#if 1
+  UpdateAndDisplayGameControlValues();
+#endif
 }
 
 void TapeHaltRecording()
@@ -776,9 +590,6 @@ void TapeHaltRecording()
 
 void TapeStopRecording()
 {
-  if (!tape.recording)
-    return;
-
   TapeHaltRecording();
 
   tape.recording = FALSE;
@@ -788,27 +599,32 @@ void TapeStopRecording()
   MapTapeEjectButton();
 }
 
-void TapeRecordAction(byte action[MAX_PLAYERS])
+void TapeRecordAction(byte action_raw[MAX_PLAYERS])
 {
+  byte action[MAX_PLAYERS];
   int i;
 
-#if 1
-  if (!tape.recording)         /* record action even when tape is paused! */
-    return;
-#else
-  if (!tape.recording || tape.pausing)
+  if (!tape.recording)         /* (record action even when tape is paused) */
     return;
-#endif
 
-  if (tape.counter >= MAX_TAPELEN - 1)
+  if (tape.counter >= MAX_TAPE_LEN - 1)
   {
     TapeStopRecording();
     return;
   }
 
-#if 0
-  printf("::: %05d: recording action: %d\n", FrameCounter, action[0]);
-#endif
+  for (i = 0; i < MAX_PLAYERS; i++)
+    action[i] = action_raw[i];
+
+  if (tape.set_centered_player)
+  {
+    for (i = 0; i < MAX_PLAYERS; i++)
+      if (tape.centered_player_nr_next == i ||
+         tape.centered_player_nr_next == -1)
+       action[i] |= KEY_SET_FOCUS;
+
+    tape.set_centered_player = FALSE;
+  }
 
   if (tape.pos[tape.counter].delay > 0)                /* already stored action */
   {
@@ -829,11 +645,6 @@ void TapeRecordAction(byte action[MAX_PLAYERS])
 
   if (tape.pos[tape.counter].delay == 0)       /* store new action */
   {
-
-#if 0
-    printf("::: %05d: new sequence\n", FrameCounter);
-#endif
-
     for (i = 0; i < MAX_PLAYERS; i++)
       tape.pos[tape.counter].action[i] = action[i];
 
@@ -845,11 +656,6 @@ void TapeTogglePause(boolean toggle_manual)
 {
   int state = 0;
 
-#if 0
-  if (!tape.recording && !tape.playing)
-    return;
-#endif
-
   if (tape.pause_before_death)
     state |= VIDEO_STATE_PBEND_OFF;
   else if (tape.fast_forward)
@@ -870,11 +676,6 @@ void TapeTogglePause(boolean toggle_manual)
 
   DrawVideoDisplay(state, 0);
 
-#if 0
-  if (tape.pausing)
-    DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
-#endif
-
   if (tape.warp_forward)
   {
     TapeStopWarpForward();
@@ -884,9 +685,9 @@ void TapeTogglePause(boolean toggle_manual)
       tape.quick_resume = FALSE;
 
       TapeAppendRecording();
-#if 0
-      TapeTogglePause(toggle_manual);
-#endif
+
+      if (!CheckEngineSnapshot())
+       SaveEngineSnapshot();
     }
   }
 }
@@ -916,16 +717,11 @@ static void TapeStartGamePlaying()
 {
   TapeStartPlaying();
 
-  game_status = GAME_MODE_PLAYING;
-  StopAnimation();
   InitGame();
 }
 
 void TapeStopPlaying()
 {
-  if (!tape.playing)
-    return;
-
   tape.playing = FALSE;
   tape.pausing = FALSE;
 
@@ -944,7 +740,7 @@ byte *TapePlayAction()
   if (!tape.playing || tape.pausing)
     return NULL;
 
-  if (tape.pause_before_death) /* STOP 10s BEFORE PLAYER GETS KILLED... */
+  if (tape.pause_before_death) /* stop 10 seconds before player gets killed */
   {
     if (!(FrameCounter % 20))
     {
@@ -962,9 +758,10 @@ byte *TapePlayAction()
        DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
     }
 
-    if (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
+    if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
     {
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
       return NULL;
     }
   }
@@ -983,6 +780,7 @@ byte *TapePlayAction()
        DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
     }
   }
+
 #if 0
   /* !!! this makes things much slower !!! */
   else if (tape.warp_forward)
@@ -1009,6 +807,21 @@ byte *TapePlayAction()
   for (i = 0; i < MAX_PLAYERS; i++)
     action[i] = tape.pos[tape.counter].action[i];
 
+  tape.set_centered_player = FALSE;
+  tape.centered_player_nr_next = -999;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (action[i] & KEY_SET_FOCUS)
+    {
+      tape.set_centered_player = TRUE;
+      tape.centered_player_nr_next =
+       (tape.centered_player_nr_next == -999 ? i : -1);
+    }
+
+    action[i] &= ~KEY_SET_FOCUS;
+  }
+
   tape.delay_played++;
   if (tape.delay_played >= tape.pos[tape.counter].delay)
   {
@@ -1016,22 +829,11 @@ byte *TapePlayAction()
     tape.delay_played = 0;
   }
 
-#if 0
-  printf("::: %05d: replaying action: %d\n", FrameCounter, action[0]);
-#endif
-
   return action;
 }
 
 void TapeStop()
 {
-#if 0
-  if (tape.recording)
-    printf("::: stopped recording: %d\n", FrameCounter);
-  else if (tape.playing)
-    printf("::: stopped playing:   %d\n\n", FrameCounter);
-#endif
-
   TapeStopRecording();
   TapeStopPlaying();
 
@@ -1042,11 +844,6 @@ void TapeStop()
     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
   }
-
-#if 0
-  if (tape.auto_play)
-    AutoPlayTape();    /* continue automatically playing next tape */
-#endif
 }
 
 unsigned int GetTapeLength()
@@ -1067,7 +864,6 @@ static void TapeStartWarpForward()
 {
   tape.warp_forward = TRUE;
 
-#if 1
   if (!tape.fast_forward && !tape.pause_before_death)
   {
     tape.pausing = FALSE;
@@ -1075,15 +871,6 @@ static void TapeStartWarpForward()
 
     TapeDeactivateDisplayOn();
   }
-#else
-  if (!tape.fast_forward || tape.pause_before_death)
-  {
-    tape.pausing = FALSE;
-    tape.deactivate_display = TRUE;
-
-    TapeDeactivateDisplayOn();
-  }
-#endif
 
   if (tape.fast_forward || tape.pause_before_death)
     DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
@@ -1100,16 +887,6 @@ static void TapeStopWarpForward()
 
   TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING);
 
-#if 0
-#if 1
-  if (game_status == GAME_MODE_PLAYING)
-#endif
-  {
-    RedrawPlayfield(TRUE, 0,0,0,0);
-    DrawGameDoorValues();
-  }
-#endif
-
   if (tape.pause_before_death)
     state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON;
   else if (tape.fast_forward)
@@ -1136,48 +913,87 @@ static void TapeSingleStep()
 
 void TapeQuickSave()
 {
-  if (game_status == GAME_MODE_PLAYING)
+  if (game_status == GAME_MODE_MAIN)
   {
-    if (tape.recording)
-      TapeHaltRecording();     /* prepare tape for saving on-the-fly */
+    Request("No game that can be saved !", REQ_CONFIRM);
 
-    if (TAPE_IS_EMPTY(tape))
-      Request("No tape that can be saved !", REQ_CONFIRM);
-    else
-      SaveTape(tape.level_nr);
+    return;
   }
-  else if (game_status == GAME_MODE_MAIN)
-    Request("No game that can be saved !", REQ_CONFIRM);
+
+  if (game_status != GAME_MODE_PLAYING)
+    return;
+
+  if (tape.recording)
+    TapeHaltRecording();       /* prepare tape for saving on-the-fly */
+
+  if (TAPE_IS_EMPTY(tape))
+  {
+    Request("No tape that can be saved !", REQ_CONFIRM);
+
+    return;
+  }
+
+  if (SaveTapeChecked(tape.level_nr))
+    SaveEngineSnapshot();
 }
 
 void TapeQuickLoad()
 {
+  char *filename = getTapeFilename(level_nr);
+
+  if (!fileExists(filename))
+  {
+    Request("No tape for this level !", REQ_CONFIRM);
+
+    return;
+  }
+
   if (tape.recording && !Request("Stop recording and load tape ?",
                                 REQ_ASK | REQ_STAY_CLOSED))
   {
-    BlitBitmap(bitmap_db_door, bitmap_db_door,
-              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
-              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-    OpenDoor(DOOR_OPEN_1);
+    OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
 
     return;
   }
 
-  if (game_status == GAME_MODE_PLAYING || game_status == GAME_MODE_MAIN)
+  if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN)
+    return;
+
+  if (CheckEngineSnapshot())
   {
-    TapeStop();
-    TapeErase();
+    TapeStartGamePlaying();
 
-    LoadTape(level_nr);
-    if (!TAPE_IS_EMPTY(tape))
-    {
-      TapeStartGamePlaying();
-      TapeStartWarpForward();
+    LoadEngineSnapshot();
 
-      tape.quick_resume = TRUE;
-    }
-    else
-      Request("No tape for this level !", REQ_CONFIRM);
+    DrawCompleteVideoDisplay();
+
+    tape.playing = TRUE;
+    tape.pausing = TRUE;
+
+    TapeStopWarpForward();
+    TapeAppendRecording();
+
+    if (FrameCounter > 0)
+      return;
+  }
+
+  TapeStop();
+  TapeErase();
+
+  LoadTape(level_nr);
+
+  if (!TAPE_IS_EMPTY(tape))
+  {
+    TapeStartGamePlaying();
+    TapeStartWarpForward();
+
+    tape.quick_resume = TRUE;
+  }
+  else /* this should not happen (basically checked above) */
+  {
+    int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0);
+
+    Request("No tape for this level !", REQ_CONFIRM | reopen_door);
   }
 }
 
@@ -1199,8 +1015,6 @@ void InsertSolutionTape()
  * tape autoplay functions
  * ------------------------------------------------------------------------- */
 
-#define MAX_NUM_AUTOPLAY_LEVELS                1000
-
 void AutoPlayTape()
 {
   static LevelDirTree *autoplay_leveldir = NULL;
@@ -1208,7 +1022,9 @@ void AutoPlayTape()
   static int autoplay_level_nr = -1;
   static int num_levels_played = 0;
   static int num_levels_solved = 0;
-  static boolean levels_failed[MAX_NUM_AUTOPLAY_LEVELS];
+  static int num_tape_missing = 0;
+  static boolean level_failed[MAX_TAPES_PER_SET];
+  static boolean tape_missing[MAX_TAPES_PER_SET];
   int i;
 
   if (autoplay_initialized)
@@ -1217,10 +1033,11 @@ void AutoPlayTape()
     printf("%s.\n", tape.auto_play_level_solved ? "solved" : "NOT SOLVED");
 
     num_levels_played++;
+
     if (tape.auto_play_level_solved)
       num_levels_solved++;
-    else if (level_nr >= 0 && level_nr < MAX_NUM_AUTOPLAY_LEVELS)
-      levels_failed[level_nr] = TRUE;
+    else if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
+      level_failed[level_nr] = TRUE;
   }
   else
   {
@@ -1236,11 +1053,10 @@ void AutoPlayTape()
 
     leveldir_current = autoplay_leveldir;
 
-    if (global.autoplay_level_nr != -1)
-    {
-      autoplay_leveldir->first_level = global.autoplay_level_nr;
-      autoplay_leveldir->last_level  = global.autoplay_level_nr;
-    }
+    if (autoplay_leveldir->first_level < 0)
+      autoplay_leveldir->first_level = 0;
+    if (autoplay_leveldir->last_level >= MAX_TAPES_PER_SET)
+      autoplay_leveldir->last_level = MAX_TAPES_PER_SET - 1;
 
     autoplay_level_nr = autoplay_leveldir->first_level;
 
@@ -1254,8 +1070,11 @@ void AutoPlayTape()
     printf_line("=", 79);
     printf("\n");
 
-    for (i = 0; i < MAX_NUM_AUTOPLAY_LEVELS; i++)
-      levels_failed[i] = FALSE;
+    for (i = 0; i < MAX_TAPES_PER_SET; i++)
+    {
+      level_failed[i] = FALSE;
+      tape_missing[i] = FALSE;
+    }
 
     autoplay_initialized = TRUE;
   }
@@ -1264,6 +1083,9 @@ void AutoPlayTape()
   {
     level_nr = autoplay_level_nr++;
 
+    if (!global.autoplay_all && !global.autoplay_level[level_nr])
+      continue;
+
     TapeErase();
 
     printf("Level %03d: ", level_nr);
@@ -1275,13 +1097,20 @@ void AutoPlayTape()
       continue;
     }
 
+#if 0
+    /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */
+    printf("(only testing level)\n");
+    continue;
+#endif
+
     LoadSolutionTape(level_nr);
-#if 1
+
     if (tape.no_valid_file)
-#else
-    if (TAPE_IS_EMPTY(tape))
-#endif
     {
+      num_tape_missing++;
+      if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
+       tape_missing[level_nr] = TRUE;
+
       printf("(no tape)\n");
       continue;
     }
@@ -1304,13 +1133,25 @@ void AutoPlayTape()
   printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)",
         autoplay_leveldir->identifier, num_levels_solved, num_levels_played,
         (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
+
   if (num_levels_played != num_levels_solved)
   {
     printf(", FAILED:");
-    for (i = 0; i < MAX_NUM_AUTOPLAY_LEVELS; i++)
-      if (levels_failed[i])
+    for (i = 0; i < MAX_TAPES_PER_SET; i++)
+      if (level_failed[i])
        printf(" %03d", i);
   }
+
+#if 0
+  if (num_tape_missing > 0)
+  {
+    printf(", NO TAPE:");
+    for (i = 0; i < MAX_TAPES_PER_SET; i++)
+      if (tape_missing[i])
+       printf(" %03d", i);
+  }
+#endif
+
   printf("\n");
   printf_line("=", 79);
 
@@ -1406,6 +1247,7 @@ void CreateTapeButtons()
                      GDI_STATE, GD_BUTTON_UNPRESSED,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+                     GDI_DIRECT_DRAW, FALSE,
                      GDI_EVENT_MASK, GD_EVENT_RELEASED,
                      GDI_CALLBACK_ACTION, HandleTapeButtons,
                      GDI_END);
@@ -1468,18 +1310,22 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
   {
     case TAPE_CTRL_ID_EJECT:
       TapeStop();
+
       if (TAPE_IS_EMPTY(tape))
       {
        LoadTape(level_nr);
+
        if (TAPE_IS_EMPTY(tape))
          Request("No tape for this level !", REQ_CONFIRM);
       }
       else
       {
        if (tape.changed)
-         SaveTape(tape.level_nr);
+         SaveTapeChecked(tape.level_nr);
+
        TapeErase();
       }
+
       DrawCompleteVideoDisplay();
       break;
 
@@ -1493,19 +1339,11 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
        else                                    /* WARP FORWARD PLAY -> PLAY */
        {
          TapeStopWarpForward();
-
-#if 0
-         if (tape.pause_before_death)
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON, 0);
-         else if (tape.fast_forward)
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON, 0);
-         else
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON, 0);
-#endif
        }
       }
       else if (tape.recording)
        TapeSingleStep();
+
       break;
 
     case TAPE_CTRL_ID_STOP:
@@ -1550,22 +1388,17 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
        else if (!tape.pause_before_death)      /* FFWD PLAY -> AUTO PAUSE */
        {
          tape.pause_before_death = TRUE;
-#if 1
          DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_ON, 0);
-#else
-         DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
-#endif
        }
        else                                    /* AUTO PAUSE -> NORMAL PLAY */
        {
+         if (tape.warp_forward)
+           TapeStopWarpForward();
+
          tape.fast_forward = FALSE;
          tape.pause_before_death = FALSE;
-         tape.warp_forward = FALSE;
-#if 1
+
          DrawVideoDisplay(VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PLAY_ON, 0);
-#else
-         DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_OFF, 0);
-#endif
        }
       }
       break;