From c4621f6e17b3806b7edc0ab50e72353cb991842e Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Tue, 15 Sep 2020 08:40:14 +0200 Subject: [PATCH] added ability to undo (restore) the previously recorded tape When the in-memory tape is erased with more than a minimum length of playing time (currently set to 20 seconds), an internal copy of the tape is created to be able to restore it. Just type ":undo-tape" or ":ut" to undo (restore) the last tape. If the in-memory tape to be erased is shorter than the minimum length, an undo tape is created from it if it is longer than the currently stored undo tape. --- src/events.c | 5 +++++ src/tape.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tape.h | 1 + 3 files changed, 62 insertions(+) diff --git a/src/events.c b/src/events.c index c18a8a46..3a303fa5 100644 --- a/src/events.c +++ b/src/events.c @@ -1859,6 +1859,11 @@ static void HandleKeysSpecial(Key key) { DumpTape(&tape); } + else if (strSuffix(cheat_input, ":undo-tape") || + strSuffix(cheat_input, ":ut")) + { + UndoTape(); + } else if (strSuffix(cheat_input, ":fix-tape") || strSuffix(cheat_input, ":ft")) { diff --git a/src/tape.c b/src/tape.c index 29886a5c..1d88941f 100644 --- a/src/tape.c +++ b/src/tape.c @@ -35,13 +35,16 @@ // values for tape handling #define TAPE_PAUSE_SECONDS_BEFORE_DEATH 5 +#define TAPE_MIN_SECONDS_FOR_UNDO_BUFFER 20 // forward declaration for internal use static void HandleTapeButtons(struct GadgetInfo *); static void TapeStopWarpForward(void); static float GetTapeLengthSecondsFloat(void); +static void CopyTapeToUndoBuffer(void); static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS]; +static struct TapeInfo tape_undo_buffer; // ============================================================================ @@ -528,6 +531,8 @@ void TapeErase(void) { int i; + CopyTapeToUndoBuffer(); + tape.counter = 0; tape.length = 0; tape.length_frames = 0; @@ -1145,6 +1150,57 @@ boolean PlaySolutionTape(void) return TRUE; } +static boolean checkTapesFromSameLevel(struct TapeInfo *t1, struct TapeInfo *t2) +{ + return (strEqual(t1->level_identifier, t2->level_identifier) && + t1->level_nr == t2->level_nr); +} + +static void CopyTape(struct TapeInfo *tape_from, struct TapeInfo *tape_to) +{ + if (tape_to->level_identifier != NULL) + checked_free(tape_to->level_identifier); + + *tape_to = *tape_from; + + tape_to->level_identifier = getStringCopy(tape_from->level_identifier); +} + +static void SwapTapes(struct TapeInfo *t1, struct TapeInfo *t2) +{ + struct TapeInfo tmp = *t1; + + *t1 = *t2; + *t2 = tmp; +} + +static void CopyTapeToUndoBuffer(void) +{ + // copy tapes to undo buffer if large enough (or larger than last undo tape) + // or if the last undo tape is from a different level set or level number + if (tape.length_seconds >= TAPE_MIN_SECONDS_FOR_UNDO_BUFFER || + tape.length_seconds >= tape_undo_buffer.length_seconds || + !checkTapesFromSameLevel(&tape, &tape_undo_buffer)) + { + CopyTape(&tape, &tape_undo_buffer); + } +} + +void UndoTape(void) +{ + // only undo tapes from same level set and with same level number + if (!checkTapesFromSameLevel(&tape, &tape_undo_buffer)) + return; + + if (!TAPE_IS_STOPPED(tape)) + TapeStop(); + + // swap last recorded tape with undo buffer, so undo can be reversed + SwapTapes(&tape, &tape_undo_buffer); + + DrawCompleteVideoDisplay(); +} + void FixTape_ForceSinglePlayer(void) { int i; diff --git a/src/tape.h b/src/tape.h index 7b9c44f8..23773684 100644 --- a/src/tape.h +++ b/src/tape.h @@ -257,6 +257,7 @@ boolean hasSolutionTape(void); boolean InsertSolutionTape(void); boolean PlaySolutionTape(void); +void UndoTape(void); void FixTape_ForceSinglePlayer(void); void AutoPlayTapes(void); -- 2.34.1