Merge branch 'na-char-replays' into 'next'

Add support for saving/loading per-skin NiGHTS replays

See merge request STJr/SRB2!1025
This commit is contained in:
SteelT 2020-07-03 14:51:05 -04:00
commit 186335c2ac
4 changed files with 99 additions and 26 deletions

View File

@ -720,14 +720,14 @@ void G_SetNightsRecords(void)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-last.lmp", gpath); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (FIL_FileExists(lastdemo)) if (FIL_FileExists(lastdemo))
{ {
UINT8 *buf; UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf); size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-time-best.lmp", gpath); snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);;
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo. { // Better time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -736,7 +736,7 @@ void G_SetNightsRecords(void)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
} }
snprintf(bestdemo, 255, "%s-score-best.lmp", gpath); snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo. { // Better score, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))

View File

@ -2276,6 +2276,9 @@ void Nextmap_OnChange(void)
{ {
char *leveltitle; char *leveltitle;
char tabase[256]; char tabase[256];
#ifdef OLDNREPLAYNAME
char tabaseold[256];
#endif
short i; short i;
boolean active; boolean active;
@ -2300,11 +2303,17 @@ void Nextmap_OnChange(void)
SP_NightsAttackMenu[naghost].status = IT_DISABLED; SP_NightsAttackMenu[naghost].status = IT_DISABLED;
// Check if file exists, if not, disable REPLAY option // Check if file exists, if not, disable REPLAY option
sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name);
#ifdef OLDNREPLAYNAME
sprintf(tabaseold,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
#endif
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
SP_NightsReplayMenu[i].status = IT_DISABLED; SP_NightsReplayMenu[i].status = IT_DISABLED;
SP_NightsGuestReplayMenu[i].status = IT_DISABLED; SP_NightsGuestReplayMenu[i].status = IT_DISABLED;
} }
if (FIL_FileExists(va("%s-score-best.lmp", tabase))) { if (FIL_FileExists(va("%s-score-best.lmp", tabase))) {
SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL; SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
@ -2320,16 +2329,37 @@ void Nextmap_OnChange(void)
SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
active = true; active = true;
} }
if (FIL_FileExists(va("%s-guest.lmp", tabase))) { if (FIL_FileExists(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) {
SP_NightsReplayMenu[3].status = IT_WHITESTRING|IT_CALL; SP_NightsReplayMenu[3].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL;
active = true; active = true;
} }
// Old style name compatibility
#ifdef OLDNREPLAYNAME
if (FIL_FileExists(va("%s-score-best.lmp", tabaseold))) {
SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
active = true;
}
if (FIL_FileExists(va("%s-time-best.lmp", tabaseold))) {
SP_NightsReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
active = true;
}
if (FIL_FileExists(va("%s-last.lmp", tabaseold))) {
SP_NightsReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
active = true;
}
#endif
if (active) { if (active) {
SP_NightsAttackMenu[naguest].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[naguest].status = IT_WHITESTRING|IT_SUBMENU;
SP_NightsAttackMenu[nareplay].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[nareplay].status = IT_WHITESTRING|IT_SUBMENU;
SP_NightsAttackMenu[naghost].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[naghost].status = IT_WHITESTRING|IT_SUBMENU;
} }
else if(itemOn == nareplay) // Reset lastOn so replay isn't still selected when not available. else if(itemOn == nareplay) // Reset lastOn so replay isn't still selected when not available.
{ {
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
@ -10126,6 +10156,8 @@ static void M_NightsAttack(INT32 choice)
// Player has selected the "START" from the nights attack screen // Player has selected the "START" from the nights attack screen
static void M_ChooseNightsAttack(INT32 choice) static void M_ChooseNightsAttack(INT32 choice)
{ {
char *gpath;
const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char nameofdemo[256]; char nameofdemo[256];
(void)choice; (void)choice;
emeralds = 0; emeralds = 0;
@ -10136,14 +10168,18 @@ static void M_ChooseNightsAttack(INT32 choice)
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
snprintf(nameofdemo, sizeof nameofdemo, "replay"PATHSEP"%s"PATHSEP"%s-last", timeattackfolder, G_BuildMapName(cv_nextmap.value)); if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name);
if (!cv_autorecord.value) if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
else else
G_RecordDemo(nameofdemo); G_RecordDemo(nameofdemo);
G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, false, false); G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), false, false);
} }
// Player has selected the "START" from the time attack screen // Player has selected the "START" from the time attack screen
@ -10179,6 +10215,7 @@ static void M_ChooseTimeAttack(INT32 choice)
static void M_ReplayTimeAttack(INT32 choice) static void M_ReplayTimeAttack(INT32 choice)
{ {
const char *which; const char *which;
char *demoname;
M_ClearMenus(true); M_ClearMenus(true);
modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows
@ -10220,11 +10257,18 @@ static void M_ReplayTimeAttack(INT32 choice)
which = "last"; which = "last";
break; break;
case 3: // guest case 3: // guest
which = "guest"; G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
break; return;
} }
// srb2/replay/main/map01-score-best.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which);
#ifdef OLDNREPLAYNAME // Check for old style named NiGHTS replay if a new style replay doesn't exist.
if (!FIL_FileExists(demoname))
demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which);
#endif
G_DoPlayDemo(demoname);
} }
} }
@ -10242,15 +10286,13 @@ static void M_EraseGuest(INT32 choice)
M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING);
} }
static void M_OverwriteGuest(const char *which, boolean nights) static void M_OverwriteGuest(const char *which)
{ {
char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
UINT8 *buf; UINT8 *buf;
size_t len; size_t len;
if (!nights) len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf);
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf);
else
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which), &buf);
if (!len) { if (!len) {
return; return;
} }
@ -10271,25 +10313,25 @@ static void M_OverwriteGuest(const char *which, boolean nights)
static void M_OverwriteGuest_Time(INT32 choice) static void M_OverwriteGuest_Time(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("time-best", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("time-best");
} }
static void M_OverwriteGuest_Score(INT32 choice) static void M_OverwriteGuest_Score(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("score-best", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("score-best");
} }
static void M_OverwriteGuest_Rings(INT32 choice) static void M_OverwriteGuest_Rings(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("rings-best", false); M_OverwriteGuest("rings-best");
} }
static void M_OverwriteGuest_Last(INT32 choice) static void M_OverwriteGuest_Last(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("last", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("last");
} }
static void M_SetGuestReplay(INT32 choice) static void M_SetGuestReplay(INT32 choice)

View File

@ -21,6 +21,9 @@
#include "r_skins.h" // for SKINNAMESIZE #include "r_skins.h" // for SKINNAMESIZE
#include "f_finale.h" // for ttmode_enum #include "f_finale.h" // for ttmode_enum
// Compatibility with old-style named NiGHTS replay files.
#define OLDNREPLAYNAME
// //
// MENUS // MENUS
// //

View File

@ -3157,6 +3157,7 @@ static void P_LoadNightsGhosts(void)
{ {
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen); char *gpath = malloc(glen);
INT32 i;
if (!gpath) if (!gpath)
return; return;
@ -3164,16 +3165,43 @@ static void P_LoadNightsGhosts(void)
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
// Best Score ghost // Best Score ghost
if (cv_ghost_bestscore.value && FIL_FileExists(va("%s-score-best.lmp", gpath))) if (cv_ghost_bestscore.value)
G_AddGhost(va("%s-score-best.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i].name));
}
}
// Best Time ghost // Best Time ghost
if (cv_ghost_besttime.value && FIL_FileExists(va("%s-time-best.lmp", gpath))) if (cv_ghost_besttime.value)
G_AddGhost(va("%s-time-best.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name));
}
}
// Last ghost // Last ghost
if (cv_ghost_last.value && FIL_FileExists(va("%s-last.lmp", gpath))) if (cv_ghost_last.value)
G_AddGhost(va("%s-last.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name));
}
}
// Guest ghost // Guest ghost
if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath)))