X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=c02e590f5fb026eb3d4c59cf09a03725a804b265;hb=6a0abfaaf87f8ae079c0baec627d0a89ae0336cc;hp=59a77329b4b5f83dbffb7fe84bd41036a90a46b9;hpb=9c92df9586b75ab4afc1345e944108e95e2f8174;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 59a77329..c02e590f 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,16 @@ 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_UNDO 3 +#define GAME_CTRL_ID_REDO 4 +#define GAME_CTRL_ID_SAVE 5 +#define GAME_CTRL_ID_PAUSE2 6 #define GAME_CTRL_ID_LOAD 7 +#define SOUND_CTRL_ID_MUSIC 8 +#define SOUND_CTRL_ID_LOOPS 9 +#define SOUND_CTRL_ID_SIMPLE 10 -#define NUM_GAME_BUTTONS 8 +#define NUM_GAME_BUTTONS 11 /* forward declaration for internal use */ @@ -2575,7 +2579,7 @@ void DisplayGameControlValues() void UpdateAndDisplayGameControlValues() { - if (tape.warp_forward) + if (tape.deactivate_display) return; UpdateGameControlValues(); @@ -3031,6 +3035,16 @@ 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); + + /* ---------- initialize game engine snapshots ---------------------------- */ + for (i = 0; i < MAX_PLAYERS; i++) + game.snapshot.last_action[i] = 0; + game.snapshot.changed_action = FALSE; + game.snapshot.mode = + (strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_STEP) ? + SNAPSHOT_MODE_EVERY_STEP : + strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_MOVE) ? + SNAPSHOT_MODE_EVERY_MOVE : SNAPSHOT_MODE_OFF); } int get_num_special_action(int element, int action_first, int action_last) @@ -3903,8 +3917,6 @@ void InitGame() /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap(backbuffer); - - redraw_mask |= REDRAW_FROM_BACKBUFFER; /* !!! FIX THIS (END) !!! */ FadeIn(REDRAW_FIELD); @@ -3991,6 +4003,8 @@ void InitGame() } game.restart_level = FALSE; + + SaveEngineSnapshotToListInitial(); } void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y) @@ -4377,13 +4391,16 @@ void GameEnd() local_player->LevelSolved_GameEnd = TRUE; - CloseDoor(DOOR_CLOSE_1); + if (!global.use_envelope_request) + CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) { SaveTapeChecked(tape.level_nr); /* ask to save tape */ } + CloseDoor(DOOR_CLOSE_ALL); + if (level_editor_test_game) { game_status = GAME_MODE_MAIN; @@ -4418,6 +4435,9 @@ void GameEnd() { game_status = GAME_MODE_SCORES; + /* needed if different viewport properties defined for scores */ + ChangeViewportPropertiesIfNeeded(); + DrawHallOfFame(hi_pos); if (raise_level) @@ -10668,6 +10688,37 @@ 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 ((!player->is_moving && player_was_moving) || + (player->MovPos == 0 && player_was_moving) || + (player->is_snapping && !player_was_snapping) || + (player->is_dropping && !player_was_dropping)) + { + if (!SaveEngineSnapshotToList()) + return; + + 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 +10731,8 @@ static void CheckSingleStepMode(struct PlayerInfo *player) SnapField(player, 0, 0); /* stop snapping */ } } + + CheckSaveEngineSnapshot(player); } static byte PlayerActions(struct PlayerInfo *player, byte player_action) @@ -10916,6 +10969,23 @@ void GameActions() byte tape_action[MAX_PLAYERS]; int i; + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + // allow engine snapshot if movement attempt was stopped + if ((game.snapshot.last_action[i] & KEY_MOTION) != 0 && + (player->action & KEY_MOTION) == 0) + game.snapshot.changed_action = TRUE; + + // allow engine snapshot in case of snapping/dropping attempt + if ((game.snapshot.last_action[i] & KEY_BUTTON) == 0 && + (player->action & KEY_BUTTON) != 0) + game.snapshot.changed_action = TRUE; + + game.snapshot.last_action[i] = player->action; + } + /* detect endless loops, caused by custom element programming */ if (recursion_loop_detected && recursion_loop_depth == 0) { @@ -11123,7 +11193,32 @@ void GameActions() } else { - GameActions_RND(); + GameActions_RND_Main(); + } + + BlitScreenToBitmap(backbuffer); + + CheckLevelTime(); + + AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ + + if (options.debug) /* calculate frames per second */ + { + static unsigned int fps_counter = 0; + static int fps_frames = 0; + unsigned int fps_delay_ms = Counter() - fps_counter; + + fps_frames++; + + 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(); + } + + redraw_mask |= REDRAW_FPS; } } @@ -11137,10 +11232,6 @@ void GameActions_EM_Main() effective_action[i] = stored_player[i].effective_action; GameActions_EM(effective_action, warp_mode); - - CheckLevelTime(); - - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ } void GameActions_SP_Main() @@ -11153,10 +11244,11 @@ void GameActions_SP_Main() effective_action[i] = stored_player[i].effective_action; GameActions_SP(effective_action, warp_mode); +} - CheckLevelTime(); - - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ +void GameActions_RND_Main() +{ + GameActions_RND(); } void GameActions_RND() @@ -11658,32 +11750,9 @@ void GameActions_RND() } #endif - CheckLevelTime(); - DrawAllPlayers(); PlayAllPlayersSound(); - if (options.debug) /* calculate frames per second */ - { - static unsigned int fps_counter = 0; - static int fps_frames = 0; - unsigned int fps_delay_ms = Counter() - fps_counter; - - fps_frames++; - - 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(); - } - - redraw_mask |= REDRAW_FPS; - } - - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ - if (local_player->show_envelope != 0 && local_player->MovPos == 0) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); @@ -11737,16 +11806,16 @@ static boolean AllPlayersInVisibleScreen() void ScrollLevel(int dx, int dy) { - int softscroll_offset = (setup.soft_scrolling ? 2 * TILEX_VAR : 0); + int scroll_offset = 2 * TILEX_VAR; int x, y; BlitBitmap(drawto_field, drawto_field, - FX + TILEX_VAR * (dx == -1) - softscroll_offset, - FY + TILEY_VAR * (dy == -1) - softscroll_offset, - SXSIZE - TILEX_VAR * (dx != 0) + 2 * softscroll_offset, - SYSIZE - TILEY_VAR * (dy != 0) + 2 * softscroll_offset, - FX + TILEX_VAR * (dx == 1) - softscroll_offset, - FY + TILEY_VAR * (dy == 1) - softscroll_offset); + FX + TILEX_VAR * (dx == -1) - scroll_offset, + FY + TILEY_VAR * (dy == -1) - scroll_offset, + SXSIZE - TILEX_VAR * (dx != 0) + 2 * scroll_offset, + SYSIZE - TILEY_VAR * (dy != 0) + 2 * scroll_offset, + FX + TILEX_VAR * (dx == 1) - scroll_offset, + FY + TILEY_VAR * (dy == 1) - scroll_offset); if (dx != 0) { @@ -12308,6 +12377,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 +14623,22 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshot() +void FreeEngineSnapshotSingle() { - FreeEngineSnapshotBuffers(); + FreeSnapshotSingle(); setString(&snapshot_level_identifier, NULL); snapshot_level_nr = -1; } -void SaveEngineSnapshot() +void FreeEngineSnapshotList() { - /* do not save snapshots from editor */ - if (level_editor_test_game) - return; + FreeSnapshotList(); +} - /* free previous snapshot buffers, if needed */ - FreeEngineSnapshotBuffers(); +ListNode *SaveEngineSnapshotBuffers() +{ + ListNode *buffers = NULL; /* copy some special values to a structure better suited for the snapshot */ @@ -14575,87 +14647,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)); - - /* save level identification information */ - - setString(&snapshot_level_identifier, leveldir_current->identifier); - snapshot_level_nr = level_nr; + 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)); #if 0 ListNode *node = engine_snapshot_list_rnd; @@ -14670,14 +14737,59 @@ void SaveEngineSnapshot() printf("::: size of engine snapshot: %d bytes\n", num_bytes); #endif + + return buffers; } -void LoadEngineSnapshot() +void SaveEngineSnapshotSingle() { - /* restore generically stored snapshot buffers */ + ListNode *buffers = SaveEngineSnapshotBuffers(); + + /* finally save all snapshot buffers to single snapshot */ + SaveSnapshotSingle(buffers); + + /* save level identification information */ + setString(&snapshot_level_identifier, leveldir_current->identifier); + snapshot_level_nr = level_nr; +} - LoadEngineSnapshotBuffers(); +static boolean SaveEngineSnapshotToListExt(boolean initial_snapshot) +{ + boolean save_snapshot = + (initial_snapshot || + (game.snapshot.mode == SNAPSHOT_MODE_EVERY_STEP) || + (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE && + game.snapshot.changed_action)); + + game.snapshot.changed_action = FALSE; + + if (game.snapshot.mode == SNAPSHOT_MODE_OFF || + tape.quick_resume || + !save_snapshot) + return FALSE; + + ListNode *buffers = SaveEngineSnapshotBuffers(); + + /* finally save all snapshot buffers to snapshot list */ + SaveSnapshotToList(buffers); + + return TRUE; +} + +boolean SaveEngineSnapshotToList() +{ + return SaveEngineSnapshotToListExt(FALSE); +} + +void SaveEngineSnapshotToListInitial() +{ + FreeEngineSnapshotList(); + SaveEngineSnapshotToListExt(TRUE); +} + +void LoadEngineSnapshotValues() +{ /* restore special values from snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) @@ -14688,19 +14800,45 @@ void LoadEngineSnapshot() LoadEngineSnapshotValues_SP(); } -boolean CheckEngineSnapshot() +void LoadEngineSnapshotSingle() +{ + LoadSnapshotSingle(); + + LoadEngineSnapshotValues(); +} + +void LoadEngineSnapshot_Undo(int steps) +{ + LoadSnapshotFromList_Older(steps); + + LoadEngineSnapshotValues(); +} + +void LoadEngineSnapshot_Redo(int steps) +{ + LoadSnapshotFromList_Newer(steps); + + LoadEngineSnapshotValues(); +} + +boolean CheckEngineSnapshotSingle() { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } +boolean CheckEngineSnapshotList() +{ + return CheckSnapshotList(); +} + /* ---------- new game button stuff ---------------------------------------- */ static struct { int graphic; - struct Rect *pos; + struct XY *pos; int gadget_id; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = @@ -14718,24 +14856,36 @@ 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_SOUND_LOOPS, &game.button.sound_loops, - SOUND_CTRL_ID_LOOPS, "sound loops on/off" + IMG_GAME_BUTTON_GFX_UNDO, &game.button.undo, + GAME_CTRL_ID_UNDO, "undo step" }, { - 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, GAME_CTRL_ID_SAVE, "save game" }, + { + IMG_GAME_BUTTON_GFX_PAUSE2, &game.button.pause2, + GAME_CTRL_ID_PAUSE2, "pause game" + }, { 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" } }; @@ -14746,7 +14896,7 @@ void CreateGameButtons() for (i = 0; i < NUM_GAME_BUTTONS; i++) { struct GraphicInfo *gfx = &graphic_info[gamebutton_info[i].graphic]; - struct Rect *pos = gamebutton_info[i].pos; + struct XY *pos = gamebutton_info[i].pos; struct GadgetInfo *gi; int button_type; boolean checked; @@ -14771,7 +14921,6 @@ void CreateGameButtons() } if (id == GAME_CTRL_ID_STOP || - id == GAME_CTRL_ID_PAUSE || id == GAME_CTRL_ID_PLAY || id == GAME_CTRL_ID_SAVE || id == GAME_CTRL_ID_LOAD) @@ -14780,6 +14929,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 +14979,69 @@ void FreeGameButtons() FreeGadget(game_gadget[i]); } +static void MapGameButtonsAtSamePosition(int id) +{ + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + if (i != id && + gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && + gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) + MapGadget(game_gadget[i]); +} + +static void UnmapGameButtonsAtSamePosition(int id) +{ + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + if (i != id && + gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && + gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) + UnmapGadget(game_gadget[i]); +} + +void MapUndoRedoButtons() +{ + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); + + MapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + MapGadget(game_gadget[GAME_CTRL_ID_REDO]); +} + +void UnmapUndoRedoButtons() +{ + UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]); + + MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); + MapGameButtonsAtSamePosition(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]); + + if (setup.show_snapshot_buttons) + { + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD); + } + else + { + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PLAY); + } + + RedrawGameButtons(); } void UnmapGameButtons() @@ -14850,8 +15063,47 @@ void RedrawGameButtons() redraw_mask &= ~REDRAW_ALL; } -static void HandleGameButtonsExt(int id) +void GameUndoRedoExt() +{ + ClearPlayerAction(); + + tape.pausing = TRUE; + + RedrawPlayfield(); + UpdateAndDisplayGameControlValues(); + + DrawCompleteVideoDisplay(); + DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); + DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); + DrawVideoDisplay((tape.single_step ? VIDEO_STATE_1STEP_ON : + VIDEO_STATE_1STEP_OFF), 0); + + BackToFront(); +} + +void GameUndo(int steps) +{ + if (!CheckEngineSnapshotList()) + return; + + LoadEngineSnapshot_Undo(steps); + + GameUndoRedoExt(); +} + +void GameRedo(int steps) +{ + if (!CheckEngineSnapshotList()) + return; + + LoadEngineSnapshot_Redo(steps); + + GameUndoRedoExt(); +} + +static void HandleGameButtonsExt(int id, int button) { + int steps = BUTTON_STEPSIZE(button); boolean handle_game_buttons = (game_status == GAME_MODE_PLAYING || (game_status == GAME_MODE_MAIN && tape.show_game_buttons)); @@ -14873,6 +15125,7 @@ static void HandleGameButtonsExt(int id) break; case GAME_CTRL_ID_PAUSE: + case GAME_CTRL_ID_PAUSE2: if (options.network && game_status == GAME_MODE_PLAYING) { #if defined(NETWORK_AVALIABLE) @@ -14898,13 +15151,26 @@ static void HandleGameButtonsExt(int id) SendToServer_ContinuePlaying(); else #endif - { - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0); - } + TapeTogglePause(TAPE_TOGGLE_MANUAL); } break; + case GAME_CTRL_ID_UNDO: + GameUndo(steps); + break; + + case GAME_CTRL_ID_REDO: + GameRedo(steps); + 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 +15210,6 @@ static void HandleGameButtonsExt(int id) } break; - case GAME_CTRL_ID_SAVE: - TapeQuickSave(); - break; - - case GAME_CTRL_ID_LOAD: - TapeQuickLoad(); - break; - default: break; } @@ -14959,7 +15217,7 @@ static void HandleGameButtonsExt(int id) static void HandleGameButtons(struct GadgetInfo *gi) { - HandleGameButtonsExt(gi->custom_id); + HandleGameButtonsExt(gi->custom_id, gi->event.button); } void HandleSoundButtonKeys(Key key)