diff --git a/src/d_main.cpp b/src/d_main.cpp index 697ee1dbe..ba9b0b201 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1935,7 +1935,7 @@ void D_SRB2Main(void) } else if (M_CheckParm("-record") && M_IsNextParm()) { - G_RecordDemo(M_GetNextParm()); + G_RecordDemo(va("%s.lmp", M_GetNextParm())); autostart = true; } diff --git a/src/g_demo.c b/src/g_demo.c index 0c38997cd..c0a44cf1a 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2719,7 +2719,6 @@ void G_RecordDemo(const char *name) INT32 maxsize; strcpy(demoname, name); - strcat(demoname, ".lmp"); maxsize = 1024 * 1024 * cv_netdemosize.value; P_SaveBufferAlloc(&demobuf, maxsize); diff --git a/src/g_game.c b/src/g_game.c index 798899279..56d129986 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -740,6 +740,41 @@ boolean G_EmblemsEnabled(void) return !demo.playback && !strcmp(currentrecordpreset, "kart"); } +char *G_GetRecordReplayFolder(boolean home, boolean breaker) +{ + return xva("%s%smedia"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", + home ? srb2home : "", + home ? PATHSEP : "", + breaker ? "itembreaker" : "timeattack", + currentrecordpreset + ); +} + +const char *tasuffixes[] = { + [TA_TIMEBEST] = "time-best", + [TA_LAPBEST] = "lap-best", + [TA_LAST] = "last", + [TA_GUEST] = "guest", +}; + +char *G_GetRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which) +{ + const char *map = G_BuildMapName(mapnum), *suf = tasuffixes[which]; + if (which != TA_GUEST) + return xva("%s"PATHSEP"%s-%s-%s.lmp", folder, map, skins[skinnum].name, suf); + else + return xva("%s"PATHSEP"%s-%s.lmp", folder, map, suf); +} + +boolean G_CheckRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which) +{ + const char *map = G_BuildMapName(mapnum), *suf = tasuffixes[which]; + if (which != TA_GUEST) + return FIL_FileExists(va("%s"PATHSEP"%s-%s-%s.lmp", folder, map, skins[skinnum].name, suf)); + else + return FIL_FileExists(va("%s"PATHSEP"%s-%s.lmp", folder, map, suf)); +} + // // G_UpdateRecordReplays // @@ -747,11 +782,8 @@ boolean G_EmblemsEnabled(void) // static void G_UpdateRecordReplays(void) { - char *gpath; - char *gamemode = M_AppendGametypeAndModName(); - char lastdemo[256], bestdemo[256]; + CLEANUP(pfree) char *gpath = NULL, *lastdemo = NULL; UINT8 earnedEmblems; - int parts; // Record new best time maprecord_t *record = G_AllocateMapRecord(G_BuildMapName(gamemap)); @@ -779,24 +811,20 @@ static void G_UpdateRecordReplays(void) } // Save demo! - bestdemo[255] = '\0'; - lastdemo[255] = '\0'; G_SetDemoTime(players[consoleplayer].realtime, bestlap); G_CheckDemoStatus(); - gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", - srb2home, timeattackfolder, G_BuildMapName(gamemap)); - parts = M_PathParts(gpath); - M_MkdirEachUntil(gpath, parts - 4, parts - 1, 0755); + gpath = G_GetRecordReplayFolder(true, modeattacking == ATTACKING_ITEMBREAK); + M_MkdirEach(gpath, M_PathParts(gpath) - 4, 0755); - snprintf(lastdemo, 255, "%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); + lastdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_LAST); if (FIL_FileExists(lastdemo)) { UINT8 *buf; size_t len = FIL_ReadFile(lastdemo, &buf); - snprintf(bestdemo, 255, "%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); + CLEANUP(pfree) char *bestdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_TIMEBEST); if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) { // Better time, save this demo. if (FIL_FileExists(bestdemo)) @@ -807,7 +835,8 @@ static void G_UpdateRecordReplays(void) if (modeattacking == ATTACKING_TIME) { - snprintf(bestdemo, 255, "%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); + free(bestdemo); + bestdemo = G_GetRecordReplay(gpath, gamemap, cv_chooseskin.value, TA_LAPBEST); if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) { // Better lap time, save this demo. if (FIL_FileExists(bestdemo)) @@ -822,9 +851,6 @@ static void G_UpdateRecordReplays(void) Z_Free(buf); } - free(gpath); - Z_Free(gamemode); - // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems())) CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); diff --git a/src/g_game.h b/src/g_game.h index 1552ce7e4..f883a5e54 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -312,6 +312,15 @@ typedef struct maprecordpreset_t *presets; } maprecord_t; +typedef enum +{ + TA_TIMEBEST, + TA_LAPBEST, + TA_LAST, + TA_GUEST, + TA__MAX, +} timeattackreplay_e; + extern maprecord_t **maprecords; extern size_t nummaprecords; @@ -320,8 +329,11 @@ maprecord_t *G_GetMapRecord(const char *mapname); maprecordpreset_t *G_AllocateMapRecordPreset(maprecord_t *record, const char *presetname, UINT8 version); maprecordpreset_t *G_GetMapRecordPreset(maprecord_t *record, const char *presetname); void G_ClearRecords(void); -boolean G_EmblemsEnabled(void); tic_t G_GetBestTime(INT16 map); +boolean G_EmblemsEnabled(void); +char *G_GetRecordReplayFolder(boolean home, boolean breaker); +char *G_GetRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which); +boolean G_CheckRecordReplay(const char *folder, UINT16 mapnum, UINT16 skinnum, timeattackreplay_e which); FUNCMATH INT32 G_TicsToHours(tic_t tics); FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full); diff --git a/src/m_menu.c b/src/m_menu.c index 065a83e04..f1c490947 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -652,37 +652,6 @@ if (cv.value >= num) \ strcat(new_str, str); \ } -char *M_AppendGametypeAndModName(void) -{ - UINT8 len = 4; - char *new_str; - - new_str = Z_Malloc(4, PU_STATIC, NULL); - - if ((!Playing() && (levellistmode == LLM_ITEMBREAKER)) || (modeattacking & ATTACKING_ITEMBREAK)) - { - strcpy(new_str, "IB-"); - } - else - { - strcpy(new_str, "RA-"); - } - - ADD(cv_dummyattackingrings, "RN-") - ADD(cv_dummyattackingstacking, "ST-") - ADD(cv_dummyattackingchaining, "CH-") - ADD(cv_dummyattackingslipdash, "SD-") - ADD(cv_dummyattackingpurpledrift, "PD-") - ADD(cv_dummyattackingslopeboost, "SB-") - ADD(cv_dummyattackingairdrop, "AD-") - ADDEQUALS(cv_dummyattackingbumpspark, "BD-", BUMPSPARK_NOCHARGE) - ADDGE(cv_dummyattackingbumpspark, "BS-", BUMPSPARK_RESET100) - - new_str[len-1] = '\0'; - - return new_str; -} - // Nextmap. Used for Time Attack. void Nextmap_OnChange(void) { @@ -722,35 +691,34 @@ void Nextmap_OnChange(void) if (menustack[0] == MN_SP_TIMEATTACK || menustack[0] == MN_SP_MODS || menustack[0] == MN_SP_PRES) { // see also p_setup.c's P_LoadRecordGhosts - char *gamemode = M_AppendGametypeAndModName(); - char *gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER); boolean visible; boolean showreplay = false, showguest = false; // best time - visible = FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); + visible = G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_TIMEBEST); M_SetItemVisible(MN_SP_REPLAY, "REPLAYTIME", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVETIME", visible); if (visible) showreplay = showguest = true; // best lap - visible = levellistmode != LLM_ITEMBREAKER && FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); + visible = levellistmode != LLM_ITEMBREAKER && G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAPBEST); M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAP", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAP", visible); if (visible) showreplay = showguest = true; // last - visible = FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); + visible = G_CheckRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAST); M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAST", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAST", visible); if (visible) showreplay = showguest = true; // guest - visible = FIL_FileExists(va("%s-%s-guest.lmp", gpath, gamemode)); + visible = G_CheckRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST);; M_SetItemVisible(MN_SP_REPLAY, "REPLAYGUEST", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "DELETE", visible); M_SetItemVisible(MN_SP_GHOST, "GUEST", visible); @@ -771,9 +739,6 @@ void Nextmap_OnChange(void) M_SetItemVisible(MN_SP_TIMEATTACK, "REPLAY", showreplay); M_SetItemVisible(MN_SP_TIMEATTACK, "GUEST", showguest); - - free(gpath); - Z_Free(gamemode); } } @@ -5825,32 +5790,22 @@ INT32 MR_QuitTimeAttackMenu(INT32 choice) // Player has selected the "START" from the time attack screen INT32 MR_ChooseTimeAttack(INT32 choice) { - char *gpath; - char *gamemode = M_AppendGametypeAndModName(); - char nameofdemo[256]; + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER); + CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, TA_LAST); + (void)choice; emeralds = 0; M_ClearMenus(true); modeattacking = (levellistmode == LLM_ITEMBREAKER ? ATTACKING_ITEMBREAK : ATTACKING_TIME); - - gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s", - srb2home, timeattackfolder); - M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755); - - strcat(gpath, PATHSEP); - strcat(gpath, G_BuildMapName(cv_nextmap.value)); - - snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-%s-last", gpath, cv_skin[0].string, gamemode); - - Z_Free(gamemode); + M_MkdirEach(gpath, M_PathParts(gpath) - 4, 0755); if (!cv_autorecord.value) - remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); + remove(demopath); else - G_RecordDemo(nameofdemo); + G_RecordDemo(demopath); G_SetPresetCvars(G_GetRecordPresetVersion(currentrecordpreset, currentrecordpresetversion)); - G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value), 0, false); + G_DeferedInitNew(false, cv_nextmap.value, cv_chooseskin.value, 0, false); return true; } @@ -5886,36 +5841,19 @@ INT32 MR_TimeAttackPreset(INT32 arg) // Player has selected the "REPLAY" from the time attack screen INT32 MR_ReplayTimeAttack(INT32 arg) { - const char *which; - char *gamemode = M_AppendGametypeAndModName(); + if (arg < 0 || arg >= TA__MAX) + return false; - switch(arg) { - default: - case 0: // best time - which = "time-best"; - break; - case 1: // best lap - which = "lap-best"; - break; - case 2: // last - which = "last"; - break; - case 3: // guest - // srb2/replay/main/map01-guest.lmp - COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode)); - Z_Free(gamemode); - return true; - } - // srb2/replay/main/map01-sonic-time-best.lmp - COM_BufAddText(va("playdemo media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp -force", timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode, which)); - Z_Free(gamemode); + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(false, levellistmode == LLM_ITEMBREAKER); + CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, arg); + COM_BufAddText(va("playdemo %s -force", demopath)); return true; } static void M_EraseGuest(INT32 choice) { - char *gamemode = M_AppendGametypeAndModName(); - const char *rguest = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode); + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER); + CLEANUP(pfree) char *rguest = G_GetRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST); (void)choice; if (FIL_FileExists(rguest)) remove(rguest); @@ -5923,16 +5861,15 @@ static void M_EraseGuest(INT32 choice) CV_AddValue(&cv_nextmap, -1); CV_AddValue(&cv_nextmap, 1); M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); - Z_Free(gamemode); } -static void M_OverwriteGuest(const char *which) +static void M_OverwriteGuest(timeattackreplay_e which) { - char *gamemode = M_AppendGametypeAndModName(); - char *rguest = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode)); + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER); + CLEANUP(pfree) char *rguest = G_GetRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST); + CLEANUP(pfree) char *overwrite = G_GetRecordReplay(gpath, cv_nextmap.value, cv_chooseskin.value, which); UINT8 *buf; - size_t len; - len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode,which), &buf); + size_t len = FIL_ReadFile(overwrite, &buf); if (!len) { return; } @@ -5941,30 +5878,28 @@ static void M_OverwriteGuest(const char *which) remove(rguest); } FIL_WriteFile(rguest, buf, len); - Z_Free(rguest); M_ExitMenu(); CV_AddValue(&cv_nextmap, -1); CV_AddValue(&cv_nextmap, 1); M_StartMessage(M_GetText("Guest replay data saved.\n"),NULL,MM_NOTHING); - Z_Free(gamemode); } static void M_OverwriteGuest_Time(INT32 choice) { (void)choice; - M_OverwriteGuest("time-best"); + M_OverwriteGuest(TA_TIMEBEST); } static void M_OverwriteGuest_Lap(INT32 choice) { (void)choice; - M_OverwriteGuest("lap-best"); + M_OverwriteGuest(TA_LAPBEST); } static void M_OverwriteGuest_Last(INT32 choice) { (void)choice; - M_OverwriteGuest("last"); + M_OverwriteGuest(TA_LAST); } INT32 MR_SetGuestReplay(INT32 arg) @@ -5986,7 +5921,8 @@ INT32 MR_SetGuestReplay(INT32 arg) M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"), M_EraseGuest, MM_YESNO); return true; } - if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, levellistmode == LLM_ITEMBREAKER); + if (G_CheckRecordReplay(gpath, cv_nextmap.value, UINT16_MAX, TA_GUEST)) M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"), which, MM_YESNO); else which(0); diff --git a/src/p_setup.c b/src/p_setup.c index 6307f949c..c913c10be 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8247,61 +8247,39 @@ static void P_ResetSpawnpoints(void) skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; } +static void P_TryAddGhosts(const char *gpath, boolean all, timeattackreplay_e which) +{ + for (INT32 i = 0; i < numskins; i++) + { + if (!all && players[consoleplayer].skin != i) + continue; + + CLEANUP(pfree) char *demopath = G_GetRecordReplay(gpath, gamemap, i, which); + if (FIL_FileExists(demopath)) + G_AddGhost(demopath); + } +} + static void P_LoadRecordGhosts(void) { - // see also m_menu.c's Nextmap_OnChange - char *gpath; - INT32 i; - char *gamemode = M_AppendGametypeAndModName(); - - gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + CLEANUP(pfree) char *gpath = G_GetRecordReplayFolder(true, modeattacking == ATTACKING_ITEMBREAK); // Best Time ghost if (cv_ghost_besttime.value) - { - for (i = 0; i < numskins; ++i) - { - if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) - continue; - - if (FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, skins[i].name, gamemode))) - G_AddGhost(va("%s-%s-%s-time-best.lmp", gpath, skins[i].name, gamemode)); - } - } + P_TryAddGhosts(gpath, cv_ghost_besttime.value != 1, TA_TIMEBEST); // Best Lap ghost - if (modeattacking != ATTACKING_ITEMBREAK) - { - if (cv_ghost_bestlap.value) - { - for (i = 0; i < numskins; ++i) - { - if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i) - continue; - - if (FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, skins[i].name, gamemode))) - G_AddGhost(va("%s-%s-%s-lap-best.lmp", gpath, skins[i].name, gamemode)); - } - } - } + if (modeattacking != ATTACKING_ITEMBREAK && cv_ghost_bestlap.value) + P_TryAddGhosts(gpath, cv_ghost_bestlap.value != 1, TA_LAPBEST); // Last ghost if (cv_ghost_last.value) - { - for (i = 0; i < numskins; ++i) - { - if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i) - continue; - - if (FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, skins[i].name, gamemode))) - G_AddGhost(va("%s-%s-%s-last.lmp", gpath, skins[i].name, gamemode)); - } - } + P_TryAddGhosts(gpath, cv_ghost_last.value != 1, TA_LAST); // Guest ghost - if (cv_ghost_guest.value && FIL_FileExists(va("%s-%s-guest.lmp", gpath, gamemode))) - G_AddGhost(va("%s-guest.lmp", gpath)); + if (cv_ghost_guest.value) + P_TryAddGhosts(gpath, false, TA_GUEST); // Staff Attack ghosts if (cv_ghost_staff.value) @@ -8315,9 +8293,6 @@ static void P_LoadRecordGhosts(void) j++; } } - - free(gpath); - Z_Free(gamemode); } static void P_SetupCamera(UINT8 pnum, camera_t *cam) @@ -8466,7 +8441,7 @@ static void P_InitGametype(void) #else strcpy(ver, VERSIONSTRING); #endif - snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s", + snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s.lmp", srb2home, ver, (int) (time(NULL)), G_BuildMapName(gamemap)); parts = M_PathParts(buf); diff --git a/src/z_zone.h b/src/z_zone.h index 1876fa0be..f989ccd27 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -16,6 +16,7 @@ #include #include "doomtype.h" +#include "doomdef.h" #ifdef __cplusplus extern "C" { @@ -153,6 +154,11 @@ FUNCINLINE static ATTRINLINE void Z_Pfree(void *p) Z_Free(*(void **)p); } +FUNCINLINE static ATTRINLINE void pfree(void *p) +{ + free(*(void **)p); +} + #ifdef __cplusplus } // extern "C" #endif