diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 768c461de..cc16907fa 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2014,7 +2014,8 @@ Command_LeaveParty_f (void) // UINT8 *demofile; // demo file buffer static void Command_Playdemo_f(void) { - char name[256]; + const char *arg1 = NULL; + menudemo_t menudemo = {0}; if (COM_Argc() < 2) { @@ -2033,30 +2034,44 @@ static void Command_Playdemo_f(void) return; } + arg1 = COM_Argv(1); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(arg1)) + { + // External demos must be checked first + sprintf(menudemo.filepath, "%s" PATHSEP "%s", srb2home, arg1); + G_LoadDemoInfo(&menudemo, /*allownonmultiplayer*/ true); + + if (menudemo.type != MD_LOADED) + { + // Do nothing because the demo can't be played + CONS_Alert(CONS_ERROR, "Unable to playdemo %s", menudemo.filepath); + return; + } + } + else + { + strlcpy(menudemo.filepath, arg1, sizeof(menudemo.filepath)); + } + // disconnect from server here? if (demo.playback) G_StopDemo(); - // open the demo file - strcpy(name, COM_Argv(1)); - // dont add .lmp so internal game demos can be played - - CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name); + CONS_Printf(M_GetText("Playing back demo '%s'.\n"), menudemo.filepath); demo.loadfiles = strcmp(COM_Argv(2), "-addfiles") == 0; demo.ignorefiles = strcmp(COM_Argv(2), "-force") == 0; - // Internal if no extension, external if one exists - // If external, convert the file name to a path in SRB2's home directory - if (FIL_CheckExtension(name)) - G_DoPlayDemo(va("%s"PATHSEP"%s", srb2home, name)); - else - G_DoPlayDemo(name); + G_DoPlayDemo(menudemo.filepath); } static void Command_Timedemo_f(void) { size_t i = 0; + const char *arg1 = NULL; + menudemo_t menudemo = {0}; if (COM_Argc() < 2) { @@ -2070,14 +2085,33 @@ static void Command_Timedemo_f(void) return; } + arg1 = COM_Argv(1); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(arg1)) + { + // External demos must be checked first + sprintf(menudemo.filepath, "%s" PATHSEP "%s", srb2home, arg1); + G_LoadDemoInfo(&menudemo, /*allownonmultiplayer*/ true); + + if (menudemo.type != MD_LOADED) + { + // Do nothing because the demo can't be played + CONS_Alert(CONS_ERROR, "Unable to timedemo %s", menudemo.filepath); + return; + } + + strlcpy(timedemo_name, menudemo.filepath, sizeof(timedemo_name)); + } + else + { + strlcpy(timedemo_name, arg1, sizeof(timedemo_name)); + } + // disconnect from server here? if (demo.playback) G_StopDemo(); - // open the demo file - strcpy (timedemo_name, COM_Argv(1)); - // dont add .lmp so internal game demos can be played - // print timedemo results as CSV? i = COM_CheckParm("-csv"); timedemo_csv = (i > 0); diff --git a/src/g_demo.cpp b/src/g_demo.cpp index d6d18b33c..eac0b1989 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -2564,7 +2564,7 @@ static bool load_ubjson_standing(menudemo_t* pdemo, tcb::span slice, return true; } -void G_LoadDemoInfo(menudemo_t *pdemo) +void G_LoadDemoInfo(menudemo_t *pdemo, boolean allownonmultiplayer) { savebuffer_t info = {0}; UINT8 *extrainfo_p; @@ -2653,7 +2653,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemoflags = READUINT16(info.p); // temp? - if (!(pdemoflags & DF_MULTIPLAYER)) + if (!(pdemoflags & DF_MULTIPLAYER) && !allownonmultiplayer) { CONS_Alert(CONS_ERROR, M_GetText("%s is not a multiplayer replay and can't be listed on this menu fully yet.\n"), pdemo->filepath); goto badreplay; @@ -2679,6 +2679,18 @@ void G_LoadDemoInfo(menudemo_t *pdemo) goto badreplay; } + if ((pdemoflags & DF_ATTACKMASK)) + { + if ((pdemoflags & ATTACKING_TIME)) + { + info.p += 4; // time + } + if ((pdemoflags & ATTACKING_LAP)) + { + info.p += 4; // lap + } + } + for (i = 0; i < PRNUMSYNCED; i++) { info.p += 4; // RNG seed diff --git a/src/g_demo.h b/src/g_demo.h index 4405589e1..4e89b24ef 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -227,7 +227,7 @@ void G_DoneLevelLoad(void); void G_StopDemo(void); boolean G_CheckDemoStatus(void); -void G_LoadDemoInfo(menudemo_t *pdemo); +void G_LoadDemoInfo(menudemo_t *pdemo, boolean allownonmultiplayer); void G_DeferedPlayDemo(const char *demo); void G_SaveDemo(void); diff --git a/src/g_game.c b/src/g_game.c index aa60e5b1d..976b18392 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1345,6 +1345,7 @@ boolean G_Responder(event_t *ev) { // stop the title demo G_CheckDemoStatus(); + demo.attract = DEMO_ATTRACT_OFF; return true; } } diff --git a/src/menus/class-egg-tv/EggTVData.cpp b/src/menus/class-egg-tv/EggTVData.cpp index f8fdd66c2..50c33f97b 100644 --- a/src/menus/class-egg-tv/EggTVData.cpp +++ b/src/menus/class-egg-tv/EggTVData.cpp @@ -216,7 +216,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref) std::copy_n(path.string().c_str(), path.native().size() + 1, info.filepath); - G_LoadDemoInfo(&info); + G_LoadDemoInfo(&info, /*allownonmultiplayer*/ false); if (info.type != MD_LOADED) { diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index c8395c26c..2db63ca73 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -8,6 +8,7 @@ #include "../v_video.h" #include "../d_main.h" // srb2home #include "../m_misc.h" // M_MkdirEach +#include "../s_sound.h" // S_StartSound #include "../z_zone.h" // Z_StrDup/Z_Free #include "../m_cond.h" @@ -433,14 +434,8 @@ void M_HandleStaffReplay(INT32 choice) void M_ReplayTimeAttack(INT32 choice) { - const char *which; - - restoreMenu = &PLAY_TimeAttackDef; - - M_ClearMenus(true); - demo.loadfiles = false; - demo.ignorefiles = true; // Just assume that record attack replays have the files needed - + menudemo_t menudemo = {0}; + const char *which = NULL; const char *modeprefix = ""; if (cv_dummyspbattack.value) @@ -459,11 +454,32 @@ void M_ReplayTimeAttack(INT32 choice) which = "last"; break; case tareplay_guest: - G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%sguest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), modeprefix)); - return; + sprintf(menudemo.filepath, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%sguest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), modeprefix); + break; } - G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s%s.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), cv_skin[0].string, modeprefix, which)); + if (which) + { + sprintf(menudemo.filepath, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s%s.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), cv_skin[0].string, modeprefix, which); + } + + G_LoadDemoInfo(&menudemo, /*allownonmultiplayer*/ true); + + if (menudemo.type != MD_LOADED || menudemo.addonstatus > 0) + { + // Do nothing because the demo can't be played + S_StartSound(NULL, sfx_tmxerr); + M_StartMessage("Invalid Replay", "Replay cannot be played on this version of the game", NULL, MM_NOTHING, NULL, "Back"); + return; + } + + restoreMenu = &PLAY_TimeAttackDef; + + M_ClearMenus(true); + demo.loadfiles = false; + demo.ignorefiles = true; // Just assume that record attack replays have the files needed + + G_DoPlayDemo(menudemo.filepath); } static const char *TA_GuestReplay_Str = NULL;