rnd-20060824-1-src
authorHolger Schemel <info@artsoft.org>
Thu, 24 Aug 2006 02:11:51 +0000 (04:11 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:53:07 +0000 (10:53 +0200)
* added engine snapshot functionality for instant tape reloading (this
  only works for the last tape saved using "quick save", and does not
  work across program restarts, because it completely works in memory)

ChangeLog
src/conftime.h
src/game.c
src/game.h
src/game_em/export.h
src/game_em/input.c
src/libgame/misc.c
src/tape.c

index 076bc6df0e77f5e1f9079cda85b358947c8e73d0..ef7d0b250710cfa3b3ab8bd22946b8943afcdff6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2006-08-23
+       * added engine snapshot functionality for instant tape reloading (this
+         only works for the last tape saved using "quick save", and does not
+         work across program restarts, because it completely works in memory)
+
 2006-08-21
        * version number set to 3.2.2
 
index fbe8d62ef5e698d3c064f5bb4e399a2feacd5afe..b906aa53ecd4c24a4957f590d5421893da092236 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2006-08-21 02:09]"
+#define COMPILE_DATE_STRING "[2006-08-24 00:46]"
index fea0d6ce8e1588f28bfc94634545cf5e5a180c74..489c476b30e431b297f420e71a904557873a4662 100644 (file)
@@ -12412,6 +12412,233 @@ void RequestQuitGame(boolean ask_if_really_quit)
 }
 
 
+/* ------------------------------------------------------------------------- */
+/* game engine snapshot handling                                             */
+/* ------------------------------------------------------------------------- */
+
+#define ARGS_ADDRESS_AND_SIZEOF(x)             (&(x)), (sizeof(x))
+
+struct EngineSnapshotInfo
+{
+  int collect_score[NUM_CUSTOM_ELEMENTS];
+  int belt_graphic[4 * NUM_BELT_PARTS];
+  int belt_anim_mode[4 * NUM_BELT_PARTS];
+};
+
+struct EngineSnapshotNodeInfo
+{
+  void *buffer_orig;
+  void *buffer_copy;
+  int size;
+};
+
+static struct EngineSnapshotInfo engine_snapshot_rnd;
+static ListNode *engine_snapshot_list = NULL;
+static char *snapshot_level_identifier = NULL;
+static int snapshot_level_nr = -1;
+
+void FreeEngineSnapshot()
+{
+  while (engine_snapshot_list != NULL)
+    deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key,
+                      checked_free);
+
+  setString(&snapshot_level_identifier, NULL);
+  snapshot_level_nr = -1;
+}
+
+static void SaveEngineSnapshotValues_RND()
+{
+  static int belt_base_active_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_4_LEFT_ACTIVE
+  };
+  int i, j;
+
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    engine_snapshot_rnd.collect_score[i] = element_info[i].collect_score;
+
+  for (i = 0; i < 4; i++)
+  {
+    for (j = 0; j < NUM_BELT_PARTS; j++)
+    {
+      int element = belt_base_active_element[i] + j;
+      int graphic = el2img(element);
+      int anim_mode = graphic_info[graphic].anim_mode;
+
+      engine_snapshot_rnd.belt_graphic[i * 4 + j] = graphic;
+      engine_snapshot_rnd.belt_anim_mode[i * 4 + j] = anim_mode;
+    }
+  }
+}
+
+static void LoadEngineSnapshotValues_RND()
+{
+  int i, j;
+
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    element_info[i].collect_score = engine_snapshot_rnd.collect_score[i];
+
+  for (i = 0; i < 4; i++)
+  {
+    for (j = 0; j < NUM_BELT_PARTS; j++)
+    {
+      int graphic = engine_snapshot_rnd.belt_graphic[i * 4 + j];
+      int anim_mode = engine_snapshot_rnd.belt_anim_mode[i * 4 + j];
+
+      graphic_info[graphic].anim_mode = anim_mode;
+    }
+  }
+}
+
+static void SaveEngineSnapshotBuffer(void *buffer, int size)
+{
+  struct EngineSnapshotNodeInfo *bi =
+    checked_calloc(sizeof(struct EngineSnapshotNodeInfo));
+
+  bi->buffer_orig = buffer;
+  bi->buffer_copy = checked_malloc(size);
+  bi->size = size;
+
+  memcpy(bi->buffer_copy, buffer, size);
+
+  addNodeToList(&engine_snapshot_list, NULL, bi);
+}
+
+void SaveEngineSnapshot()
+{
+  FreeEngineSnapshot();                /* free previous snapshot, if needed */
+
+  /* copy some special values to a structure better suited for the snapshot */
+
+  SaveEngineSnapshotValues_RND();
+  SaveEngineSnapshotValues_EM();
+
+  /* save values stored in special snapshot structure */
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em));
+
+  /* save further RND engine values */
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(stored_player));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(game));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(tape));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZX));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZY));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitX));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitY));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FrameCounter));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeFrames));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimePlayed));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeLeft));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TapeTime));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Feld));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovPos));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDir));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDelay));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeDelay));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangePage));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CustomValue));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store2));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(StorePlayer));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Back));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaNr));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeCount));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeEvent));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodePhase));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeField));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RunnerVisit));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(PlayerVisit));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxRandom));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElement));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxAction));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxDir));
+
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_x));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_y));
+
+  /* save level identification information */
+
+  setString(&snapshot_level_identifier, leveldir_current->identifier);
+  snapshot_level_nr = level_nr;
+
+#if 0
+  ListNode *node = engine_snapshot_list;
+  int num_bytes = 0;
+
+  while (node != NULL)
+  {
+    num_bytes += ((struct EngineSnapshotNodeInfo *)node->content)->size;
+
+    node = node->next;
+  }
+
+  printf("::: size of engine snapshot: %d bytes\n", num_bytes);
+#endif
+}
+
+static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi)
+{
+  memcpy(bi->buffer_orig, bi->buffer_copy, bi->size);
+}
+
+void LoadEngineSnapshot()
+{
+  ListNode *node = engine_snapshot_list;
+
+  if (engine_snapshot_list == NULL)
+    return;
+
+  while (node != NULL)
+  {
+    LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content);
+
+    node = node->next;
+  }
+
+  /* restore special values from snapshot structure */
+
+  LoadEngineSnapshotValues_RND();
+  LoadEngineSnapshotValues_EM();
+}
+
+boolean CheckEngineSnapshot()
+{
+  return (strEqual(snapshot_level_identifier, leveldir_current->identifier) &&
+         snapshot_level_nr == level_nr);
+}
+
+
 /* ---------- new game button stuff ---------------------------------------- */
 
 /* graphic position values for game buttons */
index 57621e88d9d9d9e9db8c0eb3f7092a41bf46db07..a18b624772fa8da437f9b0709a7d27c2a40b8a24 100644 (file)
@@ -199,9 +199,8 @@ struct PlayerInfo
   int inventory_size;
 };
 
-
 extern struct GameInfo         game;
-extern struct PlayerInfo       stored_player[], *local_player;
+extern struct PlayerInfo       stored_player[MAX_PLAYERS], *local_player;
 
 
 #ifdef DEBUG
@@ -240,6 +239,11 @@ void RaiseScore(int);
 void RaiseScoreElement(int);
 void RequestQuitGame(boolean);
 
+void FreeEngineSnapshot();
+void LoadEngineSnapshot();
+void SaveEngineSnapshot();
+boolean CheckEngineSnapshot();
+
 void CreateGameButtons();
 void FreeGameButtons();
 void UnmapGameButtons();
index e7cfae0e67480342295a6ebff9c4ea4f36e3632f..495aa918769d2e393b5639d36c12a80e8e7d4b9d 100644 (file)
@@ -691,6 +691,18 @@ struct GraphicInfo_EM
   int unique_identifier;       /* used to identify needed screen updates */
 };
 
+struct EngineSnapshotInfo_EM
+{
+  struct GameInfo_EM game_em;
+  unsigned long RandomEM;
+  struct LEVEL lev;
+  struct PLAYER ply[MAX_PLAYERS];
+  short Array[4][EM_MAX_CAVE_HEIGHT][EM_MAX_CAVE_WIDTH];
+  int screen_x;
+  int screen_y;
+  int frame;
+};
+
 
 /* ------------------------------------------------------------------------- */
 /* exported functions                                                        */
@@ -700,6 +712,7 @@ extern struct GlobalInfo_EM global_em_info;
 extern struct LevelInfo_EM native_em_level;
 extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
 extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
+extern struct EngineSnapshotInfo_EM engine_snapshot_em;
 
 extern void em_open_all();
 extern void em_close_all();
@@ -717,4 +730,7 @@ extern void BlitScreenToBitmap_EM(Bitmap *);
 extern void RedrawPlayfield_EM(boolean);
 extern void DrawGameDoorValues_EM();
 
+extern void LoadEngineSnapshotValues_EM();
+extern void SaveEngineSnapshotValues_EM();
+
 #endif /* EXPORT_H */
index 0dd2bb3b95f99f1621b0d1c426a09a28c690fcb5..68ba21f09d7d07ee92ed0d8b0c15ce8448d7173a 100644 (file)
@@ -22,6 +22,8 @@ static short Array[4][HEIGHT][WIDTH];
 extern int screen_x;
 extern int screen_y;
 
+struct EngineSnapshotInfo_EM engine_snapshot_em;
+
 void game_init_vars(void)
 {
   int x, y;
@@ -160,3 +162,43 @@ void readjoy(byte action, struct PLAYER *ply)
     ply->joy_w = west;
   }
 }
+
+void SaveEngineSnapshotValues_EM()
+{
+  int i, j, k;
+
+  engine_snapshot_em.RandomEM = RandomEM;
+  engine_snapshot_em.game_em = game_em;
+  engine_snapshot_em.lev = lev;
+  engine_snapshot_em.screen_x = screen_x;
+  engine_snapshot_em.screen_y = screen_y;
+  engine_snapshot_em.frame = frame;
+
+  for (i = 0; i < 4; i++)
+    engine_snapshot_em.ply[i] = ply[i];
+
+  for (i = 0; i < 4; i++)
+    for (j = 0; j < HEIGHT; j++)
+      for (k = 0; k < WIDTH; k++)
+       engine_snapshot_em.Array[i][j][k] = Array[i][j][k];
+
+}
+
+void LoadEngineSnapshotValues_EM()
+{
+  int i, j, k;
+
+  RandomEM = engine_snapshot_em.RandomEM;
+  game_em = engine_snapshot_em.game_em;
+  screen_x = engine_snapshot_em.screen_x;
+  screen_y = engine_snapshot_em.screen_y;
+  frame = engine_snapshot_em.frame;
+
+  for (i = 0; i < 4; i++)
+    ply[i] = engine_snapshot_em.ply[i];
+
+  for (i = 0; i < 4; i++)
+    for (j = 0; j < HEIGHT; j++)
+      for (k = 0; k < WIDTH; k++)
+       Array[i][j][k] = engine_snapshot_em.Array[i][j][k];
+}
index f9ec87fe5b15cf9c1206f7f6b83bade9c302e0df..ae54541fb3639f5da828a511bf4785d2dfbea943 100644 (file)
@@ -1544,7 +1544,7 @@ void deleteNodeFromList(ListNode **node_first, char *key,
 
   if (strEqual((*node_first)->key, key))
   {
-    free((*node_first)->key);
+    checked_free((*node_first)->key);
     if (destructor_function)
       destructor_function((*node_first)->content);
     *node_first = (*node_first)->next;
index 1259c0d5987ea87b51dbf1831e23d6f2ac24d5a7..90435c48179e2ffd7952f53b2f66a8651c256d64 100644 (file)
@@ -902,18 +902,25 @@ 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);
+  else
+    SaveTape(tape.level_nr);
+
+  SaveEngineSnapshot();
 }
 
 void TapeQuickLoad()
@@ -935,25 +942,42 @@ void TapeQuickLoad()
     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       /* this should not happen (basically checked above) */
-    {
-      int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0);
+    tape.playing = TRUE;
+    tape.pausing = TRUE;
 
-      Request("No tape for this level !", REQ_CONFIRM | reopen_door);
-    }
+    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);
   }
 }