commit 707b99d48761162f75b078e4c31e5505f7ce1840 Author: Bela Lubkin Date: Wed Sep 2 02:26:11 2020 -0700 added the ability to undo tape erasure. When the in-memory tape is erased with over 20 seconds of play on it, a copy is saved for possible undo. Enter ":undo-tape" or ":ut" from the main menu to undo tape erasure. The guard time preserves long tapes against short abortive actions. Note: tape undo does not pay attention to which level is loaded. Undoing an erased tape from a different level is unlikely to be helpful -- unless you are trying to test whether two levels are effectively identical. diff --git a/src/events.c b/src/events.c index 834b423..690235f 100644 --- a/src/events.c +++ b/src/events.c @@ -1825,6 +1825,11 @@ static void HandleKeysSpecial(Key key) { InsertSolutionTape(); } + else if (is_string_suffix(cheat_input, ":undo-tape") || + is_string_suffix(cheat_input, ":ut")) + { + RestoreTapeForUndo(); + } else if (is_string_suffix(cheat_input, ":play-solution-tape") || is_string_suffix(cheat_input, ":pst")) { diff --git a/src/main.c b/src/main.c index cb08365..0bb0536 100644 --- a/src/main.c +++ b/src/main.c @@ -132,6 +132,7 @@ struct LevelInfo level, level_template; struct PlayerInfo stored_player[MAX_PLAYERS], *local_player = NULL; struct HiScore highscore[MAX_SCORE_ENTRIES]; struct TapeInfo tape; +struct TapeInfo tapeUndo; struct GameInfo game; struct GlobalInfo global; struct BorderInfo border; diff --git a/src/main.h b/src/main.h index ae52c9f..8f1e53a 100644 --- a/src/main.h +++ b/src/main.h @@ -3716,6 +3716,7 @@ extern int graphics_action_mapping[]; extern struct LevelInfo level, level_template; extern struct HiScore highscore[]; extern struct TapeInfo tape; +extern struct TapeInfo tapeUndo; extern struct GlobalInfo global; extern struct BorderInfo border; extern struct ViewportInfo viewport; diff --git a/src/tape.c b/src/tape.c index 0f124e8..3be2ef1 100644 --- a/src/tape.c +++ b/src/tape.c @@ -517,10 +517,38 @@ void TapeSetDateFromNow(void) TapeSetDateFromEpochSeconds(time(NULL)); } +void SaveTapeForUndo(void) +{ + // Only if a bit of playing has happened. This leaves the 'precious' + // previous run undisturbed if no real amount of playing was done. + // (20s could be a setting) + + if (tape.length_seconds >= 20) { + tapeUndo = tape; + } +} + +void RestoreTapeForUndo(void) +{ + struct TapeInfo tmp; + + if (!TAPE_IS_STOPPED(tape)) + TapeStop(); + + // Swap so undo is undoable... + tmp = tape; + tape = tapeUndo; + tapeUndo = tmp; + + DrawCompleteVideoDisplay(); +} + void TapeErase(void) { int i; + SaveTapeForUndo(); + tape.counter = 0; tape.length = 0; tape.length_frames = 0; diff --git a/src/tape.h b/src/tape.h index a33c859..f60a419 100644 --- a/src/tape.h +++ b/src/tape.h @@ -239,6 +239,8 @@ void TapeStopPlaying(void); byte *TapePlayAction(void); void TapeStop(void); void TapeErase(void); +void SaveTapeForUndo(void); +void RestoreTapeForUndo(void); unsigned int GetTapeLengthFrames(void); unsigned int GetTapeLengthSeconds(void); void TapeQuickSave(void);