Merge branch 'separate-spb-attack-records' into 'master'

Separate/Encoreize SPB Attack records from normal Time Attack records

Closes #836

See merge request KartKrew/Kart!1875
This commit is contained in:
Oni 2024-02-23 06:44:38 +00:00
commit 9491c54e9d
10 changed files with 236 additions and 150 deletions

View file

@ -149,11 +149,17 @@ struct skinreference_t
#define MV_MYSTICMELODY (1<<4) #define MV_MYSTICMELODY (1<<4)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK|MV_MYSTICMELODY) #define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK|MV_MYSTICMELODY)
struct recordtimes_t
{
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
};
struct recorddata_t struct recorddata_t
{ {
UINT8 mapvisited; UINT8 mapvisited;
tic_t time; ///< Time in which the level was finished. recordtimes_t timeattack; ///< Best times for Time Attack
tic_t lap; ///< Best lap time for this level. recordtimes_t spbattack; ///< Best times for SPB Attack
}; };
#define KARTSPEED_AUTO -1 #define KARTSPEED_AUTO -1

View file

@ -388,10 +388,10 @@ void G_ClearRecords(void)
// For easy retrieval of records // For easy retrieval of records
tic_t G_GetBestTime(INT16 map) tic_t G_GetBestTime(INT16 map)
{ {
if (!mapheaderinfo[map] || mapheaderinfo[map]->records.time <= 0) if (!mapheaderinfo[map] || mapheaderinfo[map]->records.timeattack.time <= 0)
return (tic_t)UINT32_MAX; return (tic_t)UINT32_MAX;
return mapheaderinfo[map]->records.time; return mapheaderinfo[map]->records.timeattack.time;
} }
// BE RIGHT BACK // BE RIGHT BACK
@ -429,7 +429,7 @@ void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord)
} }
case ET_MAP: case ET_MAP:
{ {
if (emblem->flags & ME_SPBATTACK && cv_dummyspbattack.value) if (emblem->flags & (ME_SPBATTACK|ME_ENCORE) && cv_dummyspbattack.value)
break; break;
goto bademblem; goto bademblem;
} }
@ -437,7 +437,7 @@ void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord)
goto bademblem; goto bademblem;
} }
if (cv_dummyspbattack.value && !(emblem->flags & ME_SPBATTACK)) if (cv_dummyspbattack.value && !(emblem->flags & (ME_SPBATTACK|ME_ENCORE)))
return; return;
if (!gamedata->collected[(emblem-emblemlocations)] && gonnadrawtime) if (!gamedata->collected[(emblem-emblemlocations)] && gonnadrawtime)
@ -538,21 +538,24 @@ void G_TickTimeStickerMedals(void)
void G_UpdateRecords(void) void G_UpdateRecords(void)
{ {
UINT8 earnedEmblems; UINT8 earnedEmblems;
recordtimes_t *record = (encoremode == true) ?
&mapheaderinfo[gamemap-1]->records.spbattack :
&mapheaderinfo[gamemap-1]->records.timeattack;
if (modeattacking & ATTACKING_TIME) if (modeattacking & ATTACKING_TIME)
{ {
tic_t time = players[consoleplayer].realtime; tic_t time = players[consoleplayer].realtime;
if (players[consoleplayer].pflags & PF_NOCONTEST) if (players[consoleplayer].pflags & PF_NOCONTEST)
time = UINT32_MAX; time = UINT32_MAX;
if (((mapheaderinfo[gamemap-1]->records.time == 0) || (time < mapheaderinfo[gamemap-1]->records.time)) if (((record->time == 0) || (time < record->time))
&& (time < UINT32_MAX)) // DNF && (time < UINT32_MAX)) // DNF
mapheaderinfo[gamemap-1]->records.time = time; record->time = time;
} }
if (modeattacking & ATTACKING_LAP) if (modeattacking & ATTACKING_LAP)
{ {
if ((mapheaderinfo[gamemap-1]->records.lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->records.lap)) if ((record->lap == 0) || (bestlap < record->lap))
mapheaderinfo[gamemap-1]->records.lap = bestlap; record->lap = bestlap;
} }
// Check emblems when level data is updated // Check emblems when level data is updated
@ -581,6 +584,12 @@ static void G_UpdateRecordReplays(void)
{ {
char *gpath; char *gpath;
char lastdemo[256], bestdemo[256]; char lastdemo[256], bestdemo[256];
const char *modeprefix = "";
if (encoremode)
{
modeprefix = "spb-";
}
if (players[consoleplayer].pflags & PF_NOCONTEST) if (players[consoleplayer].pflags & PF_NOCONTEST)
{ {
@ -600,7 +609,7 @@ static void G_UpdateRecordReplays(void)
strcat(gpath, PATHSEP); strcat(gpath, PATHSEP);
strcat(gpath, G_BuildMapName(gamemap)); strcat(gpath, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_skin[0].string); snprintf(lastdemo, 255, "%s-%s-%slast.lmp", gpath, cv_skin[0].string, modeprefix);
if (modeattacking != ATTACKING_NONE && FIL_FileExists(lastdemo)) if (modeattacking != ATTACKING_NONE && FIL_FileExists(lastdemo))
{ {
@ -613,7 +622,7 @@ static void G_UpdateRecordReplays(void)
if (modeattacking & ATTACKING_TIME) if (modeattacking & ATTACKING_TIME)
{ {
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_skin[0].string); snprintf(bestdemo, 255, "%s-%s-%stime-best.lmp", gpath, cv_skin[0].string, modeprefix);
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))
@ -625,7 +634,7 @@ static void G_UpdateRecordReplays(void)
if (modeattacking & ATTACKING_LAP) if (modeattacking & ATTACKING_LAP)
{ {
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_skin[0].string); snprintf(bestdemo, 255, "%s-%s-%slap-best.lmp", gpath, cv_skin[0].string, modeprefix);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
{ // Better lap time, save this demo. { // Better lap time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))

View file

@ -121,10 +121,10 @@ void srb2::save_ng_gamedata()
map.visited.encore = mapheaderinfo[i]->records.mapvisited & MV_ENCORE; map.visited.encore = mapheaderinfo[i]->records.mapvisited & MV_ENCORE;
map.visited.spbattack = mapheaderinfo[i]->records.mapvisited & MV_SPBATTACK; map.visited.spbattack = mapheaderinfo[i]->records.mapvisited & MV_SPBATTACK;
map.visited.mysticmelody = mapheaderinfo[i]->records.mapvisited & MV_MYSTICMELODY; map.visited.mysticmelody = mapheaderinfo[i]->records.mapvisited & MV_MYSTICMELODY;
map.stats.timeattack.besttime = mapheaderinfo[i]->records.time; map.stats.timeattack.besttime = mapheaderinfo[i]->records.timeattack.time;
map.stats.timeattack.bestlap = mapheaderinfo[i]->records.lap; map.stats.timeattack.bestlap = mapheaderinfo[i]->records.timeattack.lap;
map.stats.spbattack.besttime = 0; map.stats.spbattack.besttime = mapheaderinfo[i]->records.spbattack.time;
map.stats.spbattack.bestlap = 0; map.stats.spbattack.bestlap = mapheaderinfo[i]->records.spbattack.lap;
ng.maps[lumpname] = std::move(map); ng.maps[lumpname] = std::move(map);
} }
for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next) for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
@ -136,10 +136,10 @@ void srb2::save_ng_gamedata()
map.visited.encore = unloadedmap->records.mapvisited & MV_ENCORE; map.visited.encore = unloadedmap->records.mapvisited & MV_ENCORE;
map.visited.spbattack = unloadedmap->records.mapvisited & MV_SPBATTACK; map.visited.spbattack = unloadedmap->records.mapvisited & MV_SPBATTACK;
map.visited.mysticmelody = unloadedmap->records.mapvisited & MV_MYSTICMELODY; map.visited.mysticmelody = unloadedmap->records.mapvisited & MV_MYSTICMELODY;
map.stats.timeattack.besttime = unloadedmap->records.time; map.stats.timeattack.besttime = unloadedmap->records.timeattack.time;
map.stats.timeattack.bestlap = unloadedmap->records.lap; map.stats.timeattack.bestlap = unloadedmap->records.timeattack.lap;
map.stats.spbattack.besttime = 0; map.stats.spbattack.besttime = unloadedmap->records.spbattack.time;
map.stats.spbattack.bestlap = 0; map.stats.spbattack.bestlap = unloadedmap->records.spbattack.lap;
ng.maps[lumpname] = std::move(map); ng.maps[lumpname] = std::move(map);
} }
for (int i = 0; i < gamedata->numspraycans; i++) for (int i = 0; i < gamedata->numspraycans; i++)
@ -536,8 +536,10 @@ void srb2::load_ng_gamedata()
dummyrecord.mapvisited |= mappair.second.visited.encore ? MV_ENCORE : 0; dummyrecord.mapvisited |= mappair.second.visited.encore ? MV_ENCORE : 0;
dummyrecord.mapvisited |= mappair.second.visited.spbattack ? MV_SPBATTACK : 0; dummyrecord.mapvisited |= mappair.second.visited.spbattack ? MV_SPBATTACK : 0;
dummyrecord.mapvisited |= mappair.second.visited.mysticmelody ? MV_SPBATTACK : 0; dummyrecord.mapvisited |= mappair.second.visited.mysticmelody ? MV_SPBATTACK : 0;
dummyrecord.time = mappair.second.stats.timeattack.besttime; dummyrecord.timeattack.time = mappair.second.stats.timeattack.besttime;
dummyrecord.lap = mappair.second.stats.timeattack.bestlap; dummyrecord.timeattack.lap = mappair.second.stats.timeattack.bestlap;
dummyrecord.spbattack.time = mappair.second.stats.spbattack.besttime;
dummyrecord.spbattack.lap = mappair.second.stats.spbattack.bestlap;
if (mapnum < nummapheaders && mapheaderinfo[mapnum]) if (mapnum < nummapheaders && mapheaderinfo[mapnum])
{ {
@ -545,7 +547,9 @@ void srb2::load_ng_gamedata()
mapheaderinfo[mapnum]->records = dummyrecord; mapheaderinfo[mapnum]->records = dummyrecord;
} }
else if (dummyrecord.mapvisited & MV_BEATEN || dummyrecord.time != 0 || dummyrecord.lap != 0) else if (dummyrecord.mapvisited & MV_BEATEN
|| dummyrecord.timeattack.time != 0 || dummyrecord.timeattack.lap != 0
|| dummyrecord.spbattack.time != 0 || dummyrecord.spbattack.lap != 0)
{ {
// Invalid, but we don't want to lose all the juicy statistics. // Invalid, but we don't want to lose all the juicy statistics.
// Instead, update a FILO linked list of "unloaded mapheaders". // Instead, update a FILO linked list of "unloaded mapheaders".

View file

@ -906,6 +906,7 @@ void M_ReplayTimeAttack(INT32 choice);
void M_HandleStaffReplay(INT32 choice); void M_HandleStaffReplay(INT32 choice);
void M_SetGuestReplay(INT32 choice); void M_SetGuestReplay(INT32 choice);
void M_TimeAttackTick(void); void M_TimeAttackTick(void);
boolean M_EncoreAttackTogglePermitted(void);
boolean M_TimeAttackInputs (INT32 choice); boolean M_TimeAttackInputs (INT32 choice);
// MP selection // MP selection

View file

@ -3508,8 +3508,10 @@ void M_DrawTimeAttack(void)
if (currentMenu == &PLAY_TimeAttackDef) if (currentMenu == &PLAY_TimeAttackDef)
{ {
tic_t timerec = mapheaderinfo[map]->records.time; recorddata_t *rcp = &mapheaderinfo[map]->records;
tic_t laprec = mapheaderinfo[map]->records.lap; recordtimes_t *record = cv_dummyspbattack.value ? &rcp->spbattack : &rcp->timeattack;
tic_t timerec = record->time;
tic_t laprec = record->lap;
UINT32 timeheight = 82; UINT32 timeheight = 82;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT) if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
@ -3528,19 +3530,20 @@ void M_DrawTimeAttack(void)
K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1); K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1);
// SPB Attack control hint + menu overlay // SPB Attack control hint + menu overlay
if (levellist.newgametype == GT_RACE && levellist.levelsearch.timeattack == true && M_SecretUnlocked(SECRET_SPBATTACK, true))
{ {
INT32 buttonx = 162 + t; INT32 buttonx = 162 + t;
INT32 buttony = timeheight; INT32 buttony = timeheight;
K_drawButtonAnim(buttonx + 35, buttony - 3, V_SNAPTOLEFT, kp_button_r, timeattackmenu.ticker); if (M_EncoreAttackTogglePermitted())
{
K_drawButtonAnim(buttonx + 35, buttony - 3, V_SNAPTOLEFT, kp_button_r, timeattackmenu.ticker);
}
if ((timeattackmenu.spbflicker == 0 || timeattackmenu.ticker % 2) == (cv_dummyspbattack.value == 1)) if ((timeattackmenu.spbflicker == 0 || timeattackmenu.ticker % 2) == (cv_dummyspbattack.value == 1))
{ {
V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_SPBATK", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE)); V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_SPBATK", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE));
} }
} }
} }
else else
opty = 80; opty = 80;
@ -7546,13 +7549,13 @@ static void M_DrawStatsMaps(void)
if (!(mapheaderinfo[i]->typeoflevel & (TOL_RACE|TOL_BATTLE|TOL_SPECIAL|TOL_VERSUS))) if (!(mapheaderinfo[i]->typeoflevel & (TOL_RACE|TOL_BATTLE|TOL_SPECIAL|TOL_VERSUS)))
continue; continue;
if (mapheaderinfo[i]->records.time <= 0) if (mapheaderinfo[i]->records.timeattack.time <= 0)
{ {
mapsunfinished++; mapsunfinished++;
continue; continue;
} }
besttime += mapheaderinfo[i]->records.time; besttime += mapheaderinfo[i]->records.timeattack.time;
} }
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, 0, V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, 0,
@ -7632,7 +7635,7 @@ static void M_DrawStatsMaps(void)
) )
) )
{ {
besttime = mapheaderinfo[mnum]->records.time; besttime = mapheaderinfo[mnum]->records.timeattack.time;
if (besttime) if (besttime)
{ {

View file

@ -3470,9 +3470,9 @@ boolean M_GotLowEnoughTime(INT32 tictime)
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK)) if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK))
continue; continue;
if (!mapheaderinfo[i]->records.time) if (!mapheaderinfo[i]->records.timeattack.time)
return false; return false;
if ((curtics += mapheaderinfo[i]->records.time) > tictime) if ((curtics += mapheaderinfo[i]->records.timeattack.time) > tictime)
return false; return false;
} }
return true; return true;

View file

@ -11,12 +11,6 @@
#include "../z_zone.h" // Z_StrDup/Z_Free #include "../z_zone.h" // Z_StrDup/Z_Free
#include "../m_cond.h" #include "../m_cond.h"
void CV_SPBAttackChanged(void);
void CV_SPBAttackChanged(void)
{
G_UpdateTimeStickerMedals(levellist.choosemap, false);
}
struct timeattackmenu_s timeattackmenu; struct timeattackmenu_s timeattackmenu;
void M_TimeAttackTick(void) void M_TimeAttackTick(void)
@ -28,13 +22,21 @@ void M_TimeAttackTick(void)
} }
} }
boolean M_EncoreAttackTogglePermitted(void)
{
if ((gametypes[levellist.newgametype]->rules & GTR_ENCORE) == 0) //levellist.newgametype != GT_RACE
return false;
return M_SecretUnlocked(SECRET_SPBATTACK, true);
}
boolean M_TimeAttackInputs(INT32 ch) boolean M_TimeAttackInputs(INT32 ch)
{ {
const UINT8 pid = 0; const UINT8 pid = 0;
const boolean buttonR = M_MenuButtonPressed(pid, MBT_R); const boolean buttonR = M_MenuButtonPressed(pid, MBT_R);
(void) ch; (void) ch;
if (buttonR && levellist.newgametype == GT_RACE && M_SecretUnlocked(SECRET_SPBATTACK, true)) if (buttonR && M_EncoreAttackTogglePermitted())
{ {
CV_AddValue(&cv_dummyspbattack, 1); CV_AddValue(&cv_dummyspbattack, 1);
timeattackmenu.spbflicker = TICRATE/6; timeattackmenu.spbflicker = TICRATE/6;
@ -122,10 +124,11 @@ menu_t PLAY_TimeAttackDef = {
typedef enum typedef enum
{ {
tareplay_besttime = 0, tareplay_header = 0,
tareplay_besttime,
tareplay_bestlap, tareplay_bestlap,
tareplay_gap1,
tareplay_last, tareplay_last,
tareplay_gap1,
tareplay_guest, tareplay_guest,
tareplay_staff, tareplay_staff,
tareplay_gap2, tareplay_gap2,
@ -134,10 +137,11 @@ typedef enum
menuitem_t PLAY_TAReplay[] = menuitem_t PLAY_TAReplay[] =
{ {
{IT_HEADERTEXT|IT_HEADER, "<!>", NULL, NULL, {NULL}, 0, 0},
{IT_STRING | IT_CALL, "Replay Best Time", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_STRING | IT_CALL, "Replay Best Time", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0},
{IT_STRING | IT_CALL, "Replay Best Lap", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_STRING | IT_CALL, "Replay Best Lap", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0},
{IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0},
{IT_STRING | IT_CALL, "Replay Last", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_STRING | IT_CALL, "Replay Last", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0},
{IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0},
{IT_STRING | IT_CALL, "Replay Guest", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_STRING | IT_CALL, "Replay Guest", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0},
{IT_STRING | IT_ARROWS, "Replay Staff", NULL, "MENUI006", {.routine = M_HandleStaffReplay}, 0, 0}, {IT_STRING | IT_ARROWS, "Replay Staff", NULL, "MENUI006", {.routine = M_HandleStaffReplay}, 0, 0},
{IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0},
@ -250,7 +254,122 @@ menu_t PLAY_TAGhostsDef = {
NULL NULL
}; };
// time attack stuff... void CV_SPBAttackChanged(void);
void CV_SPBAttackChanged(void)
{
G_UpdateTimeStickerMedals(levellist.choosemap, false);
// Menu options
{
// see also p_setup.c's P_LoadRecordGhosts
char *gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)));
const char *modeprefix = "";
UINT8 active;
if (!gpath)
return;
if (cv_dummyspbattack.value)
modeprefix = "spb-";
active = false;
PLAY_TimeAttack[ta_guest].status = IT_DISABLED;
PLAY_TimeAttack[ta_replay].status = IT_DISABLED;
PLAY_TimeAttack[ta_ghosts].status = IT_DISABLED;
PLAY_TAReplay[tareplay_header].status = IT_DISABLED;
// Check if file exists, if not, disable options
PLAY_TAReplay[tareplay_besttime].status =
PLAY_TAReplayGuest[taguest_besttime].status = IT_DISABLED;
if (FIL_FileExists(va("%s-%s-%stime-best.lmp", gpath, cv_skin[0].string, modeprefix)))
{
PLAY_TAReplay[tareplay_besttime].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_besttime].status = IT_STRING|IT_CALL;
active |= (1|2|4|8);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_besttime)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_bestlap].status =
PLAY_TAReplayGuest[taguest_bestlap].status =
PLAY_TAGhosts[taghost_bestlap].status = IT_DISABLED;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
&& (mapheaderinfo[levellist.choosemap]->numlaps != 1)
&& FIL_FileExists(va("%s-%s-%slap-best.lmp", gpath, cv_skin[0].string, modeprefix)))
{
PLAY_TAReplay[tareplay_bestlap].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_bestlap].status = IT_STRING|IT_CALL;
PLAY_TAGhosts[taghost_bestlap].status = IT_STRING|IT_CVAR;
active |= (1|2|4|8);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_bestlap)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_last].status =
PLAY_TAReplayGuest[taguest_last].status = IT_DISABLED;
if (FIL_FileExists(va("%s-%s-%slast.lmp", gpath, cv_skin[0].string, modeprefix)))
{
PLAY_TAReplay[tareplay_last].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_last].status = IT_STRING|IT_CALL;
active |= (1|2|4|8);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_last)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_guest].status =
PLAY_TAGhosts[taghost_guest].status =
PLAY_TAReplayGuest[taguest_delete].status = IT_DISABLED;
if (FIL_FileExists(va("%s-%sguest.lmp", gpath, modeprefix)))
{
PLAY_TAReplay[tareplay_guest].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_delete].status = IT_STRING|IT_CALL;
PLAY_TAGhosts[taghost_guest].status = IT_STRING|IT_CVAR;
active |= (1|2|4);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_delete)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_staff].status =
PLAY_TAGhosts[taghost_staff].status = IT_DISABLED;
if (mapheaderinfo[levellist.choosemap]->ghostCount > 0 && !modeprefix[0])
{
PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_ARROWS;
PLAY_TAGhosts[taghost_staff].status = IT_STRING|IT_CVAR;
CV_SetValue(&cv_dummystaff, 0);
active |= 1|4;
}
if (currentMenu == &PLAY_TimeAttackDef)
PLAY_TimeAttackDef.lastOn = itemOn;
if (active & 1)
PLAY_TimeAttack[ta_replay].status = IT_STRING|IT_SUBMENU;
else if (PLAY_TimeAttackDef.lastOn == ta_replay)
PLAY_TimeAttackDef.lastOn = ta_start;
if (active & 2)
PLAY_TimeAttack[ta_guest].status = IT_STRING|IT_SUBMENU;
else if (PLAY_TimeAttackDef.lastOn == ta_guest)
PLAY_TimeAttackDef.lastOn = ta_start;
//if (active & 4) -- for possible future use
PLAY_TimeAttack[ta_ghosts].status = IT_STRING|IT_SUBMENU;
/*else if (PLAY_TimeAttackDef.lastOn == ta_ghosts)
PLAY_TimeAttackDef.lastOn = ta_start;*/
if ((active & 8) && M_EncoreAttackTogglePermitted())
{
PLAY_TAReplay[tareplay_header].status = IT_HEADER;
PLAY_TAReplay[tareplay_header].text = cv_dummyspbattack.value ? "SPB Attack..." : "Time Attack...";
}
if (currentMenu == &PLAY_TimeAttackDef)
itemOn = PLAY_TimeAttackDef.lastOn;
Z_Free(gpath);
}
}
/// time attack stuff...
void M_PrepareTimeAttack(boolean menuupdate) void M_PrepareTimeAttack(boolean menuupdate)
{ {
if (menuupdate) if (menuupdate)
@ -270,102 +389,21 @@ void M_PrepareTimeAttack(boolean menuupdate)
} }
} }
if (levellist.levelsearch.timeattack == false || levellist.newgametype != GT_RACE || !M_SecretUnlocked(SECRET_SPBATTACK, true)) if (cv_dummyspbattack.value
CV_SetValue(&cv_dummyspbattack, 0); && (levellist.levelsearch.timeattack == false || !M_EncoreAttackTogglePermitted()))
// Time-sticker Medals
G_UpdateTimeStickerMedals(levellist.choosemap, false);
// Menu options
{ {
// see also p_setup.c's P_LoadRecordGhosts CV_StealthSetValue(&cv_dummyspbattack, 0);
char *gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)));
UINT8 active;
if (!gpath) if (!menuupdate)
return;
active = false;
PLAY_TimeAttack[ta_guest].status = IT_DISABLED;
PLAY_TimeAttack[ta_replay].status = IT_DISABLED;
PLAY_TimeAttack[ta_ghosts].status = IT_DISABLED;
// Check if file exists, if not, disable options
PLAY_TAReplay[tareplay_besttime].status =
PLAY_TAReplayGuest[taguest_besttime].status = IT_DISABLED;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, cv_skin[0].string)))
{ {
PLAY_TAReplay[tareplay_besttime].status = IT_STRING|IT_CALL; timeattackmenu.spbflicker = TICRATE/6;
PLAY_TAReplayGuest[taguest_besttime].status = IT_STRING|IT_CALL; S_StartSound(NULL, sfx_s3k92);
active |= (1|2|4); S_StopSoundByID(NULL, sfx_s3k9f);
} }
else if (PLAY_TAReplayGuestDef.lastOn == taguest_besttime)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_bestlap].status =
PLAY_TAReplayGuest[taguest_bestlap].status =
PLAY_TAGhosts[taghost_bestlap].status = IT_DISABLED;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
&& (mapheaderinfo[levellist.choosemap]->numlaps != 1)
&& FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_skin[0].string)))
{
PLAY_TAReplay[tareplay_bestlap].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_bestlap].status = IT_STRING|IT_CALL;
PLAY_TAGhosts[taghost_bestlap].status = IT_STRING|IT_CVAR;
active |= (1|2|4);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_bestlap)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_last].status =
PLAY_TAReplayGuest[taguest_last].status = IT_DISABLED;
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, cv_skin[0].string)))
{
PLAY_TAReplay[tareplay_last].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_last].status = IT_STRING|IT_CALL;
active |= (1|2|4);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_last)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_guest].status =
PLAY_TAGhosts[taghost_guest].status =
PLAY_TAReplayGuest[taguest_delete].status = IT_DISABLED;
if (FIL_FileExists(va("%s-guest.lmp", gpath)))
{
PLAY_TAReplay[tareplay_guest].status = IT_STRING|IT_CALL;
PLAY_TAReplayGuest[taguest_delete].status = IT_STRING|IT_CALL;
PLAY_TAGhosts[taghost_guest].status = IT_STRING|IT_CVAR;
active |= (1|2|4);
}
else if (PLAY_TAReplayGuestDef.lastOn == taguest_delete)
PLAY_TAReplayGuestDef.lastOn = taguest_back;
PLAY_TAReplay[tareplay_staff].status =
PLAY_TAGhosts[taghost_staff].status = IT_DISABLED;
if (mapheaderinfo[levellist.choosemap]->ghostCount > 0)
{
PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_ARROWS;
PLAY_TAGhosts[taghost_staff].status = IT_STRING|IT_CVAR;
CV_SetValue(&cv_dummystaff, 0);
active |= 1|4;
}
if (active & 1)
PLAY_TimeAttack[ta_replay].status = IT_STRING|IT_SUBMENU;
else if (PLAY_TimeAttackDef.lastOn == ta_replay)
PLAY_TimeAttackDef.lastOn = ta_start;
if (active & 2)
PLAY_TimeAttack[ta_guest].status = IT_STRING|IT_SUBMENU;
else if (PLAY_TimeAttackDef.lastOn == ta_guest)
PLAY_TimeAttackDef.lastOn = ta_start;
//if (active & 4) -- for possible future use
PLAY_TimeAttack[ta_ghosts].status = IT_STRING|IT_SUBMENU;
/*else if (PLAY_TimeAttackDef.lastOn == ta_ghosts)
PLAY_TimeAttackDef.lastOn = ta_start;*/
Z_Free(gpath);
} }
// Menu options / Time-sticker medals
CV_SPBAttackChanged();
} }
void M_HandleStaffReplay(INT32 choice) void M_HandleStaffReplay(INT32 choice)
@ -403,6 +441,11 @@ void M_ReplayTimeAttack(INT32 choice)
demo.loadfiles = false; demo.loadfiles = false;
demo.ignorefiles = true; // Just assume that record attack replays have the files needed demo.ignorefiles = true; // Just assume that record attack replays have the files needed
const char *modeprefix = "";
if (cv_dummyspbattack.value)
modeprefix = "spb-";
switch (choice) switch (choice)
{ {
default: default:
@ -416,11 +459,11 @@ void M_ReplayTimeAttack(INT32 choice)
which = "last"; which = "last";
break; break;
case tareplay_guest: case tareplay_guest:
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1))); G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%sguest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), modeprefix));
return; return;
} }
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), cv_skin[0].string, which)); 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));
} }
static const char *TA_GuestReplay_Str = NULL; static const char *TA_GuestReplay_Str = NULL;
@ -437,9 +480,14 @@ static void M_WriteGuestReplay(INT32 ch)
gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1))); gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)));
const char *modeprefix = "";
if (cv_dummyspbattack.value)
modeprefix = "spb-";
if (TA_GuestReplay_Str != NULL) if (TA_GuestReplay_Str != NULL)
{ {
len = FIL_ReadFile(va("%s-%s-%s.lmp", gpath, cv_skin[0].string, TA_GuestReplay_Str), &buf); len = FIL_ReadFile(va("%s-%s-%s%s.lmp", gpath, cv_skin[0].string, modeprefix, TA_GuestReplay_Str), &buf);
if (!len) if (!len)
{ {
M_StartMessage("Guest Replay", "Replay to copy no longer exists!", NULL, MM_NOTHING, NULL, NULL); M_StartMessage("Guest Replay", "Replay to copy no longer exists!", NULL, MM_NOTHING, NULL, NULL);
@ -448,7 +496,7 @@ static void M_WriteGuestReplay(INT32 ch)
} }
} }
rguest = Z_StrDup(va("%s-guest.lmp", gpath)); rguest = Z_StrDup(va("%s-%sguest.lmp", gpath, modeprefix));
if (FIL_FileExists(rguest)) if (FIL_FileExists(rguest))
{ {
@ -491,7 +539,12 @@ void M_SetGuestReplay(INT32 choice)
break; break;
} }
if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)))) const char *modeprefix = "";
if (cv_dummyspbattack.value)
modeprefix = "spb-";
if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%sguest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), modeprefix)))
{ {
M_StartMessage("Guest Replay", va("Are you sure you want to\n%s the guest replay data?\n", (TA_GuestReplay_Str != NULL ? "overwrite" : "delete")), &M_WriteGuestReplay, MM_YESNO, NULL, NULL); M_StartMessage("Guest Replay", va("Are you sure you want to\n%s the guest replay data?\n", (TA_GuestReplay_Str != NULL ? "overwrite" : "delete")), &M_WriteGuestReplay, MM_YESNO, NULL, NULL);
} }
@ -505,6 +558,7 @@ void M_StartTimeAttack(INT32 choice)
{ {
char *gpath; char *gpath;
char nameofdemo[256]; char nameofdemo[256];
const char *modeprefix = "";
(void)choice; (void)choice;
@ -518,7 +572,11 @@ void M_StartTimeAttack(INT32 choice)
if (cv_dummyspbattack.value) if (cv_dummyspbattack.value)
{ {
modeattacking |= ATTACKING_SPB; if (levellist.newgametype == GT_RACE)
{
modeattacking |= ATTACKING_SPB;
}
modeprefix = "spb-";
} }
// Still need to reset devmode // Still need to reset devmode
@ -551,7 +609,7 @@ void M_StartTimeAttack(INT32 choice)
strcat(gpath, PATHSEP); strcat(gpath, PATHSEP);
strcat(gpath, G_BuildMapName(levellist.choosemap+1)); strcat(gpath, G_BuildMapName(levellist.choosemap+1));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, cv_skin[0].string); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-%slast", gpath, cv_skin[0].string, modeprefix);
if (!cv_autorecord.value) if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
@ -561,7 +619,7 @@ void M_StartTimeAttack(INT32 choice)
restoreMenu = &PLAY_TimeAttackDef; restoreMenu = &PLAY_TimeAttackDef;
M_ClearMenus(true); M_ClearMenus(true);
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummygpencore.value == 1), 1, 1, false, false); D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummyspbattack.value == 1), 1, 1, false, false);
G_UpdateTimeStickerMedals(levellist.choosemap, true); G_UpdateTimeStickerMedals(levellist.choosemap, true);
} }

View file

@ -7786,10 +7786,14 @@ static void P_LoadRecordGhosts(void)
{ {
// see also /menus/play-local-race-time-attack.c's M_PrepareTimeAttack // see also /menus/play-local-race-time-attack.c's M_PrepareTimeAttack
char *gpath; char *gpath;
const char *modeprefix = "";
INT32 i; INT32 i;
gpath = Z_StrDup(va("%s" PATHSEP "media" PATHSEP "replay" PATHSEP "%s" PATHSEP "%s", srb2home, timeattackfolder, G_BuildMapName(gamemap))); gpath = Z_StrDup(va("%s" PATHSEP "media" PATHSEP "replay" PATHSEP "%s" PATHSEP "%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)));
if (encoremode)
modeprefix = "spb-";
enum enum
{ {
kTime = 1 << 0, kTime = 1 << 0,
@ -7832,7 +7836,7 @@ static void P_LoadRecordGhosts(void)
if (allGhosts) if (allGhosts)
{ {
for (i = 0; i < numskins; ++i) for (i = 0; i < numskins; ++i)
add_ghosts(fmt::format("{}-{}", gpath, skins[i].name), allGhosts); add_ghosts(fmt::format("{}-{}{}", gpath, skins[i].name, modeprefix), allGhosts);
} }
if (sameGhosts) if (sameGhosts)
@ -7840,15 +7844,15 @@ static void P_LoadRecordGhosts(void)
INT32 skin = R_SkinAvailable(cv_skin[0].string); INT32 skin = R_SkinAvailable(cv_skin[0].string);
if (skin < 0 || !R_SkinUsable(consoleplayer, skin, false)) if (skin < 0 || !R_SkinUsable(consoleplayer, skin, false))
skin = 0; // use default skin skin = 0; // use default skin
add_ghosts(fmt::format("{}-{}", gpath, skins[skin].name), sameGhosts); add_ghosts(fmt::format("{}-{}{}", gpath, skins[skin].name, modeprefix), sameGhosts);
} }
// Guest ghost // Guest ghost
if (cv_ghost_guest.value) if (cv_ghost_guest.value)
P_TryAddExternalGhost(va("%s-guest.lmp", gpath)); P_TryAddExternalGhost(va("%s-%sguest.lmp", gpath, modeprefix));
// Staff Attack ghosts // Staff Attack ghosts
if (cv_ghost_staff.value) if (cv_ghost_staff.value && !modeprefix[0])
{ {
for (i = mapheaderinfo[gamemap-1]->ghostCount; i > 0; i--) for (i = mapheaderinfo[gamemap-1]->ghostCount; i > 0; i--)
{ {
@ -8290,7 +8294,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
wipegamestate = gamestate; // Don't fade if reloading the gamestate wipegamestate = gamestate; // Don't fade if reloading the gamestate
// Encore mode fade to pink to white // Encore mode fade to pink to white
// This is handled BEFORE sounds are stopped. // This is handled BEFORE sounds are stopped.
else if (encoremode && !prevencoremode && !demo.rewinding) else if (encoremode && !prevencoremode && modeattacking == ATTACKING_NONE && !demo.rewinding)
{ {
if (rendermode != render_none) if (rendermode != render_none)
{ {

View file

@ -123,6 +123,7 @@ TYPEDEF (precipprops_t);
TYPEDEF (skinrecord_t); TYPEDEF (skinrecord_t);
TYPEDEF (unloaded_skin_t); TYPEDEF (unloaded_skin_t);
TYPEDEF (skinreference_t); TYPEDEF (skinreference_t);
TYPEDEF (recordtimes_t);
TYPEDEF (recorddata_t); TYPEDEF (recorddata_t);
TYPEDEF (cupwindata_t); TYPEDEF (cupwindata_t);
TYPEDEF (scene_t); TYPEDEF (scene_t);

View file

@ -207,7 +207,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
i = data.num[data.numplayers]; i = data.num[data.numplayers];
completed[i] = true; completed[i] = true;
data.grade[i] = players[i].tally.rank; data.grade[i] = K_PlayerTallyActive(&players[i]) ? players[i].tally.rank : GRADE_INVALID;
data.color[data.numplayers] = players[i].skincolor; data.color[data.numplayers] = players[i].skincolor;
data.character[data.numplayers] = players[i].skin; data.character[data.numplayers] = players[i].skin;