X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Ftape.c;h=f16e7ec9451a20ab68068add00155ed01870088a;hp=69356b0bfcf5b0e1a45eda034a16818197ef9a55;hb=HEAD;hpb=431e165c85738667ec2bd03e3020d6c4e410d6e4 diff --git a/src/tape.c b/src/tape.c index 69356b0b..f16e7ec9 100644 --- a/src/tape.c +++ b/src/tape.c @@ -18,6 +18,8 @@ #include "files.h" #include "network.h" #include "anim.h" +#include "api.h" + #define DEBUG_TAPE_WHEN_PLAYING FALSE @@ -662,6 +664,7 @@ void TapeErase(void) tape.level_nr = level_nr; tape.pos[tape.counter].delay = 0; tape.changed = TRUE; + tape.solved = FALSE; tape.random_seed = InitRND(level.random_seed); @@ -758,6 +761,7 @@ static void TapeAppendRecording(void) // start recording tape.recording = TRUE; tape.changed = TRUE; + tape.solved = FALSE; // set current delay (for last played move) tape.pos[tape.counter].delay = tape.delay_played; @@ -775,7 +779,9 @@ static void TapeAppendRecording(void) void TapeHaltRecording(void) { - tape.counter++; + // only advance tape counter if any input events have been recorded + if (tape.pos[tape.counter].delay > 0) + tape.counter++; // initialize delay for next tape entry (to be able to continue recording) if (tape.counter < MAX_TAPE_LEN) @@ -830,6 +836,8 @@ boolean TapeAddAction(byte action[MAX_TAPE_ACTIONS]) tape.pos[tape.counter].delay++; } + tape.changed = TRUE; + return TRUE; } @@ -928,6 +936,10 @@ void TapeTogglePause(boolean toggle_mode) ModifyPauseButtons(); } + + // stop tape when leaving auto-pause after completely replaying tape + if (tape.playing && !tape.pausing && tape.counter >= tape.length) + TapeStop(); } void TapeStartPlaying(void) @@ -985,21 +997,27 @@ byte *TapePlayAction(void) if (tape.pause_before_end) // stop some seconds before end of tape { - if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH) + if (TapeTime > (int)tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH) { TapeStopWarpForward(); TapeTogglePause(TAPE_TOGGLE_MANUAL); + if (setup.autorecord_after_replay) + TapeAppendRecording(); + return NULL; } } if (tape.counter >= tape.length) // end of tape reached { - if (tape.warp_forward && !tape.auto_play) + if (!tape.auto_play) { TapeStopWarpForward(); TapeTogglePause(TAPE_TOGGLE_MANUAL); + + if (setup.autorecord_after_replay) + TapeAppendRecording(); } else { @@ -1088,6 +1106,27 @@ void TapeStop(void) } } +static void TapeStopGameOrTape(boolean stop_game) +{ + if (score_info_tape_play || (!tape.playing && stop_game)) + RequestQuitGame(FALSE); + else + TapeStop(); +} + +void TapeStopGame(void) +{ + if (game_status == GAME_MODE_MAIN) + return; + + TapeStopGameOrTape(TRUE); +} + +void TapeStopTape(void) +{ + TapeStopGameOrTape(FALSE); +} + unsigned int GetTapeLengthFrames(void) { unsigned int tape_length_frames = 0; @@ -1154,22 +1193,25 @@ static void TapeSingleStep(void) void TapeQuickSave(void) { - if (game_status == GAME_MODE_MAIN) + if (game_status != GAME_MODE_PLAYING) { - Request("No game that can be saved!", REQ_CONFIRM); + Request("No game that could be saved!", REQ_CONFIRM); return; } - if (game_status != GAME_MODE_PLAYING) + if (!tape.recording) + { + Request("No recording that could be saved!", REQ_CONFIRM); + return; + } - if (tape.recording) - TapeHaltRecording(); // prepare tape for saving on-the-fly + TapeHaltRecording(); // prepare tape for saving on-the-fly if (TAPE_IS_EMPTY(tape)) { - Request("No tape that can be saved!", REQ_CONFIRM); + Request("No tape that could be saved!", REQ_CONFIRM); return; } @@ -1244,6 +1286,69 @@ void TapeQuickLoad(void) } } +static boolean checkRestartGame(char *message) +{ + if (game_status == GAME_MODE_MAIN) + return TRUE; + + if (!hasStartedNetworkGame()) + return FALSE; + + if (level_editor_test_game) + return TRUE; + + if (game.all_players_gone) + return TRUE; + + if (!setup.ask_on_quit_game) + return TRUE; + + if (Request(message, REQ_ASK | REQ_STAY_CLOSED)) + return TRUE; + + OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); + + return FALSE; +} + +void TapeRestartGame(void) +{ + if (score_info_tape_play) + { + TapeStartGamePlaying(); + + return; + } + + if (!checkRestartGame("Restart game?")) + return; + + StartGameActions(network.enabled, setup.autorecord, level.random_seed); +} + +void TapeReplayAndPauseBeforeEnd(void) +{ + if (score_info_tape_play) + return; + + if (TAPE_IS_EMPTY(tape) && !tape.recording) + { + Request("No tape for this level!", REQ_CONFIRM); + + return; + } + + if (!checkRestartGame("Replay game and pause before end?")) + return; + + TapeStop(); + TapeStartGamePlaying(); + TapeStartWarpForward(AUTOPLAY_MODE_WARP_NO_DISPLAY); + + tape.pause_before_end = TRUE; + tape.quick_resume = TRUE; +} + boolean hasSolutionTape(void) { boolean tape_file_exists = fileExists(getSolutionTapeFilename(level_nr)); @@ -1292,6 +1397,93 @@ boolean PlaySolutionTape(void) return TRUE; } +static boolean PlayScoreTape_WaitForDownload(void) +{ + DelayCounter download_delay = { 10000 }; + + ResetDelayCounter(&download_delay); + + // wait for score tape to be successfully downloaded (and fail on timeout) + while (!server_scores.tape_downloaded) + { + if (DelayReached(&download_delay)) + return FALSE; + + UPDATE_BUSY_STATE_NOT_LOADING(); + + Delay(20); + } + + return TRUE; +} + +boolean PlayScoreTape(int entry_nr) +{ + struct ScoreEntry *entry = &scores.entry[entry_nr]; + char *tape_filename = + (entry->id == -1 ? + getScoreTapeFilename(entry->tape_basename, level_nr) : + getScoreCacheTapeFilename(entry->tape_basename, level_nr)); + boolean download_tape = (!fileExists(tape_filename)); + + if (download_tape && entry->id == -1) + { + FadeSkipNextFadeIn(); + + Request("Cannot find score tape!", REQ_CONFIRM); + + return FALSE; + } + + server_scores.tape_downloaded = FALSE; + + if (download_tape) + ApiGetScoreTapeAsThread(level_nr, entry->id, entry->tape_basename); + + SetGameStatus(GAME_MODE_PLAYING); + + FadeOut(REDRAW_FIELD); + + if (download_tape && !PlayScoreTape_WaitForDownload()) + { + SetGameStatus(GAME_MODE_SCOREINFO); + ClearField(); + + Request("Cannot download score tape from score server!", REQ_CONFIRM); + + return FALSE; + } + + if (!TAPE_IS_STOPPED(tape)) + TapeStop(); + + // if tape recorder already contains a tape, remove it without asking + TapeErase(); + + if (entry->id == -1) + LoadScoreTape(entry->tape_basename, level_nr); + else + LoadScoreCacheTape(entry->tape_basename, level_nr); + + if (TAPE_IS_EMPTY(tape)) + { + SetGameStatus(GAME_MODE_SCOREINFO); + ClearField(); + + Request("Cannot load score tape for this level!", REQ_CONFIRM); + + return FALSE; + } + + FadeSkipNextFadeOut(); + + TapeStartGamePlaying(); + + score_info_tape_play = TRUE; + + return TRUE; +} + static boolean checkTapesFromSameLevel(struct TapeInfo *t1, struct TapeInfo *t2) { return (strEqual(t1->level_identifier, t2->level_identifier) && @@ -1381,8 +1573,10 @@ static TreeInfo *getFirstValidAutoPlayEntry(TreeInfo *node) static void AutoPlayTapes_SetScoreEntry(int score, int time) { + char *name = (options.mytapes ? setup.player_name : options.player_name); + // set unique basename for score tape (for uploading to score server) - strcpy(tape.score_tape_basename, getScoreTapeBasename(setup.player_name)); + strcpy(tape.score_tape_basename, getScoreTapeBasename(name)); // store score in first score entry scores.last_added = 0; @@ -1400,22 +1594,24 @@ static void AutoPlayTapes_SetScoreEntry(int score, int time) server_scores.uploaded = FALSE; } -static void AutoPlayTapes_WaitForUpload(void) +static boolean AutoPlayTapes_WaitForUpload(void) { - unsigned int upload_delay = 0; - unsigned int upload_delay_value = 10000; + DelayCounter upload_delay = { 10000 }; ResetDelayCounter(&upload_delay); // wait for score tape to be successfully uploaded (and fail on timeout) while (!server_scores.uploaded) { - if (DelayReached(&upload_delay, upload_delay_value)) + if (DelayReached(&upload_delay)) { PrintNoLog("\r"); Print("- uploading score tape to score server - TIMEOUT.\n"); - Fail("cannot upload score tape to score server"); + if (program.headless) + Fail("cannot upload score tape to score server"); + + return FALSE; } UPDATE_BUSY_STATE(); @@ -1425,6 +1621,8 @@ static void AutoPlayTapes_WaitForUpload(void) PrintNoLog("\r"); Print("- uploading score tape to score server - uploaded.\n"); + + return TRUE; } static int AutoPlayTapesExt(boolean initialize) @@ -1464,7 +1662,9 @@ static int AutoPlayTapesExt(boolean initialize) -1 }; + LevelDirTree *leveldir_current_last = leveldir_current; boolean init_level_set = FALSE; + int level_nr_last = level_nr; int i; if (!initialize) @@ -1533,7 +1733,7 @@ static int AutoPlayTapesExt(boolean initialize) // * solution tape may have native format (like Supaplex solution files) SaveScoreTape(level_nr); - SaveServerScore(level_nr); + SaveServerScore(level_nr, TRUE); AutoPlayTapes_WaitForUpload(); } @@ -1587,15 +1787,25 @@ static int AutoPlayTapesExt(boolean initialize) if (tape.no_valid_file) Fail("cannot load tape file '%s'", autoplay.tape_filename); - if (tape.no_info_chunk) + if (tape.no_info_chunk && !options.identifier) Fail("cannot get levelset from tape file '%s'", autoplay.tape_filename); + if (tape.no_info_chunk && !options.level_nr) + Fail("cannot get level nr from tape file '%s'", autoplay.tape_filename); + global.autoplay_leveldir = tape.level_identifier; + if (options.identifier != NULL) + global.autoplay_leveldir = options.identifier; + + if (options.level_nr != NULL) + tape.level_nr = atoi(options.level_nr); + if (tape.level_nr >= 0 && tape.level_nr < MAX_TAPES_PER_SET) global.autoplay_level[tape.level_nr] = TRUE; global.autoplay_all = FALSE; + options.mytapes = FALSE; } if (autoplay.all_levelsets) @@ -1651,6 +1861,41 @@ static int AutoPlayTapesExt(boolean initialize) init_level_set = FALSE; } + if (autoplay.all_levelsets && global.autoplay_mode == AUTOPLAY_MODE_UPLOAD) + { + boolean skip_levelset = FALSE; + + if (!directoryExists(getTapeDir(autoplay.leveldir->subdir))) + { + Print("No tape directory for this level set found -- skipping.\n"); + + skip_levelset = TRUE; + } + + if (CheckTapeDirectoryUploadsComplete(autoplay.leveldir->subdir)) + { + Print("All tapes for this level set already uploaded -- skipping.\n"); + + skip_levelset = TRUE; + } + + if (skip_levelset) + { + PrintTapeReplaySummary(&autoplay); + + // continue with next level set + autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir); + + // all level sets processed + if (autoplay.leveldir == NULL) + break; + + init_level_set = TRUE; + + continue; + } + } + if (global.autoplay_mode != AUTOPLAY_MODE_FIX || patch_nr == 0) level_nr = autoplay.level_nr++; @@ -1664,6 +1909,9 @@ static int AutoPlayTapesExt(boolean initialize) if (!autoplay.all_levelsets) break; + if (global.autoplay_mode == AUTOPLAY_MODE_UPLOAD) + MarkTapeDirectoryUploadsAsComplete(autoplay.leveldir->subdir); + // continue with next level set autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir); @@ -1685,6 +1933,16 @@ static int AutoPlayTapesExt(boolean initialize) if (!global.autoplay_all && !global.autoplay_level[level_nr]) continue; + // speed things up in case of missing private tapes (skip loading level) + if (options.mytapes && !fileExists(getTapeFilename(level_nr))) + { + autoplay.num_tape_missing++; + + Print("Tape %03d: (no tape found)\n", level_nr); + + continue; + } + TapeErase(); TapeRewind(); // needed to reset "tape.auto_play_level_solved" @@ -1791,19 +2049,7 @@ static int AutoPlayTapesExt(boolean initialize) autoplay.tape_filename = (options.mytapes ? getTapeFilename(level_nr) : getDefaultSolutionTapeFilename(level_nr)); - boolean correct_info_chunk = - (strEqual(leveldir_current->identifier, tape.level_identifier) && - level_nr == tape.level_nr); - - if (!correct_info_chunk) - { - strncpy(tape.level_identifier, leveldir_current->identifier, - MAX_FILENAME_LEN); - tape.level_identifier[MAX_FILENAME_LEN] = '\0'; - tape.level_nr = level_nr; - } - - if (!fileExists(autoplay.tape_filename) || !correct_info_chunk) + if (!fileExists(autoplay.tape_filename)) { // non-standard or incorrect solution tape -- save to temporary file autoplay.tape_filename = getTemporaryTapeFilename(); @@ -1814,9 +2060,9 @@ static int AutoPlayTapesExt(boolean initialize) } } - SaveServerScoreFromFile(level_nr, autoplay.tape_filename); + SaveServerScoreFromFile(level_nr, TRUE, autoplay.tape_filename); - AutoPlayTapes_WaitForUpload(); + boolean success = AutoPlayTapes_WaitForUpload(); if (use_temporary_tape_file) unlink(autoplay.tape_filename); @@ -1824,6 +2070,13 @@ static int AutoPlayTapesExt(boolean initialize) // required for uploading multiple tapes autoplay.tape_filename = NULL; + if (!success) + { + num_tapes = -num_tapes; + + break; + } + continue; } @@ -1840,12 +2093,30 @@ static int AutoPlayTapesExt(boolean initialize) return num_tapes; } + if (global.autoplay_mode == AUTOPLAY_MODE_UPLOAD) + { + Print("\n"); + PrintLine("=", 79); + + if (num_tapes >= 0) + Print("SUMMARY: %d tapes uploaded.\n", num_tapes); + else + Print("SUMMARY: Uploading tapes failed.\n"); + + PrintLine("=", 79); + } + // clear timestamp for batch tape upload (required after interactive upload) global.autoplay_time = 0; - if (program.headless) + // exit if running headless or if visually auto-playing tapes + if (program.headless || global.autoplay_mode != AUTOPLAY_MODE_UPLOAD) CloseAllAndExit(0); + // when running interactively, restore last selected level set and number + leveldir_current = leveldir_current_last; + level_nr = level_nr_last; + return num_tapes; } @@ -2260,7 +2531,7 @@ static void HandleTapeButtonsExt(int id) break; case TAPE_CTRL_ID_STOP: - TapeStop(); + TapeStopTape(); break;