From: Holger Schemel Date: Tue, 24 Mar 2015 13:11:04 +0000 (+0100) Subject: added step-based engine snapshots to undo/redo game steps X-Git-Tag: 4.0.0.0-rc1~230 X-Git-Url: https://git.artsoft.org/?a=commitdiff_plain;h=f6bcc10ce7b517f04eb5cddf01c9ec29ee729b7e;p=rocksndiamonds.git added step-based engine snapshots to undo/redo game steps --- diff --git a/graphics/gfx_classic/RocksDoor.ilbm b/graphics/gfx_classic/RocksDoor.ilbm index 2170dd94..13231581 100644 Binary files a/graphics/gfx_classic/RocksDoor.ilbm and b/graphics/gfx_classic/RocksDoor.ilbm differ diff --git a/src/conf_gfx.c b/src/conf_gfx.c index bf3a49b7..e749b222 100644 --- a/src/conf_gfx.c +++ b/src/conf_gfx.c @@ -4721,6 +4721,23 @@ struct ConfigInfo image_config[] = { "game.button.gfx.play.width", "30" }, { "game.button.gfx.play.height", "30" }, { "game.button.gfx.play.pressed_xoffset", "-100" }, + + { "game.button.gfx.undo", "RocksDoor.png" }, + { "game.button.gfx.undo.x", "405" }, + { "game.button.gfx.undo.y", "215" }, + { "game.button.gfx.undo.width", "30" }, + { "game.button.gfx.undo.height", "30" }, + { "game.button.gfx.undo.pressed_yoffset", "30" }, + { "game.button.gfx.redo", "RocksDoor.png" }, + { "game.button.gfx.redo.x", "465" }, + { "game.button.gfx.redo.y", "215" }, + { "game.button.gfx.redo.width", "30" }, + { "game.button.gfx.redo.height", "30" }, + { "game.button.gfx.redo.pressed_yoffset", "30" }, + + { "game.button.gfx.save", UNDEFINED_FILENAME }, + { "game.button.gfx.load", UNDEFINED_FILENAME }, + { "game.button.gfx.sound_music", "RocksDoor.png" }, { "game.button.gfx.sound_music.x", "305" }, { "game.button.gfx.sound_music.y", "245" }, @@ -4743,9 +4760,6 @@ struct ConfigInfo image_config[] = { "game.button.gfx.sound_simple.pressed_xoffset", "-100" }, { "game.button.gfx.sound_simple.active_yoffset", "-30" }, - { "game.button.gfx.save", UNDEFINED_FILENAME }, - { "game.button.gfx.load", UNDEFINED_FILENAME }, - { "tape.button.gfx.eject", "RocksDoor.png" }, { "tape.button.gfx.eject.x", "305" }, { "tape.button.gfx.eject.y", "357" }, @@ -7348,16 +7362,20 @@ struct ConfigInfo image_config[] = { "game.button.pause.y", "215" }, { "game.button.play.x", "65" }, { "game.button.play.y", "215" }, + { "game.button.undo.x", "5" }, + { "game.button.undo.y", "215" }, + { "game.button.redo.x", "65" }, + { "game.button.redo.y", "215" }, + { "game.button.save.x", "-1" }, + { "game.button.save.y", "-1" }, + { "game.button.load.x", "-1" }, + { "game.button.load.y", "-1" }, { "game.button.sound_music.x", "5" }, { "game.button.sound_music.y", "245" }, { "game.button.sound_loops.x", "35" }, { "game.button.sound_loops.y", "245" }, { "game.button.sound_simple.x", "65" }, { "game.button.sound_simple.y", "245" }, - { "game.button.save.x", "-1" }, - { "game.button.save.y", "-1" }, - { "game.button.load.x", "-1" }, - { "game.button.load.y", "-1" }, { "tape.button.eject.x", "5" }, { "tape.button.eject.y", "77" }, diff --git a/src/engines.h b/src/engines.h index d1181edb..0fc44577 100644 --- a/src/engines.h +++ b/src/engines.h @@ -32,7 +32,8 @@ extern int getGameFrameDelay_EM(int); extern void PlayLevelSound_EM(int, int, int, int); extern void InitGraphicInfo_EM(void); -extern void CheckSingleStepMode_EM(byte action[], int, boolean, boolean); +extern void CheckSingleStepMode_EM(byte action[], int, + boolean, boolean, boolean); void SetGfxAnimation_EM(struct GraphicInfo_EM *, int, int, int, int); void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *, int, int, int, int); diff --git a/src/events.c b/src/events.c index d599dde4..42277b02 100644 --- a/src/events.c +++ b/src/events.c @@ -932,12 +932,14 @@ void HandleWindowManagerEvent(Event *event) void HandleButton(int mx, int my, int button, int button_nr) { static int old_mx = 0, old_my = 0; + boolean button_hold = FALSE; if (button < 0) { mx = old_mx; my = old_my; button = -button; + button_hold = TRUE; } else { @@ -946,6 +948,7 @@ void HandleButton(int mx, int my, int button, int button_nr) } #if defined(PLATFORM_ANDROID) + // !!! for now, do not handle gadgets when playing -- maybe fix this !!! if (game_status != GAME_MODE_PLAYING && HandleGadgets(mx, my, button)) { @@ -960,6 +963,9 @@ void HandleButton(int mx, int my, int button, int button_nr) } #endif + if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing) + return; + /* do not use scroll wheel button events for anything other than gadgets */ if (IS_WHEEL_BUTTON(button_nr)) return; @@ -1595,7 +1601,8 @@ void HandleKey(Key key, int key_status) void HandleNoEvent() { - if (button_status && game_status != GAME_MODE_PLAYING) + // if (button_status && game_status != GAME_MODE_PLAYING) + if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing)) { HandleButton(0, 0, -button_status, button_status); } diff --git a/src/game.c b/src/game.c index 57c7b873..c0153bdf 100644 --- a/src/game.c +++ b/src/game.c @@ -15,6 +15,7 @@ #include "init.h" #include "tools.h" #include "screens.h" +#include "events.h" #include "files.h" #include "tape.h" #include "network.h" @@ -970,13 +971,15 @@ static struct GamePanelControlInfo game_panel_controls[] = #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 -#define SOUND_CTRL_ID_MUSIC 3 -#define SOUND_CTRL_ID_LOOPS 4 -#define SOUND_CTRL_ID_SIMPLE 5 -#define GAME_CTRL_ID_SAVE 6 -#define GAME_CTRL_ID_LOAD 7 +#define GAME_CTRL_ID_UNDO 3 +#define GAME_CTRL_ID_REDO 4 +#define GAME_CTRL_ID_SAVE 5 +#define GAME_CTRL_ID_LOAD 6 +#define SOUND_CTRL_ID_MUSIC 7 +#define SOUND_CTRL_ID_LOOPS 8 +#define SOUND_CTRL_ID_SIMPLE 9 -#define NUM_GAME_BUTTONS 8 +#define NUM_GAME_BUTTONS 10 /* forward declaration for internal use */ @@ -3031,6 +3034,8 @@ static void InitGameEngine() setup.scroll_delay ? setup.scroll_delay_value : 0); game.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); + + FreeEngineSnapshotList(); } int get_num_special_action(int element, int action_first, int action_last) @@ -3991,6 +3996,8 @@ void InitGame() } game.restart_level = FALSE; + + SaveEngineSnapshotToList(); } void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y) @@ -10668,6 +10675,39 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) } } +static void CheckSaveEngineSnapshot(struct PlayerInfo *player) +{ + static boolean player_was_moving = FALSE; + static boolean player_was_snapping = FALSE; + static boolean player_was_dropping = FALSE; + + if (!tape.recording) + return; + + if ((!player->is_moving && player_was_moving) || + (player->MovPos == 0 && player_was_moving) || + (player->is_snapping && !player_was_snapping) || + (player->is_dropping && !player_was_dropping)) + { + SaveEngineSnapshotToList(); + + player_was_moving = FALSE; + player_was_snapping = TRUE; + player_was_dropping = TRUE; + } + else + { + if (player->is_moving) + player_was_moving = TRUE; + + if (!player->is_snapping) + player_was_snapping = FALSE; + + if (!player->is_dropping) + player_was_dropping = FALSE; + } +} + static void CheckSingleStepMode(struct PlayerInfo *player) { if (tape.single_step && tape.recording && !tape.pausing) @@ -10680,6 +10720,8 @@ static void CheckSingleStepMode(struct PlayerInfo *player) SnapField(player, 0, 0); /* stop snapping */ } } + + CheckSaveEngineSnapshot(player); } static byte PlayerActions(struct PlayerInfo *player, byte player_action) @@ -12308,6 +12350,9 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (tape.single_step && tape.recording && !tape.pausing && !player->programmed_action) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + + if (!player->programmed_action) + CheckSaveEngineSnapshot(player); } } @@ -14551,22 +14596,26 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshot() +void FreeEngineSnapshotSingle() { - FreeEngineSnapshotBuffers(); + FreeSnapshotSingle(); setString(&snapshot_level_identifier, NULL); snapshot_level_nr = -1; } -void SaveEngineSnapshot() +void FreeEngineSnapshotList() { + FreeSnapshotList(); +} + +ListNode *SaveEngineSnapshotBuffers() +{ + ListNode *buffers = NULL; + /* do not save snapshots from editor */ if (level_editor_test_game) - return; - - /* free previous snapshot buffers, if needed */ - FreeEngineSnapshotBuffers(); + return NULL; /* copy some special values to a structure better suited for the snapshot */ @@ -14575,82 +14624,82 @@ void SaveEngineSnapshot() if (level.game_engine_type == GAME_ENGINE_TYPE_EM) SaveEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - SaveEngineSnapshotValues_SP(); + SaveEngineSnapshotValues_SP(&buffers); /* save values stored in special snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); /* 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(CheckImpact)); - 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)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(stored_player)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(game)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(tape)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZX)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZY)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitX)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitY)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTime)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Feld)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovPos)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDir)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangePage)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CustomValue)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store2)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Back)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Stop)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Pushed)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_x)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_y)); /* save level identification information */ @@ -14670,14 +14719,28 @@ void SaveEngineSnapshot() printf("::: size of engine snapshot: %d bytes\n", num_bytes); #endif + + return buffers; +} + +void SaveEngineSnapshotSingle() +{ + ListNode *buffers = SaveEngineSnapshotBuffers(); + + /* finally save all snapshot buffers to single snapshot */ + SaveSnapshotSingle(buffers); } -void LoadEngineSnapshot() +void SaveEngineSnapshotToList() { - /* restore generically stored snapshot buffers */ + ListNode *buffers = SaveEngineSnapshotBuffers(); - LoadEngineSnapshotBuffers(); + /* finally save all snapshot buffers to snapshot list */ + SaveSnapshotToList(buffers); +} +void LoadEngineSnapshotValues() +{ /* restore special values from snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) @@ -14688,6 +14751,27 @@ void LoadEngineSnapshot() LoadEngineSnapshotValues_SP(); } +void LoadEngineSnapshotSingle() +{ + LoadSnapshotSingle(); + + LoadEngineSnapshotValues(); +} + +void LoadEngineSnapshot_Undo() +{ + LoadSnapshotFromList_Older(); + + LoadEngineSnapshotValues(); +} + +void LoadEngineSnapshot_Redo() +{ + LoadSnapshotFromList_Newer(); + + LoadEngineSnapshotValues(); +} + boolean CheckEngineSnapshot() { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && @@ -14718,16 +14802,12 @@ static struct GAME_CTRL_ID_PLAY, "play game" }, { - IMG_GAME_BUTTON_GFX_SOUND_MUSIC, &game.button.sound_music, - SOUND_CTRL_ID_MUSIC, "background music on/off" + IMG_GAME_BUTTON_GFX_UNDO, &game.button.undo, + GAME_CTRL_ID_UNDO, "undo step" }, { - IMG_GAME_BUTTON_GFX_SOUND_LOOPS, &game.button.sound_loops, - SOUND_CTRL_ID_LOOPS, "sound loops on/off" - }, - { - IMG_GAME_BUTTON_GFX_SOUND_SIMPLE, &game.button.sound_simple, - SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" + IMG_GAME_BUTTON_GFX_REDO, &game.button.redo, + GAME_CTRL_ID_REDO, "redo step" }, { IMG_GAME_BUTTON_GFX_SAVE, &game.button.save, @@ -14736,6 +14816,18 @@ static struct { IMG_GAME_BUTTON_GFX_LOAD, &game.button.load, GAME_CTRL_ID_LOAD, "load game" + }, + { + IMG_GAME_BUTTON_GFX_SOUND_MUSIC, &game.button.sound_music, + SOUND_CTRL_ID_MUSIC, "background music on/off" + }, + { + IMG_GAME_BUTTON_GFX_SOUND_LOOPS, &game.button.sound_loops, + SOUND_CTRL_ID_LOOPS, "sound loops on/off" + }, + { + IMG_GAME_BUTTON_GFX_SOUND_SIMPLE, &game.button.sound_simple, + SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } }; @@ -14780,6 +14872,13 @@ void CreateGameButtons() checked = FALSE; event_mask = GD_EVENT_RELEASED; } + else if (id == GAME_CTRL_ID_UNDO || + id == GAME_CTRL_ID_REDO) + { + button_type = GD_TYPE_NORMAL_BUTTON; + checked = FALSE; + event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; + } else { button_type = GD_TYPE_CHECK_BUTTON; @@ -14823,12 +14922,32 @@ void FreeGameButtons() FreeGadget(game_gadget[i]); } +void MapStopPlayButtons() +{ + UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]); + + MapGadget(game_gadget[GAME_CTRL_ID_STOP]); + MapGadget(game_gadget[GAME_CTRL_ID_PLAY]); +} + +void MapUndoRedoButtons() +{ + UnmapGadget(game_gadget[GAME_CTRL_ID_STOP]); + UnmapGadget(game_gadget[GAME_CTRL_ID_PLAY]); + + MapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + MapGadget(game_gadget[GAME_CTRL_ID_REDO]); +} + void MapGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) - MapGadget(game_gadget[i]); + if (i != GAME_CTRL_ID_UNDO && + i != GAME_CTRL_ID_REDO) + MapGadget(game_gadget[i]); } void UnmapGameButtons() @@ -14850,6 +14969,41 @@ void RedrawGameButtons() redraw_mask &= ~REDRAW_ALL; } +void GameUndoRedoExt() +{ + ClearPlayerAction(); + + tape.pausing = TRUE; + + RedrawPlayfield(); + UpdateAndDisplayGameControlValues(); + + DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); + DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); + + BackToFront(); +} + +void GameUndo() +{ + if (!CheckEngineSnapshot()) + return; + + LoadEngineSnapshot_Undo(); + + GameUndoRedoExt(); +} + +void GameRedo() +{ + if (!CheckEngineSnapshot()) + return; + + LoadEngineSnapshot_Redo(); + + GameUndoRedoExt(); +} + static void HandleGameButtonsExt(int id) { boolean handle_game_buttons = @@ -14905,6 +15059,22 @@ static void HandleGameButtonsExt(int id) } break; + case GAME_CTRL_ID_UNDO: + GameUndo(); + break; + + case GAME_CTRL_ID_REDO: + GameRedo(); + break; + + case GAME_CTRL_ID_SAVE: + TapeQuickSave(); + break; + + case GAME_CTRL_ID_LOAD: + TapeQuickLoad(); + break; + case SOUND_CTRL_ID_MUSIC: if (setup.sound_music) { @@ -14944,14 +15114,6 @@ static void HandleGameButtonsExt(int id) } break; - case GAME_CTRL_ID_SAVE: - TapeQuickSave(); - break; - - case GAME_CTRL_ID_LOAD: - TapeQuickLoad(); - break; - default: break; } diff --git a/src/game.h b/src/game.h index 86c26eeb..3f04c02e 100644 --- a/src/game.h +++ b/src/game.h @@ -90,12 +90,15 @@ struct GameButtonInfo struct XY pause; struct XY play; - struct XY sound_music; - struct XY sound_loops; - struct XY sound_simple; + struct XY undo; + struct XY redo; struct XY save; struct XY load; + + struct XY sound_music; + struct XY sound_loops; + struct XY sound_simple; }; struct GameInfo @@ -346,13 +349,17 @@ void RequestQuitGame(boolean); unsigned int InitEngineRandom_RND(int); unsigned int RND(int); -void FreeEngineSnapshot(); -void LoadEngineSnapshot(); -void SaveEngineSnapshot(); +void FreeEngineSnapshotSingle(); +void FreeEngineSnapshotList(); +void LoadEngineSnapshotSingle(); +void SaveEngineSnapshotSingle(); +void SaveEngineSnapshotToList(); boolean CheckEngineSnapshot(); void CreateGameButtons(); void FreeGameButtons(); +void MapStopPlayButtons(); +void MapUndoRedoButtons(); void MapGameButtons(); void UnmapGameButtons(); void RedrawGameButtons(); diff --git a/src/game_em/convert.c b/src/game_em/convert.c index 3631114c..d240739e 100644 --- a/src/game_em/convert.c +++ b/src/game_em/convert.c @@ -1108,6 +1108,7 @@ void prepare_em_level(void) } game_em.any_player_moving = FALSE; + game_em.any_player_snapping = FALSE; game_em.last_moving_player = 0; /* default: first player */ for (i = 0; i < MAX_PLAYERS; i++) diff --git a/src/game_em/export.h b/src/game_em/export.h index 61e95b45..837a9baf 100644 --- a/src/game_em/export.h +++ b/src/game_em/export.h @@ -665,6 +665,7 @@ struct GlobalInfo_EM struct GameInfo_EM { boolean any_player_moving; + boolean any_player_snapping; int last_moving_player; int last_player_direction[MAX_PLAYERS]; }; diff --git a/src/game_em/input.c b/src/game_em/input.c index 7b3ae921..73d1c858 100644 --- a/src/game_em/input.c +++ b/src/game_em/input.c @@ -73,7 +73,7 @@ void UpdateGameDoorValues_EM() void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode) { int i; - boolean player_is_dropping = FALSE; + boolean any_player_dropping = FALSE; RandomEM = RandomEM * 129 + 1; @@ -103,10 +103,10 @@ void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode) ply[i].dynamite && ply[i].dynamite_cnt > 0 && ply[i].dynamite_cnt < 5) - player_is_dropping = TRUE; + any_player_dropping = TRUE; CheckSingleStepMode_EM(action, frame, game_em.any_player_moving, - player_is_dropping); + game_em.any_player_snapping, any_player_dropping); game_animscreen(); diff --git a/src/game_em/synchro_1.c b/src/game_em/synchro_1.c index f09fc848..7b2e9c80 100644 --- a/src/game_em/synchro_1.c +++ b/src/game_em/synchro_1.c @@ -23,6 +23,7 @@ void synchro_1(void) int i; game_em.any_player_moving = FALSE; + game_em.any_player_snapping = FALSE; /* must test for death and actually kill separately */ for (i = 0; i < MAX_PLAYERS; i++) @@ -460,7 +461,7 @@ static void check_player(struct PLAYER *ply) } else /* player wants to snap */ { - player_digfield(ply, dx, dy); + game_em.any_player_snapping = player_digfield(ply, dx, dy); } } diff --git a/src/game_sp/export.h b/src/game_sp/export.h index 3da95312..001fb6d7 100644 --- a/src/game_sp/export.h +++ b/src/game_sp/export.h @@ -192,7 +192,7 @@ extern void BlitScreenToBitmap_SP(Bitmap *); extern void RedrawPlayfield_SP(boolean); extern void LoadEngineSnapshotValues_SP(); -extern void SaveEngineSnapshotValues_SP(); +extern void SaveEngineSnapshotValues_SP(ListNode **); extern int map_key_RND_to_SP(int); extern int map_key_SP_to_RND(int); diff --git a/src/game_sp/init.c b/src/game_sp/init.c index 1fef7fae..b515020c 100644 --- a/src/game_sp/init.c +++ b/src/game_sp/init.c @@ -102,7 +102,7 @@ unsigned int InitEngineRandom_SP(int seed) /* Supaplex game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ -void SaveEngineSnapshotValues_SP() +void SaveEngineSnapshotValues_SP(ListNode **buffers) { int i; @@ -126,66 +126,66 @@ void SaveEngineSnapshotValues_SP() /* store special data into engine snapshot buffers */ - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldWidth)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldHeight)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FieldMax)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(LevelMax)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimerVar)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RandomSeed)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TerminalMaxCycles)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollY)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollX_last)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(mScrollY_last)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenScrollXPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenScrollYPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMinX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMinY)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMaxX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(DisplayMaxY)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(InfotronsNeeded)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(KillMurphyFlag)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyMoveCounter)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyExplodePos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(SplitMoveFlag)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseMurphyPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyPosIndex)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyXPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyYPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyScreenXPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyScreenYPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MurphyVarFaceLeft)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskCount)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseFlag)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovingPictureSequencePhase)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RedDiskReleasePhase)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScratchGravity)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GravityFlag)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(SnikSnaksElectronsFrozen)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(YellowDisksExploded)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(YawnSleepCounter)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(LeadOutCounter)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElementLast)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxGraphicLast)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxGraphic)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMinX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMinY)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMaxX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollMaxY)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollY)); - - SaveEngineSnapshotBuffer(&PlayField16[-game_sp.preceding_buffer_size], - game_sp.preceding_buffer_size * sizeof(int)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldWidth)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldHeight)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(FieldMax)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(LevelMax)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(TimerVar)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RandomSeed)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(TerminalMaxCycles)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollY)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollX_last)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(mScrollY_last)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenScrollXPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenScrollYPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMinX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMinY)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMaxX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(DisplayMaxY)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(InfotronsNeeded)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(KillMurphyFlag)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyMoveCounter)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyExplodePos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(SplitMoveFlag)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseMurphyPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyPosIndex)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyXPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyYPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyScreenXPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyScreenYPos)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MurphyVarFaceLeft)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskCount)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleaseFlag)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(MovingPictureSequencePhase)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(RedDiskReleasePhase)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScratchGravity)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GravityFlag)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(SnikSnaksElectronsFrozen)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(YellowDisksExploded)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(YawnSleepCounter)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(LeadOutCounter)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElementLast)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxGraphicLast)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxGraphic)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); + + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMinX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMinY)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMaxX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollMaxY)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollX)); + SaveSnapshotBuffer(buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollY)); + + SaveSnapshotBuffer(buffers, &PlayField16[-game_sp.preceding_buffer_size], + game_sp.preceding_buffer_size * sizeof(int)); } void LoadEngineSnapshotValues_SP() diff --git a/src/libgame/misc.c b/src/libgame/misc.c index c02d3920..052509f6 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -1965,6 +1965,10 @@ void addNodeToList(ListNode **node_first, char *key, void *content) node_new->key = getStringCopy(key); node_new->content = content; node_new->next = *node_first; + + if (*node_first) + (*node_first)->prev = node_new; + *node_first = node_new; } @@ -1977,8 +1981,15 @@ void deleteNodeFromList(ListNode **node_first, char *key, if (strEqual((*node_first)->key, key)) { checked_free((*node_first)->key); + if (destructor_function) destructor_function((*node_first)->content); + + if ((*node_first)->next) + (*node_first)->next->prev = (*node_first)->prev; + + checked_free(*node_first); + *node_first = (*node_first)->next; } else diff --git a/src/libgame/snapshot.c b/src/libgame/snapshot.c index 51171d43..f57cb5fa 100644 --- a/src/libgame/snapshot.c +++ b/src/libgame/snapshot.c @@ -12,12 +12,26 @@ #include "snapshot.h" -static ListNode *engine_snapshot_list = NULL; +static ListNode *snapshot_single = NULL; +static ListNode *snapshot_list = NULL; +static ListNode *snapshot_current = NULL; -void SaveEngineSnapshotBuffer(void *buffer, int size) +static int num_snapshots_in_list = 0; + + +#ifdef DEBUG +#define DEBUG_SNAPSHOTS 0 +#endif + + +// ----------------------------------------------------------------------------- +// functions for handling buffers for a single snapshot +// ----------------------------------------------------------------------------- + +void SaveSnapshotBuffer(ListNode **snapshot_buffers, void *buffer, int size) { - struct EngineSnapshotNodeInfo *bi = - checked_calloc(sizeof(struct EngineSnapshotNodeInfo)); + struct SnapshotNodeInfo *bi = + checked_calloc(sizeof(struct SnapshotNodeInfo)); bi->buffer_orig = buffer; bi->buffer_copy = checked_malloc(size); @@ -25,29 +39,132 @@ void SaveEngineSnapshotBuffer(void *buffer, int size) memcpy(bi->buffer_copy, buffer, size); - addNodeToList(&engine_snapshot_list, NULL, bi); + addNodeToList(snapshot_buffers, NULL, bi); } -static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi) +static void LoadSnapshotBuffer(struct SnapshotNodeInfo *bi) { memcpy(bi->buffer_orig, bi->buffer_copy, bi->size); } -void LoadEngineSnapshotBuffers() +void LoadSnapshotBuffers(ListNode *snapshot_buffers) +{ + while (snapshot_buffers != NULL) + { + LoadSnapshotBuffer((struct SnapshotNodeInfo *)snapshot_buffers->content); + + snapshot_buffers = snapshot_buffers->next; + } +} + +void FreeSnapshotBuffers(ListNode *snapshot_buffers) +{ + while (snapshot_buffers != NULL) + deleteNodeFromList(&snapshot_buffers, snapshot_buffers->key, checked_free); +} + +// ----------------------------------------------------------------------------- +// functions for handling one of several snapshots +// ----------------------------------------------------------------------------- + +static void FreeSnapshotExt(void *snapshot_buffers_ptr) +{ + FreeSnapshotBuffers(snapshot_buffers_ptr); +} + +void FreeSnapshotSingle() +{ + FreeSnapshotBuffers(snapshot_single); + + snapshot_single = NULL; +} + +void FreeSnapshotList_UpToNode(ListNode *node) +{ + while (snapshot_list != node) + { + deleteNodeFromList(&snapshot_list, snapshot_list->key, FreeSnapshotExt); + + num_snapshots_in_list--; + } +} + +void FreeSnapshotList() +{ + FreeSnapshotList_UpToNode(NULL); + + snapshot_current = NULL; +} + +void SaveSnapshotSingle(ListNode *snapshot_buffers) +{ + if (snapshot_single) + FreeSnapshotSingle(); + + snapshot_single = snapshot_buffers; +} + +void SaveSnapshotToList(ListNode *snapshot_buffers) { - ListNode *node = engine_snapshot_list; + if (snapshot_current != snapshot_list) + FreeSnapshotList_UpToNode(snapshot_current); + + addNodeToList(&snapshot_list, i_to_a(num_snapshots_in_list), + snapshot_buffers); - while (node != NULL) + snapshot_current = snapshot_list; + + num_snapshots_in_list++; + +#if DEBUG_SNAPSHOTS + printf("::: SaveSnapshotToList() [%s]\n", snapshot_current->key); +#endif +} + +boolean LoadSnapshotSingle() +{ + if (snapshot_single) { - LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content); + LoadSnapshotBuffers(snapshot_single); - node = node->next; + return TRUE; } + + return FALSE; } -void FreeEngineSnapshotBuffers() +boolean LoadSnapshotFromList_Older() { - while (engine_snapshot_list != NULL) - deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key, - checked_free); + if (snapshot_current->next) + { + snapshot_current = snapshot_current->next; + + LoadSnapshotBuffers(snapshot_current->content); + +#if DEBUG_SNAPSHOTS + printf("::: LoadSnapshotFromList_Older() [%s]\n", snapshot_current->key); +#endif + + return TRUE; + } + + return FALSE; +} + +boolean LoadSnapshotFromList_Newer() +{ + if (snapshot_current->prev) + { + snapshot_current = snapshot_current->prev; + + LoadSnapshotBuffers(snapshot_current->content); + +#if DEBUG_SNAPSHOTS + printf("::: LoadSnapshotFromList_Newer() [%s]\n", snapshot_current->key); +#endif + + return TRUE; + } + + return FALSE; } diff --git a/src/libgame/snapshot.h b/src/libgame/snapshot.h index ef63bdf8..40b85938 100644 --- a/src/libgame/snapshot.h +++ b/src/libgame/snapshot.h @@ -19,7 +19,7 @@ /* needed for comfortably saving engine snapshot buffers */ #define ARGS_ADDRESS_AND_SIZEOF(x) (&(x)), (sizeof(x)) -struct EngineSnapshotNodeInfo +struct SnapshotNodeInfo { void *buffer_orig; void *buffer_copy; @@ -27,8 +27,16 @@ struct EngineSnapshotNodeInfo }; -void SaveEngineSnapshotBuffer(void *buffer, int size); -void LoadEngineSnapshotBuffers(); -void FreeEngineSnapshotBuffers(); +void SaveSnapshotBuffer(ListNode **, void *, int); +void LoadSnapshotBuffers(ListNode *); +void FreeSnapshotBuffers(ListNode *); + +void SaveSnapshotSingle(); +void SaveSnapshotToList(); +boolean LoadSnapshotSingle(); +boolean LoadSnapshotFromList_Older(); +boolean LoadSnapshotFromList_Newer(); +void FreeSnapshotSingle(); +void FreeSnapshotList(); #endif /* SNAPSHOT_H */ diff --git a/src/libgame/types.h b/src/libgame/types.h index 0dfed15a..acc2c236 100644 --- a/src/libgame/types.h +++ b/src/libgame/types.h @@ -72,6 +72,7 @@ struct ListNode { char *key; void *content; + struct ListNode *prev; struct ListNode *next; }; typedef struct ListNode ListNode; diff --git a/src/tape.c b/src/tape.c index f6f75061..a14690d3 100644 --- a/src/tape.c +++ b/src/tape.c @@ -740,9 +740,14 @@ void TapeTogglePause(boolean toggle_manual) TapeAppendRecording(); if (!CheckEngineSnapshot()) - SaveEngineSnapshot(); + SaveEngineSnapshotSingle(); } } + + if (tape.pausing) + MapUndoRedoButtons(); + else + MapStopPlayButtons(); } void TapeStartPlaying() @@ -1002,7 +1007,7 @@ void TapeQuickSave() } if (SaveTapeChecked(tape.level_nr)) - SaveEngineSnapshot(); + SaveEngineSnapshotSingle(); } void TapeQuickLoad() @@ -1031,7 +1036,7 @@ void TapeQuickLoad() { TapeStartGamePlaying(); - LoadEngineSnapshot(); + LoadEngineSnapshotSingle(); DrawCompleteVideoDisplay(); diff --git a/src/tools.c b/src/tools.c index a95b1f79..e98ac35b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -7794,13 +7794,65 @@ void InitGraphicInfo_EM(void) #endif } +void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame, + boolean any_player_moving, + boolean any_player_snapping, + boolean any_player_dropping) +{ + static boolean player_was_waiting = TRUE; + + if (!tape.recording) + return; + + if (frame == 0 && !any_player_dropping) + { + if (!player_was_waiting) + { + SaveEngineSnapshotToList(); + + player_was_waiting = TRUE; + } + } + else if (any_player_moving || any_player_snapping || any_player_dropping) + { + player_was_waiting = FALSE; + } +} + +void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting, + boolean murphy_is_dropping) +{ + static boolean player_was_waiting = FALSE; + + if (!tape.recording) + return; + + if (murphy_is_waiting) + { + if (!player_was_waiting) + { + SaveEngineSnapshotToList(); + + player_was_waiting = TRUE; + } + } + else + { + player_was_waiting = FALSE; + } +} + void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame, boolean any_player_moving, - boolean player_is_dropping) + boolean any_player_snapping, + boolean any_player_dropping) { if (tape.single_step && tape.recording && !tape.pausing) - if (frame == 0 && !player_is_dropping) + if (frame == 0 && !any_player_dropping) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + + CheckSaveEngineSnapshot_EM(action, frame, any_player_moving, + any_player_snapping, any_player_dropping); } void CheckSingleStepMode_SP(boolean murphy_is_waiting, @@ -7809,6 +7861,8 @@ void CheckSingleStepMode_SP(boolean murphy_is_waiting, if (tape.single_step && tape.recording && !tape.pausing) if (murphy_is_waiting) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + + CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping); } void getGraphicSource_SP(struct GraphicInfo_SP *g_sp, @@ -8080,7 +8134,7 @@ void ChangeViewportPropertiesIfNeeded() // printf("::: new_tilesize_var != TILESIZE_VAR\n"); // changing tile size invalidates scroll values of engine snapshots - FreeEngineSnapshot(); + FreeEngineSnapshotSingle(); // changing tile size requires update of graphic mapping for EM engine init_em_graphics = TRUE;