Merge branch 'staff_names' into 'master'

Staff Attack improvements

See merge request KartKrew/Kart!79
This commit is contained in:
Sal 2018-11-08 14:47:23 -05:00
commit 1079c55f72
10 changed files with 191 additions and 50 deletions

View file

@ -4939,7 +4939,7 @@ static void Fishcake_OnChange(void)
static void Command_Isgamemodified_f(void)
{
if (savemoddata)
CONS_Printf(M_GetText("modifiedgame is true, but you can save emblem and time data in this mod.\n"));
CONS_Printf(M_GetText("modifiedgame is true, but you can save medal and time data in this mod.\n"));
else if (modifiedgame)
CONS_Printf(M_GetText("modifiedgame is true, secrets will not be unlocked\n"));
else

View file

@ -49,7 +49,9 @@ static tic_t stoptimer;
static boolean keypressed = false;
// (no longer) De-Demo'd Title Screen
static UINT8 curDemo = 0;
#if 0
static UINT8 laststaff = 0;
#endif
static UINT32 demoDelayLeft;
static UINT32 demoIdleLeft;
@ -985,8 +987,8 @@ void F_TitleScreenTicker(boolean run)
if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
return;
// no demos to play? or, are they disabled?
if (!cv_rollingdemos.value || !numDemos)
// are demos disabled?
if (!cv_rollingdemos.value)
return;
// Wait for a while (for the music to finish, preferably)
@ -1009,27 +1011,58 @@ void F_TitleScreenTicker(boolean run)
{
char dname[9];
lumpnum_t l;
const char *mapname;
UINT8 numstaff;
// prevent console spam if failed
demoIdleLeft = demoIdleTime;
if ((l = W_CheckNumForName("MAP01S01")) == LUMPERROR) // gotta have ONE
{
F_StartIntro();
return;
}
// Replay intro when done cycling through demos
if (curDemo == numDemos)
/*if (curDemo == numDemos) -- uuuh... we have a LOT of maps AND a big devteam... probably not gonna see a repeat unless you're super unlucky :V
{
curDemo = 0;
F_StartIntro();
return;
}*/
mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, false, false, 0, false)+1);
numstaff = 1;
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR)
numstaff++;
#if 0 // turns out this isn't how we're gonna organise 'em
if (numstaff > 1)
{
if (laststaff && laststaff <= numstaff) // don't do the same staff member twice in a row, even if they're on different maps
{
numstaff = M_RandomKey(numstaff-1)+1;
if (numstaff >= laststaff)
numstaff++;
}
else
numstaff = M_RandomKey(numstaff)+1;
}
laststaff = numstaff;
#else
numstaff = M_RandomKey(numstaff)+1;
#endif
// Setup demo name
snprintf(dname, 9, "DEMO_%03u", ++curDemo);
snprintf(dname, 9, "%sS%02u", mapname, numstaff);
if ((l = W_CheckNumForName(dname)) == LUMPERROR)
/*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now
{
CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname);
F_StartIntro();
return;
}
}*/
titledemo = true;
G_DoPlayDemo(dname);

View file

@ -3312,7 +3312,7 @@ tryagain:
|| (!dedicated && M_MapLocked(ix+1))
|| (!maphell && (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU)) // this is bad
|| ((maphell == 2) && !(mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // gasp
isokmap = false;
continue; //isokmap = false;
if (!ignorebuffer)
{
@ -3328,8 +3328,17 @@ tryagain:
}
}
if (isokmap)
okmaps[numokmaps++] = ix;
if (!isokmap)
continue;
if (pprevmap == -2) // title demos
{
lumpnum_t l;
if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR)
continue;
}
okmaps[numokmaps++] = ix;
}
if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V)
@ -4133,8 +4142,8 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
}
save_p += VERSIONSIZE;
// if (demoplayback) // reset game engine
// G_StopDemo();
if (demoplayback) // reset game engine
G_StopDemo();
// paused = false;
// automapactive = false;
@ -5899,7 +5908,7 @@ void G_DoPlayDemo(char *defdemoname)
players[0].skincolor = i;
break;
}
CV_StealthSetValue(&cv_playercolor, players[0].skincolor);
//CV_StealthSetValue(&cv_playercolor, players[0].skincolor); -- as far as I can tell this is more trouble than it's worth
if (players[0].mo)
{
players[0].mo->color = players[0].skincolor;
@ -6153,6 +6162,68 @@ void G_AddGhost(char *defdemoname)
Z_Free(pdemoname);
}
// A simplified version of G_AddGhost...
void G_UpdateStaffGhostName(lumpnum_t l)
{
UINT8 *buffer,*p;
UINT16 ghostversion;
UINT8 flags;
buffer = p = W_CacheLumpNum(l, PU_CACHE);
// read demo header
if (memcmp(p, DEMOHEADER, 12))
{
goto fail;
} p += 12; // DEMOHEADER
p++; // VERSION
p++; // SUBVERSION
ghostversion = READUINT16(p);
switch(ghostversion)
{
case DEMOVERSION: // latest always supported
break;
// too old, cannot support.
default:
goto fail;
}
p += 16; // demo checksum
if (memcmp(p, "PLAY", 4))
{
goto fail;
} p += 4; // "PLAY"
p += 2; // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
if (!(flags & DF_GHOST))
{
goto fail; // we don't NEED to do it here, but whatever
}
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
/*case ATTACKING_NIGHTS: // 2
p += 8; // demo time left, score
break;*/
default: // 3
break;
}
p += 4; // random seed
// Player name
M_Memcpy(dummystaffname, p,16);
dummystaffname[16] = '\0';
// Ok, no longer any reason to care, bye
fail:
Z_Free(buffer);
return;
}
//
// G_TimeDemo
// NOTE: name is a full filename for external demos
@ -6297,10 +6368,17 @@ void G_StopDemo(void)
Z_Free(demobuffer);
demobuffer = NULL;
demoplayback = false;
if (titledemo)
modeattacking = false;
titledemo = false;
timingdemo = false;
singletics = false;
if (gamestate == GS_LEVEL && rendermode != render_none)
{
V_SetPaletteLump("PLAYPAL"); // Reset the palette
R_ReInitColormaps(0, LUMPERROR);
}
if (gamestate == GS_INTERMISSION)
Y_EndIntermission(); // cleanup
if (gamestate == GS_VOTING)

View file

@ -186,6 +186,7 @@ extern demoghost *ghosts;
void G_DoPlayDemo(char *defdemoname);
void G_TimeDemo(const char *name);
void G_AddGhost(char *defdemoname);
void G_UpdateStaffGhostName(lumpnum_t l);
void G_DoPlayMetal(void);
void G_DoneLevelLoad(void);
void G_StopMetalDemo(void);

View file

@ -5576,6 +5576,7 @@ static patch_t *kp_nodraw;
static patch_t *kp_timesticker;
static patch_t *kp_timestickerwide;
static patch_t *kp_lapsticker;
static patch_t *kp_lapstickerwide;
static patch_t *kp_lapstickernarrow;
static patch_t *kp_splitlapflag;
static patch_t *kp_bumpersticker;
@ -5655,6 +5656,7 @@ void K_LoadKartHUDGraphics(void)
kp_timesticker = W_CachePatchName("K_STTIME", PU_HUDGFX);
kp_timestickerwide = W_CachePatchName("K_STTIMW", PU_HUDGFX);
kp_lapsticker = W_CachePatchName("K_STLAPS", PU_HUDGFX);
kp_lapstickerwide = W_CachePatchName("K_STLAPW", PU_HUDGFX);
kp_lapstickernarrow = W_CachePatchName("K_STLAPN", PU_HUDGFX);
kp_splitlapflag = W_CachePatchName("K_SPTLAP", PU_HUDGFX);
kp_bumpersticker = W_CachePatchName("K_STBALN", PU_HUDGFX);
@ -6259,7 +6261,7 @@ static void K_drawKartItem(void)
V_DrawScaledPatch(ITEM_X+17, ITEM_Y+13-offset, V_HUDTRANS|splitflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]);
}
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, boolean playing)
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode)
{
// TIME_X = BASEVIDWIDTH-124; // 196
// TIME_Y = 6; // 6
@ -6267,7 +6269,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo
tic_t worktime;
INT32 splitflags = 0;
if (playing)
if (!mode)
{
splitflags = V_HUDTRANS|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTORIGHT);
if (cv_timelimit.value && timelimitintics > 0)
@ -6279,13 +6281,13 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo
}
}
V_DrawScaledPatch(TX, TY, splitflags, kp_timestickerwide);
V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide));
TX += 33;
worktime = drawtime/(60*TICRATE);
if (!playing && !drawtime)
if (mode && !drawtime)
V_DrawKartString(TX, TY+3, splitflags, va("--'--\"--"));
else if (worktime < 100) // 99:99:99 only
{
@ -6335,7 +6337,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo
else if ((drawtime/TICRATE) & 1)
V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99"));
if (emblemmap && (modeattacking || !playing)) // emblem time!
if (emblemmap && (modeattacking || (mode == 1))) // emblem time!
{
INT32 workx = TX + 96, worky = TY+18;
SINT8 curemb = 0;
@ -6368,7 +6370,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo
G_TicsToSeconds(timetoreach),
G_TicsToCentiseconds(timetoreach));
if (playing)
if (!mode)
{
if (stplyr->realtime > timetoreach)
{
@ -6400,7 +6402,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo
emblem = M_GetLevelEmblems(-1);
}
if (playing)
if (!mode)
splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS;
while (curemb--)
{
@ -7798,7 +7800,7 @@ void K_drawKartHUD(void)
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_time))
#endif
K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, true);
K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, 0);
if (!modeattacking)
{

View file

@ -67,7 +67,7 @@ void K_LoadKartHUDGraphics(void);
fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my);
void K_drawKartHUD(void);
void K_drawKartFreePlay(UINT32 flashtime);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, boolean playing);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
// =========================================================================
#endif // __K_KART__

View file

@ -117,27 +117,27 @@ void M_SetupDefaultConditionSets(void)
{
memset(conditionSets, 0, sizeof(conditionSets));
// -- 1: Collect 5 emblems OR play 10 matches
// -- 1: Collect 5 medals OR play 10 matches
M_AddRawCondition(1, 1, UC_TOTALEMBLEMS, 5, 0, 0);
M_AddRawCondition(1, 2, UC_MATCHESPLAYED, 10, 0, 0);
// -- 2: Collect 10 emblems OR play 25 matches
// -- 2: Collect 10 medals OR play 25 matches
M_AddRawCondition(2, 1, UC_TOTALEMBLEMS, 10, 0, 0);
M_AddRawCondition(2, 2, UC_MATCHESPLAYED, 25, 0, 0);
// -- 3: Collect 20 emblems OR play 50 matches
// -- 3: Collect 20 medals OR play 50 matches
M_AddRawCondition(3, 1, UC_TOTALEMBLEMS, 20, 0, 0);
M_AddRawCondition(3, 2, UC_MATCHESPLAYED, 50, 0, 0);
// -- 4: Collect 30 emblems OR play 100 matches
// -- 4: Collect 30 medals OR play 100 matches
M_AddRawCondition(4, 1, UC_TOTALEMBLEMS, 30, 0, 0);
M_AddRawCondition(4, 2, UC_MATCHESPLAYED, 100, 0, 0);
// -- 5: Collect 40 emblems OR play 150 matches
// -- 5: Collect 40 medals OR play 150 matches
M_AddRawCondition(5, 1, UC_TOTALEMBLEMS, 40, 0, 0);
M_AddRawCondition(5, 2, UC_MATCHESPLAYED, 150, 0, 0);
// -- 6: Collect 50 emblems ONLY
// -- 6: Collect 50 medals ONLY
M_AddRawCondition(6, 1, UC_TOTALEMBLEMS, 50, 0, 0);
// -- 10: Play 300 matches
@ -318,7 +318,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(boolean force)
continue;
if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false)
{
strcat(cechoText, va(M_GetText("Got \"%s\" emblem!\\"), extraemblems[i].name));
strcat(cechoText, va(M_GetText("Got \"%s\" medal!\\"), extraemblems[i].name));
++cechoLines;
}
}

View file

@ -595,7 +595,7 @@ static menuitem_t SPauseMenu[] =
{
// Pandora's Box will be shifted up if both options are available
{IT_CALL | IT_STRING, NULL, "Pandora's Box...", M_PandorasBox, 16},
{IT_CALL | IT_STRING, NULL, "Emblem Hints...", M_EmblemHints, 24},
{IT_CALL | IT_STRING, NULL, "Medal Hints...", M_EmblemHints, 24},
//{IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32},
{IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48},
@ -741,7 +741,7 @@ static menuitem_t SR_UnlockChecklistMenu[] =
static menuitem_t SR_EmblemHintMenu[] =
{
{IT_STRING|IT_CVAR, NULL, "Emblem Radar", &cv_itemfinder, 10},
{IT_STRING|IT_CVAR, NULL, "Medal Radar", &cv_itemfinder, 10},
{IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SPauseDef, 20}
};
@ -1475,7 +1475,7 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 40},
{IT_STRING | IT_CVAR, NULL, "Map Progression", &cv_advancemap, 50},
{IT_STRING | IT_CVAR, NULL, "Voting Timer", &cv_votetime, 60},
{IT_STRING | IT_CVAR, NULL, "Voting Rule Changes", &cv_kartvoterulechanges, 70},
{IT_STRING | IT_CVAR, NULL, "Voting Rule Changes", &cv_kartvoterulechanges, 70},
#ifndef NONET
{IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 90},
@ -2035,7 +2035,6 @@ static void Nextmap_OnChange(void)
{
char *leveltitle;
UINT8 active;
lumpnum_t l;
// Update the string in the consvar.
Z_Free(cv_nextmap.zstring);
@ -2095,7 +2094,9 @@ static void Nextmap_OnChange(void)
SP_GhostMenu[3].status = IT_STRING|IT_CVAR;
active |= 3;
}
if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) != LUMPERROR)
CV_SetValue(&cv_dummystaff, 1);
if (cv_dummystaff.value)
{
SP_ReplayMenu[4].status = IT_WHITESTRING|IT_KEYHANDLER;
SP_GhostMenu[4].status = IT_STRING|IT_CVAR;
@ -2148,9 +2149,14 @@ static void Dummymenuplayer_OnChange(void)
}
}*/
char dummystaffname[22];
static void Dummystaff_OnChange(void)
{
lumpnum_t l;
dummystaffname[0] = '\0';
if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR)
{
CV_StealthSetValue(&cv_dummystaff, 0);
@ -2158,14 +2164,25 @@ static void Dummystaff_OnChange(void)
}
else
{
char *temp = dummystaffname;
UINT8 numstaff = 1;
while (numstaff < 100 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR)
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR)
numstaff++;
if (cv_dummystaff.value < 1)
CV_StealthSetValue(&cv_dummystaff, numstaff);
else if (cv_dummystaff.value > numstaff)
CV_StealthSetValue(&cv_dummystaff, 1);
if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR)
return; // shouldn't happen but might as well check...
G_UpdateStaffGhostName(l);
while (*temp)
temp++;
sprintf(temp, " - %d", cv_dummystaff.value);
}
}
@ -5130,9 +5147,9 @@ static char *M_GetConditionString(condition_t cond)
G_TicsToSeconds(cond.requirement),
G_TicsToCentiseconds(cond.requirement));
case UC_TOTALEMBLEMS:
return va("Get %d emblems", cond.requirement);
return va("Get %d medals", cond.requirement);
case UC_EXTRAEMBLEM:
return va("Get \"%s\" emblem", extraemblems[cond.requirement-1].name);
return va("Get \"%s\" medal", extraemblems[cond.requirement-1].name);
default:
return NULL;
}
@ -5238,7 +5255,7 @@ static void M_DrawEmblemHints(void)
break;
}
if (!j)
V_DrawCenteredString(160, 48, highlightflags, "No hidden emblems on this map.");
V_DrawCenteredString(160, 48, highlightflags, "No hidden medals on this map.");
M_DrawGenericMenu();
}
@ -5536,7 +5553,7 @@ static void M_DrawLoadGameData(void)
V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "PLAY WITHOUT SAVING");
V_DrawCenteredString(ecks + 68, 156, 0, "THIS GAME WILL NOT BE");
V_DrawCenteredString(ecks + 68, 164, 0, "SAVED, BUT YOU CAN STILL");
V_DrawCenteredString(ecks + 68, 172, 0, "GET EMBLEMS AND SECRETS.");
V_DrawCenteredString(ecks + 68, 172, 0, "GET MEDALS AND SECRETS.");
}
return;
}
@ -6196,7 +6213,7 @@ static void M_DrawStatsMaps(int location)
else if (dotopname)
{
V_DrawString(20, y, highlightflags, "LEVEL NAME");
V_DrawString(248, y, highlightflags, "EMBLEMS");
V_DrawString(256, y, highlightflags, "MEDALS");
y += 8;
dotopname = false;
}
@ -6222,7 +6239,7 @@ static void M_DrawStatsMaps(int location)
if (dotopname && !location)
{
V_DrawString(20, y, highlightflags, "LEVEL NAME");
V_DrawString(248, y, highlightflags, "EMBLEMS");
V_DrawString(256, y, highlightflags, "MEDALS");
y += 8;
}
else if (location)
@ -6233,7 +6250,7 @@ static void M_DrawStatsMaps(int location)
{
if (i == -1)
{
V_DrawString(20, y, highlightflags, "EXTRA EMBLEMS");
V_DrawString(20, y, highlightflags, "EXTRA MEDALS");
if (location)
{
y += 8;
@ -6436,7 +6453,17 @@ void M_DrawTimeAttackMenu(void)
}
}
else if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_KEYHANDLER && cv_dummystaff.value) // bad hacky assumption: IT_KEYHANDLER is assumed to be staff ghost selector
V_DrawString(BASEVIDWIDTH - x - 80 - V_StringWidth(cv_dummystaff.string, 0), y, highlightflags, cv_dummystaff.string);
{
INT32 strw = V_StringWidth(dummystaffname, V_ALLOWLOWERCASE);
V_DrawString(BASEVIDWIDTH - x - strw, y, highlightflags|V_ALLOWLOWERCASE, dummystaffname);
if (i == itemOn)
{
V_DrawCharacter(BASEVIDWIDTH - x - 10 - strw - (skullAnimCounter/5), y,
'\x1C' | highlightflags, false); // left arrow
V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y,
'\x1D' | highlightflags, false); // right arrow
}
}
}
x = currentMenu->x;
@ -6460,10 +6487,10 @@ void M_DrawTimeAttackMenu(void)
V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 239);
V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:");
K_drawKartTimestamp(lap, 19, 86, 0, false);
K_drawKartTimestamp(lap, 19, 86, 0, 2);
V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:");
K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, false);
K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1);
}
/*{
char beststr[40];
@ -6830,9 +6857,7 @@ static void M_ReplayTimeAttack(INT32 choice)
case 2: // last
which = "last";
break;
case 3: // best staff
return; // M_HandleStaffReplay
case 4: // guest
case 3: // guest
// srb2/replay/main/map01-guest.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
return;

View file

@ -211,6 +211,8 @@ extern description_t description[32];
extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort;
extern CV_PossibleValue_t gametype_cons_t[];
extern char dummystaffname[22];
extern INT16 startmap;
extern INT32 ultimate_selectable;

View file

@ -704,7 +704,7 @@ static void Y_UpdateRecordReplays(void)
// Check emblems when level data is updated
if ((earnedEmblems = M_CheckLevelEmblems()))
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
// Update timeattack menu's replay availability.
CV_AddValue(&cv_nextmap, 1);