mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-27 04:21:47 +00:00
Merge branch 'round-queue' into 'master'
roundqueue See merge request KartKrew/Kart!1156
This commit is contained in:
commit
e0901ed7a7
18 changed files with 789 additions and 353 deletions
|
|
@ -6139,7 +6139,7 @@ boolean TryRunTics(tic_t realtics)
|
||||||
{
|
{
|
||||||
COM_BufTicker();
|
COM_BufTicker();
|
||||||
if (mapchangepending)
|
if (mapchangepending)
|
||||||
D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change
|
D_MapChange(-1, 0, encoremode, false, 2, false, forcespecialstage); // finish the map change
|
||||||
}
|
}
|
||||||
|
|
||||||
NetUpdate();
|
NetUpdate();
|
||||||
|
|
|
||||||
11
src/d_main.c
11
src/d_main.c
|
|
@ -1022,8 +1022,9 @@ void D_ClearState(void)
|
||||||
modeattacking = ATTACKING_NONE;
|
modeattacking = ATTACKING_NONE;
|
||||||
marathonmode = 0;
|
marathonmode = 0;
|
||||||
|
|
||||||
// Reset GP
|
// Reset GP and roundqueue
|
||||||
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
||||||
|
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||||
|
|
||||||
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
|
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
|
||||||
maptol = 0;
|
maptol = 0;
|
||||||
|
|
@ -1743,13 +1744,12 @@ void D_SRB2Main(void)
|
||||||
|
|
||||||
// Start up a "minor" grand prix session
|
// Start up a "minor" grand prix session
|
||||||
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
||||||
|
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||||
|
|
||||||
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
|
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
|
||||||
grandprixinfo.encore = false;
|
|
||||||
grandprixinfo.masterbots = false;
|
grandprixinfo.masterbots = false;
|
||||||
|
|
||||||
grandprixinfo.gp = true;
|
grandprixinfo.gp = true;
|
||||||
grandprixinfo.roundnum = 0;
|
|
||||||
grandprixinfo.cup = NULL;
|
grandprixinfo.cup = NULL;
|
||||||
grandprixinfo.wonround = false;
|
grandprixinfo.wonround = false;
|
||||||
|
|
||||||
|
|
@ -2002,11 +2002,6 @@ void D_SRB2Main(void)
|
||||||
D_GameTypeChanged(j);
|
D_GameTypeChanged(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gametyperules & (GTR_BOSS|GTR_CATCHER))
|
|
||||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
|
||||||
else if (gametype != GT_RACE)
|
|
||||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
|
||||||
|
|
||||||
multiplayer = true;
|
multiplayer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
611
src/d_netcmd.c
611
src/d_netcmd.c
|
|
@ -100,6 +100,8 @@ static void Got_DiscordInfo(UINT8 **cp, INT32 playernum);
|
||||||
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum);
|
static void Got_ScheduleTaskcmd(UINT8 **cp, INT32 playernum);
|
||||||
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum);
|
static void Got_ScheduleClearcmd(UINT8 **cp, INT32 playernum);
|
||||||
static void Got_Automatecmd(UINT8 **cp, INT32 playernum);
|
static void Got_Automatecmd(UINT8 **cp, INT32 playernum);
|
||||||
|
static void Got_RequestMapQueuecmd(UINT8 **cp, INT32 playernum);
|
||||||
|
static void Got_MapQueuecmd(UINT8 **cp, INT32 playernum);
|
||||||
static void Got_Cheat(UINT8 **cp, INT32 playernum);
|
static void Got_Cheat(UINT8 **cp, INT32 playernum);
|
||||||
|
|
||||||
static void PointLimit_OnChange(void);
|
static void PointLimit_OnChange(void);
|
||||||
|
|
@ -160,6 +162,7 @@ static void Command_StopMovie_f(void);
|
||||||
static void Command_Map_f(void);
|
static void Command_Map_f(void);
|
||||||
static void Command_RandomMap(void);
|
static void Command_RandomMap(void);
|
||||||
static void Command_RestartLevel(void);
|
static void Command_RestartLevel(void);
|
||||||
|
static void Command_QueueMap_f(void);
|
||||||
static void Command_ResetCamera_f(void);
|
static void Command_ResetCamera_f(void);
|
||||||
|
|
||||||
static void Command_View_f (void);
|
static void Command_View_f (void);
|
||||||
|
|
@ -564,6 +567,8 @@ INT16 numgametypes = GT_FIRSTFREESLOT;
|
||||||
|
|
||||||
boolean forceresetplayers = false;
|
boolean forceresetplayers = false;
|
||||||
boolean deferencoremode = false;
|
boolean deferencoremode = false;
|
||||||
|
boolean forcespecialstage = false;
|
||||||
|
|
||||||
UINT8 splitscreen = 0;
|
UINT8 splitscreen = 0;
|
||||||
INT32 adminplayers[MAXPLAYERS];
|
INT32 adminplayers[MAXPLAYERS];
|
||||||
|
|
||||||
|
|
@ -625,6 +630,8 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||||
"SCHEDULETASK", // XD_SCHEDULETASK
|
"SCHEDULETASK", // XD_SCHEDULETASK
|
||||||
"SCHEDULECLEAR", // XD_SCHEDULECLEAR
|
"SCHEDULECLEAR", // XD_SCHEDULECLEAR
|
||||||
"AUTOMATE", // XD_AUTOMATE
|
"AUTOMATE", // XD_AUTOMATE
|
||||||
|
"REQMAPQUEUE", // XD_REQMAPQUEUE
|
||||||
|
"MAPQUEUE", // XD_MAPQUEUE
|
||||||
};
|
};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
@ -672,6 +679,8 @@ void D_RegisterServerCommands(void)
|
||||||
RegisterNetXCmd(XD_SCHEDULETASK, Got_ScheduleTaskcmd);
|
RegisterNetXCmd(XD_SCHEDULETASK, Got_ScheduleTaskcmd);
|
||||||
RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd);
|
RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd);
|
||||||
RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd);
|
RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd);
|
||||||
|
RegisterNetXCmd(XD_REQMAPQUEUE, Got_RequestMapQueuecmd);
|
||||||
|
RegisterNetXCmd(XD_MAPQUEUE, Got_MapQueuecmd);
|
||||||
|
|
||||||
RegisterNetXCmd(XD_CHEAT, Got_Cheat);
|
RegisterNetXCmd(XD_CHEAT, Got_Cheat);
|
||||||
|
|
||||||
|
|
@ -694,6 +703,7 @@ void D_RegisterServerCommands(void)
|
||||||
COM_AddCommand("map", Command_Map_f);
|
COM_AddCommand("map", Command_Map_f);
|
||||||
COM_AddCommand("randommap", Command_RandomMap);
|
COM_AddCommand("randommap", Command_RandomMap);
|
||||||
COM_AddCommand("restartlevel", Command_RestartLevel);
|
COM_AddCommand("restartlevel", Command_RestartLevel);
|
||||||
|
COM_AddCommand("queuemap", Command_QueueMap_f);
|
||||||
|
|
||||||
COM_AddCommand("exitgame", Command_ExitGame_f);
|
COM_AddCommand("exitgame", Command_ExitGame_f);
|
||||||
COM_AddCommand("retry", Command_Retry_f);
|
COM_AddCommand("retry", Command_Retry_f);
|
||||||
|
|
@ -2502,42 +2512,27 @@ INT32 mapchangepending = 0;
|
||||||
* 63 old events will get reexecuted, with ridiculous results. Just don't do
|
* 63 old events will get reexecuted, with ridiculous results. Just don't do
|
||||||
* it (without setting delay to 1, which is the current solution).
|
* it (without setting delay to 1, which is the current solution).
|
||||||
*
|
*
|
||||||
* \param mapnum Map number to change to.
|
* \param mapnum Map number to change to.
|
||||||
* \param gametype Gametype to switch to.
|
* \param gametype Gametype to switch to.
|
||||||
* \param pencoremode Is this 'Encore Mode'?
|
* \param pencoremode Is this 'Encore Mode'?
|
||||||
* \param resetplayers 1 to reset player scores and lives and such, 0 not to.
|
* \param presetplayers 1 to reset player scores and lives and such, 0 not to.
|
||||||
* \param delay Determines how the function will be executed: 0 to do
|
* \param delay Determines how the function will be executed: 0 to do
|
||||||
* it all right now (must not be done from a menu), 1 to
|
* it all right now (must not be done from a menu), 1 to
|
||||||
* do step one and prepare step two, 2 to do step two.
|
* do step one and prepare step two, 2 to do step two.
|
||||||
* \param skipprecutscene To skip the precutscence or not?
|
* \param skipprecutscene To skip the precutscence or not?
|
||||||
|
* \param pforcespecialstage For certain contexts, forces a special stage.
|
||||||
* \sa D_GameTypeChanged, Command_Map_f
|
* \sa D_GameTypeChanged, Command_Map_f
|
||||||
* \author Graue <graue@oceanbase.org>
|
* \author Graue <graue@oceanbase.org>
|
||||||
*/
|
*/
|
||||||
void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean resetplayers, INT32 delay, boolean skipprecutscene, boolean FLS)
|
void D_MapChange(UINT16 mapnum, INT32 newgametype, boolean pencoremode, boolean presetplayers, INT32 delay, boolean skipprecutscene, boolean pforcespecialstage)
|
||||||
{
|
{
|
||||||
static char buf[2+MAX_WADPATH+1+4];
|
static char buf[1+1+1+1+1+2+4];
|
||||||
static char *buf_p = buf;
|
static char *buf_p = buf;
|
||||||
// The supplied data are assumed to be good.
|
// The supplied data are assumed to be good.
|
||||||
I_Assert(delay >= 0 && delay <= 2);
|
I_Assert(delay >= 0 && delay <= 2);
|
||||||
|
|
||||||
/*
|
CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d pencoremode=%d presetplayers=%d delay=%d skipprecutscene=%d pforcespecialstage = %d\n",
|
||||||
if (mapnum != -1)
|
mapnum, newgametype, pencoremode, presetplayers, delay, skipprecutscene, pforcespecialstage);
|
||||||
{
|
|
||||||
CV_SetValue(&cv_nextmap, mapnum);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d pencoremode=%d resetplayers=%d delay=%d skipprecutscene=%d\n",
|
|
||||||
mapnum, newgametype, pencoremode, resetplayers, delay, skipprecutscene);
|
|
||||||
|
|
||||||
if ((netgame || multiplayer) && (grandprixinfo.gp != false))
|
|
||||||
FLS = false;
|
|
||||||
|
|
||||||
// Too lazy to change the input value for every instance of this function.......
|
|
||||||
if (grandprixinfo.gp == true)
|
|
||||||
{
|
|
||||||
pencoremode = grandprixinfo.encore;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delay != 2)
|
if (delay != 2)
|
||||||
{
|
{
|
||||||
|
|
@ -2546,18 +2541,29 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
|
||||||
buf_p = buf;
|
buf_p = buf;
|
||||||
if (pencoremode)
|
if (pencoremode)
|
||||||
flags |= 1;
|
flags |= 1;
|
||||||
if (!resetplayers)
|
if (presetplayers)
|
||||||
flags |= 1<<1;
|
flags |= 1<<1;
|
||||||
if (skipprecutscene)
|
if (skipprecutscene)
|
||||||
flags |= 1<<2;
|
flags |= 1<<2;
|
||||||
if (FLS)
|
if (pforcespecialstage)
|
||||||
flags |= 1<<3;
|
flags |= 1<<3;
|
||||||
|
if (roundqueue.netcommunicate)
|
||||||
|
flags |= 1<<4;
|
||||||
WRITEUINT8(buf_p, flags);
|
WRITEUINT8(buf_p, flags);
|
||||||
|
|
||||||
// new gametype value
|
if (roundqueue.netcommunicate)
|
||||||
WRITEUINT8(buf_p, newgametype);
|
{
|
||||||
|
// roundqueue state
|
||||||
|
WRITEUINT8(buf_p, roundqueue.position);
|
||||||
|
WRITEUINT8(buf_p, roundqueue.size);
|
||||||
|
WRITEUINT8(buf_p, roundqueue.roundnum);
|
||||||
|
roundqueue.netcommunicate = false;
|
||||||
|
}
|
||||||
|
|
||||||
WRITEINT16(buf_p, mapnum);
|
// new gametype value
|
||||||
|
WRITEUINT16(buf_p, newgametype);
|
||||||
|
|
||||||
|
WRITEUINT16(buf_p, mapnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delay == 1)
|
if (delay == 1)
|
||||||
|
|
@ -2736,6 +2742,64 @@ ConcatCommandArgv (int start, int end)
|
||||||
//
|
//
|
||||||
// Largely rewritten by James.
|
// Largely rewritten by James.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static INT32 GetGametypeParm(size_t option_gametype)
|
||||||
|
{
|
||||||
|
const char *gametypename;
|
||||||
|
INT32 newgametype;
|
||||||
|
|
||||||
|
if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR,
|
||||||
|
"No gametype name follows parameter '%s'.\n",
|
||||||
|
COM_Argv(option_gametype));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new gametype value
|
||||||
|
// use current one by default
|
||||||
|
gametypename = COM_Argv(option_gametype + 1);
|
||||||
|
|
||||||
|
newgametype = G_GetGametypeByName(gametypename);
|
||||||
|
|
||||||
|
if (newgametype == -1) // reached end of the list with no match
|
||||||
|
{
|
||||||
|
/* Did they give us a gametype number? That's okay too! */
|
||||||
|
if (isdigit(gametypename[0]))
|
||||||
|
{
|
||||||
|
INT16 d = atoi(gametypename);
|
||||||
|
if (d >= 0 && d < numgametypes)
|
||||||
|
newgametype = d;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR,
|
||||||
|
"Gametype number %d is out of range. Use a number between"
|
||||||
|
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
||||||
|
d,
|
||||||
|
numgametypes-1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR,
|
||||||
|
"'%s' is not a valid gametype.\n",
|
||||||
|
gametypename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Playing() && netgame && (gametypes[newgametype]->rules & GTR_FORBIDMP))
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR,
|
||||||
|
"'%s' is not a net-compatible gametype.\n",
|
||||||
|
gametypename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newgametype;
|
||||||
|
}
|
||||||
|
|
||||||
static void Command_Map_f(void)
|
static void Command_Map_f(void)
|
||||||
{
|
{
|
||||||
size_t first_option;
|
size_t first_option;
|
||||||
|
|
@ -2743,8 +2807,8 @@ static void Command_Map_f(void)
|
||||||
size_t option_gametype;
|
size_t option_gametype;
|
||||||
size_t option_encore;
|
size_t option_encore;
|
||||||
size_t option_skill;
|
size_t option_skill;
|
||||||
const char *gametypename;
|
|
||||||
boolean newresetplayers;
|
boolean newresetplayers;
|
||||||
|
boolean newforcespecialstage;
|
||||||
|
|
||||||
boolean usingcheats;
|
boolean usingcheats;
|
||||||
boolean ischeating;
|
boolean ischeating;
|
||||||
|
|
@ -2757,8 +2821,6 @@ static void Command_Map_f(void)
|
||||||
INT32 newgametype = gametype;
|
INT32 newgametype = gametype;
|
||||||
boolean newencoremode = (cv_kartencore.value == 1);
|
boolean newencoremode = (cv_kartencore.value == 1);
|
||||||
|
|
||||||
INT32 d;
|
|
||||||
|
|
||||||
if (client && !IsPlayerAdmin(consoleplayer))
|
if (client && !IsPlayerAdmin(consoleplayer))
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||||
|
|
@ -2770,28 +2832,18 @@ static void Command_Map_f(void)
|
||||||
option_encore = COM_CheckPartialParm("-e");
|
option_encore = COM_CheckPartialParm("-e");
|
||||||
option_skill = COM_CheckPartialParm("-s");
|
option_skill = COM_CheckPartialParm("-s");
|
||||||
newresetplayers = ! COM_CheckParm("-noresetplayers");
|
newresetplayers = ! COM_CheckParm("-noresetplayers");
|
||||||
|
newforcespecialstage = COM_CheckParm("-forcespecialstage");
|
||||||
|
|
||||||
usingcheats = CV_CheatsEnabled();
|
usingcheats = CV_CheatsEnabled();
|
||||||
ischeating = (!(netgame || multiplayer)) || (!newresetplayers);
|
ischeating = (!(netgame || multiplayer)) || (!newresetplayers);
|
||||||
|
|
||||||
if (option_gametype)
|
|
||||||
{
|
|
||||||
if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"No gametype name follows parameter '%s'.\n",
|
|
||||||
COM_Argv(option_gametype));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!( first_option = COM_FirstOption() ))
|
if (!( first_option = COM_FirstOption() ))
|
||||||
first_option = COM_Argc();
|
first_option = COM_Argc();
|
||||||
|
|
||||||
if (first_option < 2)
|
if (first_option < 2)
|
||||||
{
|
{
|
||||||
/* I'm going over the fucking lines and I DON'T CAREEEEE */
|
/* I'm going over the fucking lines and I DON'T CAREEEEE */
|
||||||
CONS_Printf("map <name / [MAP]code / number> [-gametype <type>] [-force]:\n");
|
CONS_Printf("map <name / number> [-gametype <type>] [-force]:\n");
|
||||||
CONS_Printf(M_GetText(
|
CONS_Printf(M_GetText(
|
||||||
"Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n"
|
"Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n"
|
||||||
"All parameters are case-insensitive and may be abbreviated.\n"));
|
"All parameters are case-insensitive and may be abbreviated.\n"));
|
||||||
|
|
@ -2824,46 +2876,9 @@ static void Command_Map_f(void)
|
||||||
// use current one by default
|
// use current one by default
|
||||||
if (option_gametype)
|
if (option_gametype)
|
||||||
{
|
{
|
||||||
gametypename = COM_Argv(option_gametype + 1);
|
newgametype = GetGametypeParm(option_gametype);
|
||||||
|
if (newgametype == -1)
|
||||||
newgametype = G_GetGametypeByName(gametypename);
|
|
||||||
|
|
||||||
if (newgametype == -1) // reached end of the list with no match
|
|
||||||
{
|
{
|
||||||
/* Did they give us a gametype number? That's okay too! */
|
|
||||||
if (isdigit(gametypename[0]))
|
|
||||||
{
|
|
||||||
d = atoi(gametypename);
|
|
||||||
if (d >= 0 && d < numgametypes)
|
|
||||||
newgametype = d;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"Gametype number %d is out of range. Use a number between"
|
|
||||||
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
|
||||||
d,
|
|
||||||
numgametypes-1);
|
|
||||||
Z_Free(realmapname);
|
|
||||||
Z_Free(mapname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"'%s' is not a valid gametype.\n",
|
|
||||||
gametypename);
|
|
||||||
Z_Free(realmapname);
|
|
||||||
Z_Free(mapname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Playing() && netgame && (gametypes[newgametype]->rules & GTR_FORBIDMP))
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"'%s' is not a net-compatible gametype.\n",
|
|
||||||
gametypename);
|
|
||||||
Z_Free(realmapname);
|
Z_Free(realmapname);
|
||||||
Z_Free(mapname);
|
Z_Free(mapname);
|
||||||
return;
|
return;
|
||||||
|
|
@ -2907,7 +2922,7 @@ static void Command_Map_f(void)
|
||||||
// don't use a gametype the map doesn't support
|
// don't use a gametype the map doesn't support
|
||||||
if (cht_debug || option_force || cv_skipmapcheck.value)
|
if (cht_debug || option_force || cv_skipmapcheck.value)
|
||||||
{
|
{
|
||||||
fromlevelselect = false; // The player wants us to trek on anyway. Do so.
|
// The player wants us to trek on anyway. Do so.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -2922,12 +2937,6 @@ static void Command_Map_f(void)
|
||||||
Z_Free(mapname);
|
Z_Free(mapname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
fromlevelselect =
|
|
||||||
( netgame || multiplayer ) &&
|
|
||||||
grandprixinfo.gp != false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(netgame || multiplayer))
|
if (!(netgame || multiplayer))
|
||||||
|
|
@ -2972,29 +2981,16 @@ static void Command_Map_f(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grandprixinfo.encore = newencoremode;
|
|
||||||
|
|
||||||
grandprixinfo.gp = true;
|
grandprixinfo.gp = true;
|
||||||
grandprixinfo.roundnum = 0;
|
|
||||||
grandprixinfo.cup = NULL;
|
|
||||||
grandprixinfo.wonround = false;
|
grandprixinfo.wonround = false;
|
||||||
grandprixinfo.initalize = true;
|
|
||||||
|
|
||||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
|
||||||
|
|
||||||
if (gametypes[newgametype]->rules & (GTR_BOSS|GTR_CATCHER))
|
|
||||||
{
|
|
||||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
|
||||||
}
|
|
||||||
else if (newgametype != GT_RACE)
|
|
||||||
{
|
|
||||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Playing())
|
if (!Playing())
|
||||||
{
|
{
|
||||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
UINT8 ssplayers = cv_splitplayers.value-1;
|
||||||
|
|
||||||
|
grandprixinfo.cup = NULL;
|
||||||
|
grandprixinfo.initalize = true;
|
||||||
|
|
||||||
multiplayer = true;
|
multiplayer = true;
|
||||||
restoreMenu = NULL;
|
restoreMenu = NULL;
|
||||||
|
|
||||||
|
|
@ -3011,9 +3007,10 @@ static void Command_Map_f(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, fromlevelselect);
|
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, newforcespecialstage);
|
||||||
|
|
||||||
Z_Free(realmapname);
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Receives a map command and changes the map.
|
/** Receives a map command and changes the map.
|
||||||
|
|
@ -3026,10 +3023,10 @@ static void Command_Map_f(void)
|
||||||
static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
||||||
{
|
{
|
||||||
UINT8 flags;
|
UINT8 flags;
|
||||||
INT32 resetplayer = 1, lastgametype;
|
INT32 presetplayer = 1;
|
||||||
UINT8 skipprecutscene, FLS;
|
UINT8 skipprecutscene, pforcespecialstage;
|
||||||
boolean pencoremode;
|
boolean pencoremode, hasroundqueuedata;
|
||||||
INT16 mapnumber;
|
UINT16 mapnumber, lastgametype;
|
||||||
|
|
||||||
forceresetplayers = deferencoremode = false;
|
forceresetplayers = deferencoremode = false;
|
||||||
|
|
||||||
|
|
@ -3041,17 +3038,51 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chmappending)
|
|
||||||
chmappending--;
|
|
||||||
|
|
||||||
flags = READUINT8(*cp);
|
flags = READUINT8(*cp);
|
||||||
|
|
||||||
pencoremode = ((flags & 1) != 0);
|
pencoremode = ((flags & 1) != 0);
|
||||||
|
|
||||||
resetplayer = ((flags & (1<<1)) == 0);
|
presetplayer = ((flags & (1<<1)) != 0);
|
||||||
|
|
||||||
|
skipprecutscene = ((flags & (1<<2)) != 0);
|
||||||
|
|
||||||
|
pforcespecialstage = ((flags & (1<<3)) != 0);
|
||||||
|
|
||||||
|
hasroundqueuedata = ((flags & (1<<4)) != 0);
|
||||||
|
|
||||||
|
if (hasroundqueuedata)
|
||||||
|
{
|
||||||
|
UINT8 position = READUINT8(*cp);
|
||||||
|
UINT8 size = READUINT8(*cp);
|
||||||
|
UINT8 roundnum = READUINT8(*cp);
|
||||||
|
|
||||||
|
if (playernum != serverplayer // Clients, even admin clients, don't have full roundqueue data
|
||||||
|
|| position > size // Sanity check A (intentionally not a >= comparison)
|
||||||
|
|| size > ROUNDQUEUE_MAX) // Sanity Check B (ditto)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_WARNING, M_GetText("Illegal round-queue data received from %s\n"), player_names[playernum]);
|
||||||
|
if (server && playernum != serverplayer)
|
||||||
|
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
roundqueue.position = position;
|
||||||
|
while (roundqueue.size < size)
|
||||||
|
{
|
||||||
|
// We wipe rather than provide full data to prevent bloating the packet,
|
||||||
|
// and because only this data is necessary for sync. ~toast 100423
|
||||||
|
memset(&roundqueue.entries[roundqueue.size], 0, sizeof(roundentry_t));
|
||||||
|
roundqueue.size++;
|
||||||
|
}
|
||||||
|
roundqueue.roundnum = roundnum; // no sanity checking required, server is authoriative
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more kicks below this line, we can now start modifying state beyond this function.
|
||||||
|
if (chmappending)
|
||||||
|
chmappending--;
|
||||||
|
|
||||||
lastgametype = gametype;
|
lastgametype = gametype;
|
||||||
gametype = READUINT8(*cp);
|
gametype = READUINT16(*cp);
|
||||||
G_SetGametype(gametype); // I fear putting that macro as an argument
|
G_SetGametype(gametype); // I fear putting that macro as an argument
|
||||||
|
|
||||||
if (gametype < 0 || gametype >= numgametypes)
|
if (gametype < 0 || gametype >= numgametypes)
|
||||||
|
|
@ -3059,14 +3090,46 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
||||||
else if (gametype != lastgametype)
|
else if (gametype != lastgametype)
|
||||||
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
|
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
|
||||||
|
|
||||||
|
if (hasroundqueuedata && roundqueue.position > 0 && roundqueue.size > 0)
|
||||||
|
{
|
||||||
|
// ...we can evaluate CURRENT specifics for roundqueue data, though.
|
||||||
|
roundqueue.entries[roundqueue.position-1].gametype = gametype;
|
||||||
|
roundqueue.entries[roundqueue.position-1].encore = pencoremode;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(gametyperules & GTR_ENCORE))
|
if (!(gametyperules & GTR_ENCORE))
|
||||||
pencoremode = false;
|
pencoremode = false;
|
||||||
|
|
||||||
skipprecutscene = ((flags & (1<<2)) != 0);
|
mapnumber = READUINT16(*cp);
|
||||||
|
|
||||||
FLS = ((flags & (1<<3)) != 0);
|
// Handle some Grand Prix state.
|
||||||
|
if (grandprixinfo.gp)
|
||||||
|
{
|
||||||
|
boolean caughtretry = (gametype == lastgametype
|
||||||
|
&& mapnumber == gamemap);
|
||||||
|
if (pforcespecialstage // Forced.
|
||||||
|
|| (caughtretry && grandprixinfo.eventmode == GPEVENT_SPECIAL) // Catch retries of forced.
|
||||||
|
|| (gametyperules & (GTR_BOSS|GTR_CATCHER))) // Conventional rules.
|
||||||
|
{
|
||||||
|
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||||
|
|
||||||
mapnumber = READINT16(*cp);
|
if (pforcespecialstage == true && gamedata->everseenspecial == false)
|
||||||
|
{
|
||||||
|
gamedata->everseenspecial = true;
|
||||||
|
// No need to do anything else here -- P_LoadLevel will get this for us!
|
||||||
|
//M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||||
|
//gamedata->deferredsave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gametype != GT_RACE)
|
||||||
|
{
|
||||||
|
grandprixinfo.eventmode = GPEVENT_BONUS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grandprixinfo.eventmode = GPEVENT_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (netgame)
|
if (netgame)
|
||||||
P_ClearRandom(READUINT32(*cp));
|
P_ClearRandom(READUINT32(*cp));
|
||||||
|
|
@ -3074,23 +3137,17 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
||||||
if (!skipprecutscene)
|
if (!skipprecutscene)
|
||||||
{
|
{
|
||||||
DEBFILE(va("Warping to %s [resetplayer=%d lastgametype=%d gametype=%d cpnd=%d]\n",
|
DEBFILE(va("Warping to %s [resetplayer=%d lastgametype=%d gametype=%d cpnd=%d]\n",
|
||||||
G_BuildMapName(mapnumber), resetplayer, lastgametype, gametype, chmappending));
|
G_BuildMapName(mapnumber), presetplayer, lastgametype, gametype, chmappending));
|
||||||
CON_LogMessage(M_GetText("Speeding off to level...\n"));
|
CON_LogMessage(M_GetText("Speeding off to level...\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (demo.playback && !demo.timing)
|
if (demo.playback && !demo.timing)
|
||||||
precache = false;
|
precache = false;
|
||||||
|
|
||||||
if (resetplayer && !FLS)
|
|
||||||
{
|
|
||||||
emeralds = 0;
|
|
||||||
memset(&luabanks, 0, sizeof(luabanks));
|
|
||||||
}
|
|
||||||
|
|
||||||
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING;
|
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING;
|
||||||
demo.savebutton = 0;
|
demo.savebutton = 0;
|
||||||
|
|
||||||
G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS);
|
G_InitNew(pencoremode, mapnumber, presetplayer, skipprecutscene);
|
||||||
if (demo.playback && !demo.timing)
|
if (demo.playback && !demo.timing)
|
||||||
precache = true;
|
precache = true;
|
||||||
if (demo.timing)
|
if (demo.timing)
|
||||||
|
|
@ -3124,56 +3181,9 @@ static void Command_RandomMap(void)
|
||||||
|
|
||||||
if ((option_gametype = COM_CheckPartialParm("-g")))
|
if ((option_gametype = COM_CheckPartialParm("-g")))
|
||||||
{
|
{
|
||||||
const char *gametypename;
|
newgametype = GetGametypeParm(option_gametype);
|
||||||
|
if (newgametype == -1)
|
||||||
if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"No gametype name follows parameter '%s'.\n",
|
|
||||||
COM_Argv(option_gametype));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// new gametype value
|
|
||||||
// use current one by default
|
|
||||||
gametypename = COM_Argv(option_gametype + 1);
|
|
||||||
|
|
||||||
newgametype = G_GetGametypeByName(gametypename);
|
|
||||||
|
|
||||||
if (newgametype == -1) // reached end of the list with no match
|
|
||||||
{
|
|
||||||
/* Did they give us a gametype number? That's okay too! */
|
|
||||||
if (isdigit(gametypename[0]))
|
|
||||||
{
|
|
||||||
INT16 d = atoi(gametypename);
|
|
||||||
if (d >= 0 && d < numgametypes)
|
|
||||||
newgametype = d;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"Gametype number %d is out of range. Use a number between"
|
|
||||||
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
|
||||||
d,
|
|
||||||
numgametypes-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"'%s' is not a valid gametype.\n",
|
|
||||||
gametypename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Playing() && netgame && (gametypes[newgametype]->rules & GTR_FORBIDMP))
|
|
||||||
{
|
|
||||||
CONS_Alert(CONS_ERROR,
|
|
||||||
"'%s' is not a net-compatible gametype.\n",
|
|
||||||
gametypename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle singleplayer conditions.
|
// TODO: Handle singleplayer conditions.
|
||||||
|
|
@ -3230,6 +3240,247 @@ static void Command_RestartLevel(void)
|
||||||
D_MapChange(gamemap, gametype, newencore, false, 0, false, false);
|
D_MapChange(gamemap, gametype, newencore, false, 0, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Handle_MapQueueSend(UINT16 newmapnum, UINT16 newgametype, boolean newencoremode)
|
||||||
|
{
|
||||||
|
static char buf[1+2+2];
|
||||||
|
static char *buf_p = buf;
|
||||||
|
|
||||||
|
UINT8 flags = 0;
|
||||||
|
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "Map queue: mapnum=%d newgametype=%d newencoremode=%d\n",
|
||||||
|
newmapnum, newgametype, newencoremode);
|
||||||
|
|
||||||
|
buf_p = buf;
|
||||||
|
|
||||||
|
if (newencoremode)
|
||||||
|
flags |= 1;
|
||||||
|
|
||||||
|
WRITEUINT8(buf_p, flags);
|
||||||
|
WRITEUINT16(buf_p, newgametype);
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
{
|
||||||
|
WRITEUINT16(buf_p, newmapnum);
|
||||||
|
SendNetXCmd(XD_REQMAPQUEUE, buf, buf_p - buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITEUINT8(buf_p, roundqueue.size);
|
||||||
|
SendNetXCmd(XD_MAPQUEUE, buf, buf_p - buf);
|
||||||
|
|
||||||
|
G_MapIntoRoundQueue(newmapnum, newgametype, newencoremode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Command_QueueMap_f(void)
|
||||||
|
{
|
||||||
|
size_t first_option;
|
||||||
|
size_t option_force;
|
||||||
|
size_t option_gametype;
|
||||||
|
size_t option_encore;
|
||||||
|
|
||||||
|
boolean usingcheats;
|
||||||
|
boolean ischeating;
|
||||||
|
|
||||||
|
INT32 newmapnum;
|
||||||
|
|
||||||
|
char * mapname;
|
||||||
|
char *realmapname = NULL;
|
||||||
|
|
||||||
|
INT32 newgametype = gametype;
|
||||||
|
boolean newencoremode = (cv_kartencore.value == 1);
|
||||||
|
|
||||||
|
if (!Playing())
|
||||||
|
{
|
||||||
|
CONS_Printf(M_GetText("Levels can only be queued in-game.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client && !IsPlayerAdmin(consoleplayer))
|
||||||
|
{
|
||||||
|
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.size >= ROUNDQUEUE_MAX)
|
||||||
|
{
|
||||||
|
CONS_Printf(M_GetText("Round queue is currently full.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
option_force = COM_CheckPartialParm("-f");
|
||||||
|
option_gametype = COM_CheckPartialParm("-g");
|
||||||
|
option_encore = COM_CheckPartialParm("-e");
|
||||||
|
|
||||||
|
usingcheats = CV_CheatsEnabled();
|
||||||
|
ischeating = (!(netgame || multiplayer));
|
||||||
|
|
||||||
|
if (!( first_option = COM_FirstOption() ))
|
||||||
|
first_option = COM_Argc();
|
||||||
|
|
||||||
|
if (first_option < 2)
|
||||||
|
{
|
||||||
|
/* I'm going over the fucking lines and I DON'T CAREEEEE */
|
||||||
|
CONS_Printf("queuemap <name / number> [-gametype <type>] [-force]:\n");
|
||||||
|
CONS_Printf(M_GetText(
|
||||||
|
"Queue up a map by its name, or by its number (though why would you).\n"
|
||||||
|
"All parameters are case-insensitive and may be abbreviated.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapname = ConcatCommandArgv(1, first_option);
|
||||||
|
|
||||||
|
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
|
||||||
|
|
||||||
|
if (newmapnum == 0)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!K_CanChangeRules(false) || (/*newmapnum != 1 &&*/ M_MapLocked(newmapnum)))
|
||||||
|
{
|
||||||
|
ischeating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ischeating && !usingcheats)
|
||||||
|
{
|
||||||
|
CONS_Printf(M_GetText("Cheats must be enabled.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new gametype value
|
||||||
|
// use current one by default
|
||||||
|
if (option_gametype)
|
||||||
|
{
|
||||||
|
newgametype = GetGametypeParm(option_gametype);
|
||||||
|
if (newgametype == -1)
|
||||||
|
{
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new encoremode value
|
||||||
|
if (option_encore)
|
||||||
|
{
|
||||||
|
newencoremode = !newencoremode;
|
||||||
|
|
||||||
|
if (!M_SecretUnlocked(SECRET_ENCORE, false) && newencoremode == true && !usingcheats)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't use a gametype the map doesn't support
|
||||||
|
if (cht_debug || option_force || cv_skipmapcheck.value)
|
||||||
|
{
|
||||||
|
// The player wants us to trek on anyway. Do so.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
|
||||||
|
if (!(
|
||||||
|
mapheaderinfo[newmapnum-1] &&
|
||||||
|
mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)
|
||||||
|
))
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum), gametypes[newgametype]->name);
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle_MapQueueSend(newmapnum-1, newgametype, newencoremode);
|
||||||
|
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Got_RequestMapQueuecmd(UINT8 **cp, INT32 playernum)
|
||||||
|
{
|
||||||
|
UINT8 flags;
|
||||||
|
boolean setencore;
|
||||||
|
UINT16 mapnumber, setgametype;
|
||||||
|
|
||||||
|
flags = READUINT8(*cp);
|
||||||
|
|
||||||
|
setencore = ((flags & 1) != 0);
|
||||||
|
|
||||||
|
setgametype = READUINT16(*cp);
|
||||||
|
|
||||||
|
mapnumber = READUINT16(*cp);
|
||||||
|
|
||||||
|
if (!IsPlayerAdmin(playernum))
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_WARNING, M_GetText("Illegal request map queue command received from %s\n"), player_names[playernum]);
|
||||||
|
if (server && playernum != serverplayer)
|
||||||
|
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.size >= ROUNDQUEUE_MAX)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "queuemap: Unable to add map beyond %u\n", roundqueue.size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Handle_MapQueueSend(mapnumber, setgametype, setencore);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Got_MapQueuecmd(UINT8 **cp, INT32 playernum)
|
||||||
|
{
|
||||||
|
UINT8 flags, queueposition;
|
||||||
|
boolean setencore;
|
||||||
|
UINT16 setgametype;
|
||||||
|
|
||||||
|
flags = READUINT8(*cp);
|
||||||
|
|
||||||
|
setencore = ((flags & 1) != 0);
|
||||||
|
|
||||||
|
setgametype = READUINT16(*cp);
|
||||||
|
|
||||||
|
queueposition = READUINT8(*cp);
|
||||||
|
|
||||||
|
if (playernum != serverplayer)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_WARNING, M_GetText("Illegal map queue command received from %s\n"), player_names[playernum]);
|
||||||
|
if (server)
|
||||||
|
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queueposition >= ROUNDQUEUE_MAX)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "queuemap: Unable to add map beyond %u\n", roundqueue.size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (roundqueue.size <= queueposition)
|
||||||
|
{
|
||||||
|
memset(&roundqueue.entries[roundqueue.size], 0, sizeof(roundentry_t));
|
||||||
|
roundqueue.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_MapSlipIntoRoundQueue(queueposition, 0, setgametype, setencore, false);
|
||||||
|
|
||||||
|
if (!IsPlayerAdmin(playernum))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CONS_Printf("queuemap: A map was successfully added to the round queue (position %u)\n", queueposition);
|
||||||
|
}
|
||||||
|
|
||||||
static void Command_Pause(void)
|
static void Command_Pause(void)
|
||||||
{
|
{
|
||||||
UINT8 buf[2];
|
UINT8 buf[2];
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,8 @@ typedef enum
|
||||||
XD_SCHEDULETASK, // 34
|
XD_SCHEDULETASK, // 34
|
||||||
XD_SCHEDULECLEAR, // 35
|
XD_SCHEDULECLEAR, // 35
|
||||||
XD_AUTOMATE, // 36
|
XD_AUTOMATE, // 36
|
||||||
|
XD_REQMAPQUEUE, // 37
|
||||||
|
XD_MAPQUEUE, // 38
|
||||||
|
|
||||||
MAXNETXCMD
|
MAXNETXCMD
|
||||||
} netxcmd_t;
|
} netxcmd_t;
|
||||||
|
|
@ -237,7 +239,7 @@ void D_SendPlayerConfig(UINT8 n);
|
||||||
void Command_ExitGame_f(void);
|
void Command_ExitGame_f(void);
|
||||||
void Command_Retry_f(void);
|
void Command_Retry_f(void);
|
||||||
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
|
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
|
||||||
void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
|
void D_MapChange(UINT16 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pforcespecialstage);
|
||||||
void D_SetupVote(void);
|
void D_SetupVote(void);
|
||||||
void D_ModifyClientVote(UINT8 player, SINT8 voted);
|
void D_ModifyClientVote(UINT8 player, SINT8 voted);
|
||||||
void D_PickVote(void);
|
void D_PickVote(void);
|
||||||
|
|
|
||||||
|
|
@ -182,8 +182,7 @@ extern boolean multiplayer;
|
||||||
extern UINT8 splitscreen;
|
extern UINT8 splitscreen;
|
||||||
extern int r_splitscreen;
|
extern int r_splitscreen;
|
||||||
|
|
||||||
extern boolean fromlevelselect;
|
extern boolean forceresetplayers, deferencoremode, forcespecialstage;
|
||||||
extern boolean forceresetplayers, deferencoremode;
|
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// Internal parameters for sound rendering.
|
// Internal parameters for sound rendering.
|
||||||
|
|
|
||||||
|
|
@ -3455,7 +3455,7 @@ void G_DoPlayDemo(char *defdemoname)
|
||||||
P_SetRandSeed(i, randseed[i]);
|
P_SetRandSeed(i, randseed[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
G_InitNew(demoflags & DF_ENCORE, gamemap, true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
G_InitNew(demoflags & DF_ENCORE, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
||||||
|
|
||||||
for (i = 0; i < numslots; i++)
|
for (i = 0; i < numslots; i++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
286
src/g_game.c
286
src/g_game.c
|
|
@ -4003,117 +4003,215 @@ static void G_HandleSaveLevel(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next map apparatus
|
||||||
|
struct roundqueue roundqueue;
|
||||||
|
|
||||||
|
void G_MapSlipIntoRoundQueue(UINT8 position, UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted)
|
||||||
|
{
|
||||||
|
I_Assert(position < ROUNDQUEUE_MAX);
|
||||||
|
|
||||||
|
roundqueue.entries[position].mapnum = map;
|
||||||
|
roundqueue.entries[position].gametype = setgametype;
|
||||||
|
roundqueue.entries[position].encore = setencore;
|
||||||
|
roundqueue.entries[position].rankrestricted = rankrestricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G_MapIntoRoundQueue(UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted)
|
||||||
|
{
|
||||||
|
if (roundqueue.size >= ROUNDQUEUE_MAX)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, "G_MapIntoRoundQueue: Unable to add map beyond %u\n", roundqueue.size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_MapSlipIntoRoundQueue(roundqueue.size, map, setgametype, setencore, rankrestricted);
|
||||||
|
roundqueue.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencore)
|
||||||
|
{
|
||||||
|
UINT8 i, levelindex = 0, bonusindex = 0;
|
||||||
|
UINT8 bonusmodulo = (cup->numlevels+1)/(cup->numbonus+1);
|
||||||
|
UINT16 cupLevelNum;
|
||||||
|
|
||||||
|
// Levels are added to the queue in the following pattern.
|
||||||
|
// For 5 Race rounds and 2 Bonus rounds, the most common case:
|
||||||
|
// race - race - BONUS - race - race - BONUS - race
|
||||||
|
// The system is flexible enough to permit other arrangements.
|
||||||
|
// However, we just want to keep the pacing even & consistent.
|
||||||
|
while (levelindex < cup->numlevels)
|
||||||
|
{
|
||||||
|
// Fill like two or three Race maps.
|
||||||
|
for (i = 0; i < bonusmodulo; i++)
|
||||||
|
{
|
||||||
|
cupLevelNum = cup->cachedlevels[levelindex];
|
||||||
|
|
||||||
|
if (cupLevelNum >= nummapheaders)
|
||||||
|
{
|
||||||
|
// For invalid Race maps, we keep the pacing by going to TEST RUN.
|
||||||
|
// It transparently lets the user know something is wrong.
|
||||||
|
cupLevelNum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_MapIntoRoundQueue(
|
||||||
|
cupLevelNum,
|
||||||
|
setgametype,
|
||||||
|
setencore, // *probably* correct
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
levelindex++;
|
||||||
|
if (levelindex >= cup->numlevels)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to add an interstitial Bonus round.
|
||||||
|
if (levelindex < cup->numlevels
|
||||||
|
&& bonusindex < cup->numbonus)
|
||||||
|
{
|
||||||
|
cupLevelNum = cup->cachedlevels[CUPCACHE_BONUS + bonusindex];
|
||||||
|
|
||||||
|
if (cupLevelNum < nummapheaders)
|
||||||
|
{
|
||||||
|
// In the case of Bonus rounds, we simply skip invalid maps.
|
||||||
|
G_MapIntoRoundQueue(
|
||||||
|
cupLevelNum,
|
||||||
|
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel),
|
||||||
|
setencore, // if this isn't correct, Got_Mapcmd will fix it
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bonusindex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...but there's one last trick up our sleeves.
|
||||||
|
// At the end of the Cup is a Rank-restricted treat.
|
||||||
|
// So we append it to the end of the roundqueue.
|
||||||
|
// (as long as it exists, of course!)
|
||||||
|
cupLevelNum = cup->cachedlevels[CUPCACHE_SPECIAL];
|
||||||
|
if (cupLevelNum < nummapheaders)
|
||||||
|
{
|
||||||
|
G_MapIntoRoundQueue(
|
||||||
|
cupLevelNum,
|
||||||
|
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel),
|
||||||
|
setencore, // if this isn't correct, Got_Mapcmd will fix it
|
||||||
|
true // Rank-restricted!
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.size == 0)
|
||||||
|
{
|
||||||
|
I_Error("G_CupToRoundQueue: roundqueue size is 0 after population!?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void G_GetNextMap(void)
|
static void G_GetNextMap(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
boolean setalready = false;
|
||||||
|
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
// Server is authoriative, not you
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deferencoremode = (cv_kartencore.value == 1);
|
||||||
|
forceresetplayers = forcespecialstage = false;
|
||||||
|
|
||||||
// go to next level
|
// go to next level
|
||||||
// nextmap is 0-based, unlike gamemap
|
// nextmap is 0-based, unlike gamemap
|
||||||
if (nextmapoverride != 0)
|
if (nextmapoverride != 0)
|
||||||
{
|
{
|
||||||
nextmap = (INT16)(nextmapoverride-1);
|
nextmap = (INT16)(nextmapoverride-1);
|
||||||
|
setalready = true;
|
||||||
}
|
}
|
||||||
else if (grandprixinfo.gp == true)
|
else if (roundqueue.size > 0)
|
||||||
{
|
{
|
||||||
if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session
|
boolean permitrank = false;
|
||||||
|
if (grandprixinfo.gp == true
|
||||||
|
&& grandprixinfo.gamespeed >= KARTSPEED_NORMAL)
|
||||||
{
|
{
|
||||||
nextmap = prevmap; // Same map
|
// On A rank pace? Then you get a chance for S rank!
|
||||||
|
permitrank = (K_CalculateGPGrade(&grandprixinfo.rank) >= GRADE_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (roundqueue.position < roundqueue.size
|
||||||
|
&& (roundqueue.entries[roundqueue.position].mapnum >= nummapheaders
|
||||||
|
|| mapheaderinfo[roundqueue.entries[roundqueue.position].mapnum] == NULL
|
||||||
|
|| (netgame && (gametypes[roundqueue.entries[roundqueue.position].gametype]->rules & GTR_FORBIDMP))
|
||||||
|
|| (permitrank == false && roundqueue.entries[roundqueue.position].rankrestricted == true)))
|
||||||
|
{
|
||||||
|
// Skip all restricted queue entries.
|
||||||
|
roundqueue.position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.position < roundqueue.size)
|
||||||
|
{
|
||||||
|
// The next entry in the queue is valid; set it as nextmap!
|
||||||
|
nextmap = roundqueue.entries[roundqueue.position].mapnum;
|
||||||
|
deferencoremode = roundqueue.entries[roundqueue.position].encore;
|
||||||
|
|
||||||
|
// And we handle gametype changes, too.
|
||||||
|
if (roundqueue.entries[roundqueue.position].gametype != gametype)
|
||||||
|
{
|
||||||
|
INT32 lastgametype = gametype;
|
||||||
|
G_SetGametype(roundqueue.entries[roundqueue.position].gametype);
|
||||||
|
D_GameTypeChanged(lastgametype);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this special..?
|
||||||
|
forcespecialstage = roundqueue.entries[roundqueue.position].rankrestricted;
|
||||||
|
|
||||||
|
// On entering roundqueue mode, kill the non-PWR between-round scores.
|
||||||
|
// This makes it viable as a future tournament mode base.
|
||||||
|
if (roundqueue.position == 0)
|
||||||
|
{
|
||||||
|
forceresetplayers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle primary queue position update.
|
||||||
|
roundqueue.position++;
|
||||||
|
if (grandprixinfo.gp == false || gametype == roundqueue.entries[0].gametype)
|
||||||
|
{
|
||||||
|
roundqueue.roundnum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
setalready = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INT32 lastgametype = gametype, newgametype = GT_RACE;
|
// Wipe the queue info.
|
||||||
// 5 levels, 2 bonus stages: after rounds 2 and 4 (but flexible enough to accomodate other solutions)
|
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||||
UINT8 bonusmodulo = (grandprixinfo.cup->numlevels+1)/(grandprixinfo.cup->numbonus+1);
|
|
||||||
UINT8 bonusindex = (grandprixinfo.roundnum / bonusmodulo) - 1;
|
|
||||||
|
|
||||||
// If we're in a GP event, don't immediately follow it up with another.
|
if (grandprixinfo.gp == true)
|
||||||
// I also suspect this will not work with online GP so I'm gonna prevent it right now.
|
|
||||||
// The server might have to communicate eventmode (alongside other GP data) in XD_MAP later.
|
|
||||||
if (netgame)
|
|
||||||
;
|
|
||||||
else if (grandprixinfo.eventmode != GPEVENT_NONE)
|
|
||||||
{
|
{
|
||||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
// In GP, we're now ready to go to the ceremony.
|
||||||
|
nextmap = NEXTMAP_CEREMONY;
|
||||||
G_SetGametype(GT_RACE);
|
setalready = true;
|
||||||
if (gametype != lastgametype)
|
|
||||||
D_GameTypeChanged(lastgametype);
|
|
||||||
}
|
|
||||||
// Special stage
|
|
||||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
|
||||||
{
|
|
||||||
gp_rank_e grade = K_CalculateGPGrade(&grandprixinfo.rank);
|
|
||||||
|
|
||||||
if (grade >= GRADE_A && grandprixinfo.gamespeed >= KARTSPEED_NORMAL) // On A rank pace? Then you get a chance for S rank!
|
|
||||||
{
|
|
||||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL];
|
|
||||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
|
||||||
{
|
|
||||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
|
||||||
nextmap = cupLevelNum;
|
|
||||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
|
|
||||||
|
|
||||||
if (gamedata->everseenspecial == false)
|
|
||||||
{
|
|
||||||
gamedata->everseenspecial = true;
|
|
||||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
|
||||||
G_SaveGameData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((grandprixinfo.cup->numbonus > 0)
|
|
||||||
&& (grandprixinfo.roundnum % bonusmodulo) == 0
|
|
||||||
&& bonusindex < MAXBONUSLIST)
|
|
||||||
{
|
|
||||||
// todo any other condition?
|
|
||||||
{
|
|
||||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + bonusindex];
|
|
||||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
|
||||||
{
|
|
||||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
|
||||||
nextmap = cupLevelNum;
|
|
||||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newgametype == -1)
|
|
||||||
{
|
|
||||||
// Don't permit invalid changes.
|
|
||||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
|
||||||
newgametype = gametype;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grandprixinfo.eventmode != GPEVENT_NONE)
|
|
||||||
{
|
|
||||||
G_SetGametype(newgametype);
|
|
||||||
if (gametype != lastgametype)
|
|
||||||
D_GameTypeChanged(lastgametype);
|
|
||||||
}
|
|
||||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map
|
|
||||||
{
|
|
||||||
nextmap = NEXTMAP_CEREMONY; // ceremonymap
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Proceed to next map
|
// On exiting roundqueue mode, kill the non-PWR between-round scores.
|
||||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum];
|
// This prevents future tournament winners from carrying their wins out.
|
||||||
|
forceresetplayers = true;
|
||||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
|
||||||
{
|
|
||||||
nextmap = cupLevelNum;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nextmap = 0; // Prevent uninitialised use -- go to TEST RUN, it's very obvious
|
|
||||||
}
|
|
||||||
|
|
||||||
grandprixinfo.roundnum++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the next D_MapChange sends updated roundqueue state.
|
||||||
|
roundqueue.netcommunicate = true;
|
||||||
}
|
}
|
||||||
else
|
else if (grandprixinfo.gp == true)
|
||||||
|
{
|
||||||
|
// Fast And Rapid Testing
|
||||||
|
// this codepath is exclusively accessible through console/command line
|
||||||
|
nextmap = prevmap;
|
||||||
|
setalready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setalready == false)
|
||||||
{
|
{
|
||||||
UINT32 tolflag = G_TOLFlag(gametype);
|
UINT32 tolflag = G_TOLFlag(gametype);
|
||||||
register INT16 cm;
|
register INT16 cm;
|
||||||
|
|
@ -4257,8 +4355,6 @@ static void G_GetNextMap(void)
|
||||||
if (!spec)
|
if (!spec)
|
||||||
#endif //#if 0
|
#endif //#if 0
|
||||||
lastmap = nextmap;
|
lastmap = nextmap;
|
||||||
|
|
||||||
deferencoremode = (cv_kartencore.value == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -4432,8 +4528,6 @@ void G_NextLevel(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
forceresetplayers = false;
|
|
||||||
|
|
||||||
gameaction = ga_worlddone;
|
gameaction = ga_worlddone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4448,7 +4542,7 @@ static void G_DoWorldDone(void)
|
||||||
forceresetplayers,
|
forceresetplayers,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
false);
|
forcespecialstage);
|
||||||
}
|
}
|
||||||
|
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
|
|
@ -5421,14 +5515,12 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss
|
||||||
// This is the map command interpretation something like Command_Map_f
|
// This is the map command interpretation something like Command_Map_f
|
||||||
//
|
//
|
||||||
// called at: map cmd execution, doloadgame, doplaydemo
|
// called at: map cmd execution, doloadgame, doplaydemo
|
||||||
void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skipprecutscene, boolean FLS)
|
void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skipprecutscene)
|
||||||
{
|
{
|
||||||
const char * mapname = G_BuildMapName(map);
|
const char * mapname = G_BuildMapName(map);
|
||||||
|
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
|
||||||
(void)FLS;
|
|
||||||
|
|
||||||
if (paused)
|
if (paused)
|
||||||
{
|
{
|
||||||
paused = false;
|
paused = false;
|
||||||
|
|
@ -5455,7 +5547,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
||||||
|
|
||||||
players[i].roundscore = 0;
|
players[i].roundscore = 0;
|
||||||
|
|
||||||
if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart
|
if (resetplayer && !demo.playback) // SRB2Kart
|
||||||
{
|
{
|
||||||
players[i].lives = 3;
|
players[i].lives = 3;
|
||||||
players[i].xtralife = 0;
|
players[i].xtralife = 0;
|
||||||
|
|
|
||||||
25
src/g_game.h
25
src/g_game.h
|
|
@ -53,6 +53,29 @@ typedef enum
|
||||||
NEXTMAP_SPECIAL = NEXTMAP_INVALID
|
NEXTMAP_SPECIAL = NEXTMAP_INVALID
|
||||||
} nextmapspecial_t;
|
} nextmapspecial_t;
|
||||||
|
|
||||||
|
#define ROUNDQUEUE_MAX 10 // sane max? maybe make dynamically allocated later
|
||||||
|
|
||||||
|
struct roundentry_t
|
||||||
|
{
|
||||||
|
UINT16 mapnum; // Map number at this position
|
||||||
|
UINT16 gametype; // Gametype we want to play this in
|
||||||
|
boolean encore; // Whether this will be flipped
|
||||||
|
boolean rankrestricted; // For grand prix progression
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct roundqueue
|
||||||
|
{
|
||||||
|
UINT8 roundnum; // Visible number on HUD
|
||||||
|
UINT8 position; // Head position in the round queue
|
||||||
|
UINT8 size; // Number of entries in the round queue
|
||||||
|
boolean netcommunicate; // As server, should we net-communicate this in XD_MAP?
|
||||||
|
roundentry_t entries[ROUNDQUEUE_MAX]; // Entries in the round queue
|
||||||
|
} roundqueue;
|
||||||
|
|
||||||
|
void G_MapSlipIntoRoundQueue(UINT8 position, UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted);
|
||||||
|
void G_MapIntoRoundQueue(UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted);
|
||||||
|
void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencore);
|
||||||
|
|
||||||
extern INT32 gameovertics;
|
extern INT32 gameovertics;
|
||||||
extern UINT8 ammoremovaltics;
|
extern UINT8 ammoremovaltics;
|
||||||
extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
|
extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
|
||||||
|
|
@ -117,7 +140,7 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo);
|
||||||
void G_DoReborn(INT32 playernum);
|
void G_DoReborn(INT32 playernum);
|
||||||
void G_PlayerReborn(INT32 player, boolean betweenmaps);
|
void G_PlayerReborn(INT32 player, boolean betweenmaps);
|
||||||
void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer,
|
void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer,
|
||||||
boolean skipprecutscene, boolean FLS);
|
boolean skipprecutscene);
|
||||||
char *G_BuildMapTitle(INT32 mapnum);
|
char *G_BuildMapTitle(INT32 mapnum);
|
||||||
|
|
||||||
struct searchdim
|
struct searchdim
|
||||||
|
|
|
||||||
|
|
@ -2482,24 +2482,26 @@ static void HU_DrawRankings(void)
|
||||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametypes[gametype]->name);
|
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametypes[gametype]->name);
|
||||||
|
|
||||||
// Left hand side
|
// Left hand side
|
||||||
if (grandprixinfo.gp == true)
|
if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||||
{
|
{
|
||||||
const char *roundstr = NULL;
|
const char *roundstr = NULL;
|
||||||
V_DrawCenteredString(64, 8, 0, "ROUND");
|
V_DrawCenteredString(64, 8, 0, "ROUND");
|
||||||
switch (grandprixinfo.eventmode)
|
switch (grandprixinfo.eventmode)
|
||||||
{
|
{
|
||||||
case GPEVENT_BONUS:
|
|
||||||
roundstr = "BONUS";
|
|
||||||
break;
|
|
||||||
case GPEVENT_SPECIAL:
|
case GPEVENT_SPECIAL:
|
||||||
roundstr = "SPECIAL";
|
roundstr = "SPECIAL";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
roundstr = va("%d", grandprixinfo.roundnum);
|
roundstr = "BONUS";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
V_DrawCenteredString(64, 16, hilicol, roundstr);
|
V_DrawCenteredString(64, 16, hilicol, roundstr);
|
||||||
}
|
}
|
||||||
|
else if (roundqueue.size > 0)
|
||||||
|
{
|
||||||
|
V_DrawCenteredString(64, 8, 0, "ROUND");
|
||||||
|
V_DrawCenteredString(64, 16, hilicol, va("%d", roundqueue.roundnum));
|
||||||
|
}
|
||||||
else if ((gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
else if ((gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
||||||
{
|
{
|
||||||
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
||||||
|
|
|
||||||
|
|
@ -283,10 +283,10 @@ static INT16 K_RivalScore(player_t *bot)
|
||||||
UINT8 lowestdifficulty = MAXBOTDIFFICULTY;
|
UINT8 lowestdifficulty = MAXBOTDIFFICULTY;
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
||||||
if (grandprixinfo.cup != NULL)
|
if (grandprixinfo.cup != NULL && roundqueue.size > 0)
|
||||||
{
|
{
|
||||||
roundnum = grandprixinfo.roundnum;
|
roundnum = roundqueue.roundnum;
|
||||||
roundsleft = grandprixinfo.cup->numlevels - grandprixinfo.roundnum;
|
roundsleft = grandprixinfo.cup->numlevels - roundnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
|
@ -523,8 +523,10 @@ void K_RetireBots(void)
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
||||||
if (grandprixinfo.gp == true
|
if (grandprixinfo.gp == true
|
||||||
&& ((grandprixinfo.cup != NULL && grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
&& (grandprixinfo.eventmode != GPEVENT_NONE
|
||||||
|| grandprixinfo.eventmode != GPEVENT_NONE))
|
|| (grandprixinfo.cup != NULL
|
||||||
|
&& roundqueue.size > 0
|
||||||
|
&& roundqueue.roundnum >= grandprixinfo.cup->numlevels)))
|
||||||
{
|
{
|
||||||
// No replacement.
|
// No replacement.
|
||||||
return;
|
return;
|
||||||
|
|
@ -566,7 +568,11 @@ void K_RetireBots(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||||
newDifficulty = startingdifficulty - 4 + grandprixinfo.roundnum;
|
newDifficulty = startingdifficulty - 4;
|
||||||
|
if (roundqueue.size > 0)
|
||||||
|
{
|
||||||
|
newDifficulty += roundqueue.roundnum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDifficulty > MAXBOTDIFFICULTY)
|
if (newDifficulty > MAXBOTDIFFICULTY)
|
||||||
|
|
@ -697,7 +703,7 @@ void K_PlayerLoseLife(player_t *player)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
boolean K_CanChangeRules(boolean allowdemos)
|
boolean K_CanChangeRules(boolean allowdemos)
|
||||||
{
|
{
|
||||||
if (grandprixinfo.gp == true /*&& grandprixinfo.roundnum > 0*/)
|
if (grandprixinfo.gp == true)
|
||||||
{
|
{
|
||||||
// Don't cheat the rules of the GP!
|
// Don't cheat the rules of the GP!
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ typedef enum
|
||||||
extern struct grandprixinfo
|
extern struct grandprixinfo
|
||||||
{
|
{
|
||||||
boolean gp; ///< If true, then we are in a Grand Prix.
|
boolean gp; ///< If true, then we are in a Grand Prix.
|
||||||
UINT8 roundnum; ///< Round number. If 0, this is a single session from the warp command.
|
|
||||||
cupheader_t *cup; ///< Which cup are we playing?
|
cupheader_t *cup; ///< Which cup are we playing?
|
||||||
UINT8 gamespeed; ///< Copy of gamespeed, just to make sure you can't cheat it with cvars
|
UINT8 gamespeed; ///< Copy of gamespeed, just to make sure you can't cheat it with cvars
|
||||||
boolean encore; ///< Ditto, but for encore mode
|
boolean encore; ///< Ditto, but for encore mode
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ I_mutex k_menu_mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boolean menuactive = false;
|
boolean menuactive = false;
|
||||||
boolean fromlevelselect = false;
|
|
||||||
|
|
||||||
// current menudef
|
// current menudef
|
||||||
menu_t *currentMenu = &MAIN_ProfilesDef;
|
menu_t *currentMenu = &MAIN_ProfilesDef;
|
||||||
|
|
|
||||||
|
|
@ -38,23 +38,38 @@ consvar_t cv_debugencorevote = CVAR_INIT ("debugencorevote", "Off", CV_CHEAT|CV_
|
||||||
|
|
||||||
SINT8 K_UsingPowerLevels(void)
|
SINT8 K_UsingPowerLevels(void)
|
||||||
{
|
{
|
||||||
SINT8 pt = PWRLV_DISABLED;
|
if (!cv_kartusepwrlv.value)
|
||||||
|
|
||||||
if (!cv_kartusepwrlv.value || !(netgame || (demo.playback && demo.netgame)) || grandprixinfo.gp == true)
|
|
||||||
{
|
{
|
||||||
|
// Explicitly forbidden.
|
||||||
|
return PWRLV_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(netgame || (demo.playback && demo.netgame)))
|
||||||
|
{
|
||||||
|
// Servers only.
|
||||||
|
return PWRLV_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundqueue.size > 0 && roundqueue.position > 0)
|
||||||
|
{
|
||||||
|
// When explicit progression is in place, we're going by different rules.
|
||||||
return PWRLV_DISABLED;
|
return PWRLV_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gametype == GT_RACE)
|
if (gametype == GT_RACE)
|
||||||
{
|
{
|
||||||
pt = PWRLV_RACE;
|
// Race PWR.
|
||||||
}
|
return PWRLV_RACE;
|
||||||
else if (gametype == GT_BATTLE)
|
|
||||||
{
|
|
||||||
pt = PWRLV_BATTLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pt;
|
if (gametype == GT_BATTLE)
|
||||||
|
{
|
||||||
|
// Battle PWR.
|
||||||
|
return PWRLV_BATTLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not support PWR for custom gametypes at this moment in time.
|
||||||
|
return PWRLV_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void K_ClearClientPowerLevels(void)
|
void K_ClearClientPowerLevels(void)
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,6 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
|
|
||||||
if (cupgrid.grandprix == true)
|
if (cupgrid.grandprix == true)
|
||||||
{
|
{
|
||||||
INT32 levelNum;
|
|
||||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
UINT8 ssplayers = cv_splitplayers.value-1;
|
||||||
|
|
||||||
S_StartSound(NULL, sfx_s3k63);
|
S_StartSound(NULL, sfx_s3k63);
|
||||||
|
|
@ -130,13 +129,16 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
|
|
||||||
grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value);
|
grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value);
|
||||||
grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3);
|
grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3);
|
||||||
grandprixinfo.encore = (boolean)cv_dummygpencore.value;
|
|
||||||
|
|
||||||
grandprixinfo.cup = newcup;
|
|
||||||
|
|
||||||
grandprixinfo.gp = true;
|
grandprixinfo.gp = true;
|
||||||
grandprixinfo.roundnum = 1;
|
|
||||||
grandprixinfo.initalize = true;
|
grandprixinfo.initalize = true;
|
||||||
|
grandprixinfo.cup = newcup;
|
||||||
|
|
||||||
|
// Populate the roundqueue
|
||||||
|
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||||
|
G_GPCupIntoRoundQueue(newcup, levellist.newgametype, (boolean)cv_dummygpencore.value);
|
||||||
|
roundqueue.position = roundqueue.roundnum = 1;
|
||||||
|
roundqueue.netcommunicate = true; // relevant for future Online GP
|
||||||
|
|
||||||
paused = false;
|
paused = false;
|
||||||
|
|
||||||
|
|
@ -146,16 +148,14 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||||
}
|
}
|
||||||
|
|
||||||
levelNum = grandprixinfo.cup->cachedlevels[0];
|
|
||||||
|
|
||||||
D_MapChange(
|
D_MapChange(
|
||||||
levelNum + 1,
|
roundqueue.entries[0].mapnum + 1,
|
||||||
GT_RACE,
|
roundqueue.entries[0].gametype,
|
||||||
grandprixinfo.encore,
|
roundqueue.entries[0].encore,
|
||||||
true,
|
true,
|
||||||
1,
|
1,
|
||||||
false,
|
false,
|
||||||
false
|
roundqueue.entries[0].rankrestricted
|
||||||
);
|
);
|
||||||
|
|
||||||
M_ClearMenus(true);
|
M_ClearMenus(true);
|
||||||
|
|
|
||||||
|
|
@ -49,15 +49,16 @@ savedata_t savedata;
|
||||||
|
|
||||||
// Block UINT32s to attempt to ensure that the correct data is
|
// Block UINT32s to attempt to ensure that the correct data is
|
||||||
// being sent and received
|
// being sent and received
|
||||||
#define ARCHIVEBLOCK_MISC 0x7FEEDEED
|
#define ARCHIVEBLOCK_MISC 0x7FEEDEED
|
||||||
#define ARCHIVEBLOCK_PLAYERS 0x7F448008
|
#define ARCHIVEBLOCK_PLAYERS 0x7F448008
|
||||||
#define ARCHIVEBLOCK_PARTIES 0x7F87AF0C
|
#define ARCHIVEBLOCK_PARTIES 0x7F87AF0C
|
||||||
#define ARCHIVEBLOCK_WORLD 0x7F8C08C0
|
#define ARCHIVEBLOCK_ROUNDQUEUE 0x7F721331
|
||||||
#define ARCHIVEBLOCK_POBJS 0x7F928546
|
#define ARCHIVEBLOCK_WORLD 0x7F8C08C0
|
||||||
#define ARCHIVEBLOCK_THINKERS 0x7F37037C
|
#define ARCHIVEBLOCK_POBJS 0x7F928546
|
||||||
#define ARCHIVEBLOCK_SPECIALS 0x7F228378
|
#define ARCHIVEBLOCK_THINKERS 0x7F37037C
|
||||||
#define ARCHIVEBLOCK_WAYPOINTS 0x7F46498F
|
#define ARCHIVEBLOCK_SPECIALS 0x7F228378
|
||||||
#define ARCHIVEBLOCK_RNG 0x7FAAB5BD
|
#define ARCHIVEBLOCK_WAYPOINTS 0x7F46498F
|
||||||
|
#define ARCHIVEBLOCK_RNG 0x7FAAB5BD
|
||||||
|
|
||||||
// Note: This cannot be bigger
|
// Note: This cannot be bigger
|
||||||
// than an UINT16
|
// than an UINT16
|
||||||
|
|
@ -942,6 +943,48 @@ static void P_NetUnArchiveParties(savebuffer_t *save)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void P_NetArchiveRoundQueue(savebuffer_t *save)
|
||||||
|
{
|
||||||
|
UINT8 i;
|
||||||
|
WRITEUINT32(save->p, ARCHIVEBLOCK_ROUNDQUEUE);
|
||||||
|
|
||||||
|
WRITEUINT8(save->p, roundqueue.position);
|
||||||
|
WRITEUINT8(save->p, roundqueue.size);
|
||||||
|
WRITEUINT8(save->p, roundqueue.roundnum);
|
||||||
|
|
||||||
|
for (i = 0; i < roundqueue.size; i++)
|
||||||
|
{
|
||||||
|
//WRITEUINT16(save->p, roundqueue.entries[i].mapnum);
|
||||||
|
/* NOPE! Clients do not need to know what is in the roundqueue.
|
||||||
|
This disincentivises cheaty clients in future tournament environments.
|
||||||
|
~toast 080423 */
|
||||||
|
WRITEUINT8(save->p, roundqueue.entries[i].gametype);
|
||||||
|
WRITEUINT8(save->p, (UINT8)roundqueue.entries[i].encore);
|
||||||
|
WRITEUINT8(save->p, (UINT8)roundqueue.entries[i].rankrestricted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void P_NetUnArchiveRoundQueue(savebuffer_t *save)
|
||||||
|
{
|
||||||
|
UINT8 i;
|
||||||
|
if (READUINT32(save->p) != ARCHIVEBLOCK_ROUNDQUEUE)
|
||||||
|
I_Error("Bad $$$.sav at archive block Round-queue");
|
||||||
|
|
||||||
|
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||||
|
|
||||||
|
roundqueue.position = READUINT8(save->p);
|
||||||
|
roundqueue.size = READUINT8(save->p);
|
||||||
|
roundqueue.roundnum = READUINT8(save->p);
|
||||||
|
|
||||||
|
for (i = 0; i < roundqueue.size; i++)
|
||||||
|
{
|
||||||
|
roundqueue.entries[i].mapnum = 0; // TEST RUN -- dummy, has to be < nummapheaders
|
||||||
|
roundqueue.entries[i].gametype = READUINT8(save->p);
|
||||||
|
roundqueue.entries[i].encore = (boolean)READUINT8(save->p);
|
||||||
|
roundqueue.entries[i].rankrestricted = (boolean)READUINT8(save->p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Colormaps
|
/// Colormaps
|
||||||
///
|
///
|
||||||
|
|
@ -5419,6 +5462,7 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
||||||
|
|
||||||
P_NetArchivePlayers(save);
|
P_NetArchivePlayers(save);
|
||||||
P_NetArchiveParties(save);
|
P_NetArchiveParties(save);
|
||||||
|
P_NetArchiveRoundQueue(save);
|
||||||
|
|
||||||
if (gamestate == GS_LEVEL)
|
if (gamestate == GS_LEVEL)
|
||||||
{
|
{
|
||||||
|
|
@ -5469,6 +5513,7 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
||||||
|
|
||||||
P_NetUnArchivePlayers(save);
|
P_NetUnArchivePlayers(save);
|
||||||
P_NetUnArchiveParties(save);
|
P_NetUnArchiveParties(save);
|
||||||
|
P_NetUnArchiveRoundQueue(save);
|
||||||
|
|
||||||
if (gamestate == GS_LEVEL)
|
if (gamestate == GS_LEVEL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,7 @@ void ST_runTitleCard(void)
|
||||||
{
|
{
|
||||||
boolean run = !(paused || P_AutoPause());
|
boolean run = !(paused || P_AutoPause());
|
||||||
INT32 auxticker;
|
INT32 auxticker;
|
||||||
boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum));
|
boolean doroundicon = (marathonmode || (roundqueue.size > 0 && roundqueue.position > 0));
|
||||||
|
|
||||||
if (!G_IsTitleCardAvailable())
|
if (!G_IsTitleCardAvailable())
|
||||||
return;
|
return;
|
||||||
|
|
@ -818,7 +818,7 @@ void ST_runTitleCard(void)
|
||||||
roundnumy = eggy1;
|
roundnumy = eggy1;
|
||||||
|
|
||||||
// split both halves of the egg, but only do that in grand prix!
|
// split both halves of the egg, but only do that in grand prix!
|
||||||
if (gp && lt_ticker > TTANIMTHRESHOLD + TICRATE/2)
|
if (doroundicon && lt_ticker > TTANIMTHRESHOLD + TICRATE/2)
|
||||||
{
|
{
|
||||||
auxticker = (INT32)lt_ticker - (TTANIMTHRESHOLD + TICRATE/2);
|
auxticker = (INT32)lt_ticker - (TTANIMTHRESHOLD + TICRATE/2);
|
||||||
|
|
||||||
|
|
@ -881,7 +881,7 @@ void ST_drawTitleCard(void)
|
||||||
char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
|
char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
|
||||||
char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart
|
char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart
|
||||||
UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
|
UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
|
||||||
boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum));
|
boolean doroundicon = (marathonmode || (roundqueue.size > 0 && roundqueue.position > 0));
|
||||||
|
|
||||||
INT32 acttimer;
|
INT32 acttimer;
|
||||||
fixed_t actscale;
|
fixed_t actscale;
|
||||||
|
|
@ -1011,9 +1011,9 @@ void ST_drawTitleCard(void)
|
||||||
// Draw ROUND bar, scroll it downwards.
|
// Draw ROUND bar, scroll it downwards.
|
||||||
V_DrawFixedPatch(roundx*FRACUNIT, ((-32) + (lt_ticker%32))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcroundbar, NULL);
|
V_DrawFixedPatch(roundx*FRACUNIT, ((-32) + (lt_ticker%32))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcroundbar, NULL);
|
||||||
// Draw ROUND text
|
// Draw ROUND text
|
||||||
if (gp)
|
if (doroundicon)
|
||||||
V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT,
|
V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT,
|
||||||
((grandprixinfo.gp && grandprixinfo.eventmode) ? tcbonus : tcround),
|
((grandprixinfo.gp && grandprixinfo.eventmode != GPEVENT_NONE) ? tcbonus : tcround),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
// round num background
|
// round num background
|
||||||
|
|
@ -1032,25 +1032,29 @@ void ST_drawTitleCard(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If possible, draw round number/icon
|
// If possible, draw round number/icon
|
||||||
if (gp)
|
if (doroundicon)
|
||||||
{
|
{
|
||||||
patch_t *roundico = NULL;
|
patch_t *roundico = NULL;
|
||||||
if (marathonmode)
|
if (marathonmode)
|
||||||
; // TODO: Ruby
|
; // TODO: Ruby
|
||||||
else switch (grandprixinfo.eventmode)
|
else if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||||
{
|
{
|
||||||
case GPEVENT_BONUS:
|
switch (grandprixinfo.eventmode)
|
||||||
roundico = tcroundbonus; // TODO don't show capsule if we have other bonus types
|
{
|
||||||
break;
|
case GPEVENT_BONUS:
|
||||||
/*case GPEVENT_SPECIAL:
|
roundico = tcroundbonus; // TODO don't show capsule if we have other bonus types
|
||||||
; // TODO: Emerald/mount
|
break;
|
||||||
break;*/
|
/*case GPEVENT_SPECIAL:
|
||||||
case GPEVENT_NONE:
|
; // TODO: Emerald/mount
|
||||||
if (grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE.
|
break;*/
|
||||||
roundico = tcroundnum[grandprixinfo.roundnum-1];
|
default:
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
break;
|
}
|
||||||
|
else if (roundqueue.size > 0)
|
||||||
|
{
|
||||||
|
if (roundqueue.roundnum > 0 && roundqueue.roundnum < 11) // We DEFINITELY need to check boundaries.
|
||||||
|
roundico = tcroundnum[roundqueue.roundnum-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundico)
|
if (roundico)
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ TYPEDEF (menudemo_t);
|
||||||
TYPEDEF (demoghost);
|
TYPEDEF (demoghost);
|
||||||
|
|
||||||
// g_game.h
|
// g_game.h
|
||||||
|
TYPEDEF (roundentry_t);
|
||||||
TYPEDEF (mapsearchfreq_t);
|
TYPEDEF (mapsearchfreq_t);
|
||||||
|
|
||||||
// hu_stuff.h
|
// hu_stuff.h
|
||||||
|
|
|
||||||
|
|
@ -539,6 +539,9 @@ skiptallydrawer:
|
||||||
|
|
||||||
if (demo.playback)
|
if (demo.playback)
|
||||||
string = va("Replay ends in %d", tickdown);
|
string = va("Replay ends in %d", tickdown);
|
||||||
|
else if ((nextmapoverride != 0)
|
||||||
|
|| (roundqueue.size > 0 && roundqueue.position < roundqueue.size))
|
||||||
|
string = va("Next starts in %d", tickdown);
|
||||||
else
|
else
|
||||||
string = va("%s starts in %d", cv_advancemap.string, tickdown);
|
string = va("%s starts in %d", cv_advancemap.string, tickdown);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue