+// ============================================================================
+// tape logging functions
+// ============================================================================
+
+struct AutoPlayInfo
+{
+ LevelDirTree *leveldir;
+ boolean all_levelsets;
+ int last_level_nr;
+ int level_nr;
+ int num_levels_played;
+ int num_levels_solved;
+ int num_tapes_patched;
+ int num_tape_missing;
+ boolean level_failed[MAX_TAPES_PER_SET];
+ char *tape_filename;
+};
+
+static char tape_patch_info[MAX_OUTPUT_LINESIZE];
+
+static void PrintTapeReplayHeader(struct AutoPlayInfo *autoplay)
+{
+ PrintLine("=", 79);
+
+ if (global.autoplay_mode == AUTOPLAY_MODE_FIX)
+ Print("Automatically fixing level tapes\n");
+ else if (global.autoplay_mode == AUTOPLAY_MODE_UPLOAD)
+ Print("Automatically uploading level tapes\n");
+ else
+ Print("Automatically playing level tapes\n");
+
+ PrintLine("-", 79);
+ Print("Level series identifier: '%s'\n", autoplay->leveldir->identifier);
+ Print("Level series name: '%s'\n", autoplay->leveldir->name);
+ Print("Level series author: '%s'\n", autoplay->leveldir->author);
+ Print("Number of levels: %d\n", autoplay->leveldir->levels);
+ PrintLine("=", 79);
+ Print("\n");
+
+ DrawInitTextItem(autoplay->leveldir->name);
+}
+
+static void PrintTapeReplayProgress(boolean replay_finished)
+{
+ static unsigned int counter_last = -1;
+ unsigned int counter = Counter();
+ unsigned int counter_seconds = counter / 1000;
+
+ if (!replay_finished)
+ {
+ unsigned int counter_delay = 50;
+
+ if (counter > counter_last + counter_delay)
+ {
+ PrintNoLog("\r");
+ PrintNoLog("Tape %03d %s[%02d:%02d]: [%02d:%02d] - playing tape ... ",
+ level_nr, tape_patch_info,
+ tape.length_seconds / 60, tape.length_seconds % 60,
+ TapeTime / 60, TapeTime % 60);
+
+ counter_last = counter;
+ }
+ }
+ else
+ {
+ float tape_length_seconds = GetTapeLengthSecondsFloat();
+
+ PrintNoLog("\r");
+ Print("Tape %03d %s[%02d:%02d]: (%02d:%02d.%03d / %.2f %%) - %s.\n",
+ level_nr, tape_patch_info,
+ tape.length_seconds / 60, tape.length_seconds % 60,
+ counter_seconds / 60, counter_seconds % 60, counter % 1000,
+ (float)counter / tape_length_seconds / 10,
+ tape.auto_play_level_fixed ? "solved and fixed" :
+ tape.auto_play_level_solved ? "solved" :
+ tape.auto_play_level_not_fixable ? "NOT SOLVED, NOT FIXED" :
+ "NOT SOLVED");
+
+ counter_last = -1;
+ }
+}
+
+static void PrintTapeReplaySummary(struct AutoPlayInfo *autoplay)
+{
+ char *autoplay_status =
+ (autoplay->num_levels_played == autoplay->num_levels_solved &&
+ autoplay->num_levels_played > 0 ? " OK " : "WARN");
+ int autoplay_percent =
+ (autoplay->num_levels_played ?
+ autoplay->num_levels_solved * 100 / autoplay->num_levels_played : 0);
+ int i;
+
+ Print("\n");
+ PrintLine("=", 79);
+ Print("Number of levels played: %d\n", autoplay->num_levels_played);
+ Print("Number of levels solved: %d (%d%%)\n", autoplay->num_levels_solved,
+ (autoplay->num_levels_played ?
+ autoplay->num_levels_solved * 100 / autoplay->num_levels_played : 0));
+ if (global.autoplay_mode == AUTOPLAY_MODE_FIX)
+ Print("Number of tapes fixed: %d\n", autoplay->num_tapes_patched);
+ PrintLine("-", 79);
+ Print("Summary (for automatic parsing by scripts):\n");
+
+ if (autoplay->tape_filename)
+ {
+ Print("TAPEFILE [%s] '%s', %d, %d, %d",
+ autoplay_status,
+ autoplay->leveldir->identifier,
+ autoplay->last_level_nr,
+ game.score_final,
+ game.score_time_final);
+ }
+ else
+ {
+ Print("LEVELDIR [%s] '%s', SOLVED %d/%d (%d%%)",
+ autoplay_status,
+ autoplay->leveldir->identifier,
+ autoplay->num_levels_solved,
+ autoplay->num_levels_played,
+ autoplay_percent);
+
+ if (autoplay->num_levels_played != autoplay->num_levels_solved)
+ {
+ Print(", FAILED:");
+ for (i = 0; i < MAX_TAPES_PER_SET; i++)
+ if (autoplay->level_failed[i])
+ Print(" %03d", i);
+ }
+ }
+
+ Print("\n");
+ PrintLine("=", 79);
+}
+
+static FILE *tape_log_file;
+
+static void OpenTapeLogfile(void)
+{
+ if (!(tape_log_file = fopen(options.tape_log_filename, MODE_WRITE)))
+ Warn("cannot write tape logfile '%s'", options.tape_log_filename);
+}
+
+static void WriteTapeLogfile(byte action[MAX_TAPE_ACTIONS])
+{
+ int i;
+
+ for (i = 0; i < MAX_TAPE_ACTIONS; i++)
+ putFile8Bit(tape_log_file, action[i]);
+}
+
+static void CloseTapeLogfile(void)
+{
+ fclose(tape_log_file);
+}
+
+
+// ============================================================================
+// tape control functions
+// ============================================================================