added ability to undo (restore) the previously recorded tape
authorHolger Schemel <info@artsoft.org>
Tue, 15 Sep 2020 06:40:14 +0000 (08:40 +0200)
committerHolger Schemel <info@artsoft.org>
Tue, 15 Sep 2020 06:40:14 +0000 (08:40 +0200)
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
src/tape.c
src/tape.h

index c18a8a468a3b24ac32d7c21e7b7ecd7573eb1a98..3a303fa5e5fc20155b1e179401e3e79b9ed881e6 100644 (file)
@@ -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"))
     {
index 29886a5c7346da27c25a3b3b5b538d0f8e982a5d..1d88941fedd31905322b33d03ae8d7828bd4b166 100644 (file)
 
 // 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;
index 7b9c44f8681d8db6eaa15ff585b8668c4e8ffc0b..23773684aeb794702b18ed56d3d4c1c6dc0b5536 100644 (file)
@@ -257,6 +257,7 @@ boolean hasSolutionTape(void);
 boolean InsertSolutionTape(void);
 boolean PlaySolutionTape(void);
 
+void UndoTape(void);
 void FixTape_ForceSinglePlayer(void);
 
 void AutoPlayTapes(void);