}
+/* ------------------------------------------------------------------------- */
+/* 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 */
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()
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);
}
}