Merge branch '21-version' into 'next'

Update code versions to 2.1.21

See merge request STJr/SRB2!338
This commit is contained in:
Digiku 2018-12-06 17:20:45 -05:00
commit 3880da272b
21 changed files with 523 additions and 105 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.20 VERSION 2.1.21
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.1.20.{branch}-{build} version: 2.1.21.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

View file

@ -49,6 +49,7 @@ static void COM_Wait_f(void);
static void COM_Help_f(void); static void COM_Help_f(void);
static void COM_Toggle_f(void); static void COM_Toggle_f(void);
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr);
static boolean CV_Command(void); static boolean CV_Command(void);
static consvar_t *CV_FindVar(const char *name); static consvar_t *CV_FindVar(const char *name);
static const char *CV_StringValue(const char *var_name); static const char *CV_StringValue(const char *var_name);
@ -62,6 +63,17 @@ CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
// Filter consvars by MODVERSION
// First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20)
// Also set CV_HIDEN during runtime, after config is loaded
consvar_t cv_execversion = {"execversion","25",0,CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
// for default joyaxis detection
static boolean joyaxis_default = false;
static boolean joyaxis2_default = false;
static INT32 joyaxis_count = 0;
static INT32 joyaxis2_count = 0;
#define COM_BUF_SIZE 8192 // command buffer size #define COM_BUF_SIZE 8192 // command buffer size
#define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases #define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases
@ -1232,7 +1244,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
char *svalue; char *svalue;
UINT8 stealth = false; UINT8 stealth = false;
if (playernum != serverplayer && playernum != adminplayer && !serverloading) if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading)
{ {
// not from server or remote admin, must be hacked/buggy client // not from server or remote admin, must be hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal netvar command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal netvar command received from %s\n"), player_names[playernum]);
@ -1361,7 +1373,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
// send the value of the variable // send the value of the variable
XBOXSTATIC UINT8 buf[128]; XBOXSTATIC UINT8 buf[128];
UINT8 *p = buf; UINT8 *p = buf;
if (!(server || (adminplayer == consoleplayer))) if (!(server || (IsPlayerAdmin(consoleplayer))))
{ {
CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string); CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string);
return; return;
@ -1568,6 +1580,200 @@ void CV_AddValue(consvar_t *var, INT32 increment)
var->changed = 1; // user has changed it now var->changed = 1; // user has changed it now
} }
void CV_InitFilterVar(void)
{
joyaxis_default = joyaxis2_default = true;
joyaxis_count = joyaxis2_count = 0;
}
static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
{
// If ALL axis settings are previous defaults, set them to the new defaults
// MODVERSION < 26 (2.1.21)
if (joyaxis_default)
{
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis_turn"))
{
if (joyaxis_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#if !defined (PSP)
if (!stricmp(v->name, "joyaxis_move"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_side"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
#if !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_look"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
if (!stricmp(v->name, "joyaxis_fire")
|| !stricmp(v->name, "joyaxis_firenormal"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
// reset all axis settings to defaults
if (joyaxis_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis.name, cv_turnaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis.name, cv_moveaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis.name, cv_sideaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis.name, cv_lookaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis.name, cv_fireaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis.name, cv_firenaxis.defaultvalue));
joyaxis_count++;
return false;
}
}
if (joyaxis2_default)
{
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis2_turn"))
{
if (joyaxis2_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
// #if !defined (PSP)
if (!stricmp(v->name, "joyaxis2_move"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
// #endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_side"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
#if !defined (_XBOX) // && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_look"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
if (!stricmp(v->name, "joyaxis2_fire")
|| !stricmp(v->name, "joyaxis2_firenormal"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
// reset all axis settings to defaults
if (joyaxis2_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis2.name, cv_turnaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis2.name, cv_moveaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis2.name, cv_sideaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis2.name, cv_lookaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis2.name, cv_fireaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis2.name, cv_firenaxis2.defaultvalue));
joyaxis2_count++;
return false;
}
}
// we haven't reached our counts yet, or we're not default
return true;
}
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
{
// True means allow the CV change, False means block it
// We only care about CV_SAVE because this filters the user's config files
// We do this same check in CV_Command
if (!(v->flags & CV_SAVE))
return true;
// We go by MODVERSION here
if (cv_execversion.value < 26) // 26 = 2.1.21
{
// MOUSE SETTINGS
// alwaysfreelook split between first and third person (chasefreelook)
// mousemove was on by default, which invalidates the current approach
if (!stricmp(v->name, "alwaysmlook")
|| !stricmp(v->name, "alwaysmlook2")
|| !stricmp(v->name, "mousemove")
|| !stricmp(v->name, "mousemove2"))
return false;
// mousesens was changed from 35 to 20 due to oversensitivity
if ((!stricmp(v->name, "mousesens")
|| !stricmp(v->name, "mousesens2")
|| !stricmp(v->name, "mouseysens")
|| !stricmp(v->name, "mouseysens2"))
&& atoi(valstr) == 35)
return false;
// JOYSTICK DEFAULTS
// use_joystick was changed from 0 to 1 to automatically use a joystick if available
#if defined(HAVE_SDL) || defined(_WINDOWS)
if ((!stricmp(v->name, "use_joystick")
|| !stricmp(v->name, "use_joystick2"))
&& atoi(valstr) == 0)
return false;
#endif
// axis defaults were changed to be friendly to 360 controllers
// if ALL axis settings are defaults, then change them to new values
if (!CV_FilterJoyAxisVars(v, valstr))
return false;
}
return true;
}
/** Displays or changes a variable from the console. /** Displays or changes a variable from the console.
* Since the user is presumed to have been directly responsible * Since the user is presumed to have been directly responsible
* for this change, the variable is marked as changed this game. * for this change, the variable is marked as changed this game.
@ -1592,8 +1798,11 @@ static boolean CV_Command(void)
return true; return true;
} }
CV_Set(v, COM_Argv(1)); if (!(v->flags & CV_SAVE) || CV_FilterVarByVersion(v, COM_Argv(1)))
v->changed = 1; // now it's been changed by (presumably) the user {
CV_Set(v, COM_Argv(1));
v->changed = 1; // now it's been changed by (presumably) the user
}
return true; return true;
} }

View file

@ -125,6 +125,12 @@ extern CV_PossibleValue_t CV_OnOff[];
extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_YesNo[];
extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Unsigned[];
extern CV_PossibleValue_t CV_Natural[]; extern CV_PossibleValue_t CV_Natural[];
// Filter consvars by version
extern consvar_t cv_execversion;
void CV_InitFilterVar(void);
// register a variable for use at the console // register a variable for use at the console
void CV_RegisterVar(consvar_t *variable); void CV_RegisterVar(consvar_t *variable);

View file

@ -1366,15 +1366,18 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate; netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.adminplayer = (SINT8)adminplayer;
// we fill these structs with FFs so that any players not in game get sent as 0xFFFF // we fill these structs with FFs so that any players not in game get sent as 0xFFFF
// which is nice and easy for us to detect // which is nice and easy for us to detect
memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins));
memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor));
memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers));
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i];
if (!playeringame[i]) if (!playeringame[i])
continue; continue;
netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin;
@ -2043,7 +2046,7 @@ static void CL_ConnectToServer(boolean viams)
G_SetGamestate(GS_WAITINGPLAYERS); G_SetGamestate(GS_WAITINGPLAYERS);
wipegamestate = GS_WAITINGPLAYERS; wipegamestate = GS_WAITINGPLAYERS;
adminplayer = -1; ClearAdminPlayers();
pnumnodes = 1; pnumnodes = 1;
oldtic = I_GetTime() - 1; oldtic = I_GetTime() - 1;
#ifndef NONET #ifndef NONET
@ -2426,8 +2429,10 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
// Reset the name // Reset the name
sprintf(player_names[playernum], "Player %d", playernum+1); sprintf(player_names[playernum], "Player %d", playernum+1);
if (playernum == adminplayer) if (IsPlayerAdmin(playernum))
adminplayer = -1; // don't stay admin after you're gone {
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}
if (playernum == displayplayer) if (playernum == displayplayer)
displayplayer = consoleplayer; // don't look through someone's view who isn't there displayplayer = consoleplayer; // don't look through someone's view who isn't there
@ -2545,7 +2550,7 @@ static void Command_Nodes(void)
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
CONS_Printf(" - %s", address); CONS_Printf(" - %s", address);
if (i == adminplayer) if (IsPlayerAdmin(i))
CONS_Printf(M_GetText(" (verified admin)")); CONS_Printf(M_GetText(" (verified admin)"));
if (players[i].spectator) if (players[i].spectator)
@ -2570,7 +2575,7 @@ static void Command_Ban(void)
return; return;
} }
if (server || adminplayer == consoleplayer) if (server || IsPlayerAdmin(consoleplayer))
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf; UINT8 *p = buf;
@ -2636,7 +2641,7 @@ static void Command_Kick(void)
return; return;
} }
if (server || adminplayer == consoleplayer) if (server || IsPlayerAdmin(consoleplayer))
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf; UINT8 *p = buf;
@ -2645,13 +2650,16 @@ static void Command_Kick(void)
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
// Special case if we are trying to kick a player who is downloading the game state: if (server)
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
{ {
Net_ConnectionTimeout(playernode[pn]); // Special case if we are trying to kick a player who is downloading the game state:
return; // trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
} }
WRITESINT8(p, pn); WRITESINT8(p, pn);
@ -2694,7 +2702,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
pnum = READUINT8(*p); pnum = READUINT8(*p);
msg = READUINT8(*p); msg = READUINT8(*p);
if (pnum == serverplayer && playernum == adminplayer) if (pnum == serverplayer && IsPlayerAdmin(playernum))
{ {
CONS_Printf(M_GetText("Server is being shut down remotely. Goodbye!\n")); CONS_Printf(M_GetText("Server is being shut down remotely. Goodbye!\n"));
@ -2705,7 +2713,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
} }
// Is playernum authorized to make this kick? // Is playernum authorized to make this kick?
if (playernum != serverplayer && playernum != adminplayer if (playernum != serverplayer && !IsPlayerAdmin(playernum)
&& !(playerpernode[playernode[playernum]] == 2 && !(playerpernode[playernode[playernum]] == 2
&& nodetoplayer2[playernode[playernum]] == pnum)) && nodetoplayer2[playernode[playernum]] == pnum))
{ {
@ -2976,6 +2984,7 @@ void SV_ResetServer(void)
playeringame[i] = false; playeringame[i] = false;
playernode[i] = UINT8_MAX; playernode[i] = UINT8_MAX;
sprintf(player_names[i], "Player %d", i + 1); sprintf(player_names[i], "Player %d", i + 1);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
} }
mynode = 0; mynode = 0;
@ -3050,7 +3059,7 @@ void D_QuitNetGame(void)
} }
D_CloseConnection(); D_CloseConnection();
adminplayer = -1; ClearAdminPlayers();
DEBFILE("===========================================================================\n" DEBFILE("===========================================================================\n"
" Log finish\n" " Log finish\n"
@ -3081,7 +3090,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
INT16 node, newplayernum; INT16 node, newplayernum;
boolean splitscreenplayer; boolean splitscreenplayer;
if (playernum != serverplayer && playernum != adminplayer) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
// protect against hacked/buggy client // protect against hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]);
@ -3606,7 +3615,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype; gametype = netbuffer->u.servercfg.gametype;
modifiedgame = netbuffer->u.servercfg.modifiedgame; modifiedgame = netbuffer->u.servercfg.modifiedgame;
adminplayer = netbuffer->u.servercfg.adminplayer; for (j = 0; j < MAXPLAYERS; j++)
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
memcpy(server_context, netbuffer->u.servercfg.server_context, 8); memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
} }

View file

@ -282,7 +282,7 @@ typedef struct
UINT8 gametype; UINT8 gametype;
UINT8 modifiedgame; UINT8 modifiedgame;
SINT8 adminplayer; // Needs to be signed SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed
char server_context[8]; // Unique context id, generated at server startup. char server_context[8]; // Unique context id, generated at server startup.

View file

@ -144,7 +144,9 @@ static void Command_Changepassword_f(void);
static void Command_Login_f(void); static void Command_Login_f(void);
static void Got_Login(UINT8 **cp, INT32 playernum); static void Got_Login(UINT8 **cp, INT32 playernum);
static void Got_Verification(UINT8 **cp, INT32 playernum); static void Got_Verification(UINT8 **cp, INT32 playernum);
static void Got_Removal(UINT8 **cp, INT32 playernum);
static void Command_Verify_f(void); static void Command_Verify_f(void);
static void Command_RemoveAdmin_f(void);
static void Command_MotD_f(void); static void Command_MotD_f(void);
static void Got_MotD_f(UINT8 **cp, INT32 playernum); static void Got_MotD_f(UINT8 **cp, INT32 playernum);
@ -240,7 +242,7 @@ INT32 cv_debug;
consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL};
#if defined (DC) || defined (_XBOX) || defined (WMINPUT) || defined (_WII) || defined(HAVE_SDL) || defined(_WIN32) //joystick 1 and 2 #if defined (DC) || defined (_XBOX) || defined (WMINPUT) || defined (_WII) || defined(HAVE_SDL) || defined(_WINDOWS) //joystick 1 and 2
consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t,
I_InitJoystick, 0, NULL, NULL, 0, 0, NULL}; I_InitJoystick, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_usejoystick2 = {"use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, consvar_t cv_usejoystick2 = {"use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t,
@ -317,7 +319,6 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL,
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display
static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}};
consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t,
PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL}; PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -365,7 +366,7 @@ consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL
INT16 gametype = GT_COOP; INT16 gametype = GT_COOP;
boolean splitscreen = false; boolean splitscreen = false;
boolean circuitmap = false; boolean circuitmap = false;
INT32 adminplayer = -1; INT32 adminplayers[MAXPLAYERS];
/// \warning Keep this up-to-date if you add/remove/rename net text commands /// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] = const char *netxcmdnames[MAXNETXCMD - 1] =
@ -427,8 +428,10 @@ void D_RegisterServerCommands(void)
COM_AddCommand("password", Command_Changepassword_f); COM_AddCommand("password", Command_Changepassword_f);
RegisterNetXCmd(XD_LOGIN, Got_Login); RegisterNetXCmd(XD_LOGIN, Got_Login);
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
COM_AddCommand("verify", Command_Verify_f); COM_AddCommand("promote", Command_Verify_f);
RegisterNetXCmd(XD_VERIFIED, Got_Verification); RegisterNetXCmd(XD_VERIFIED, Got_Verification);
COM_AddCommand("demote", Command_RemoveAdmin_f);
RegisterNetXCmd(XD_DEMOTED, Got_Removal);
COM_AddCommand("motd", Command_MotD_f); COM_AddCommand("motd", Command_MotD_f);
RegisterNetXCmd(XD_SETMOTD, Got_MotD_f); // For remote admin RegisterNetXCmd(XD_SETMOTD, Got_MotD_f); // For remote admin
@ -1007,7 +1010,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true; return true;
// Force skin in effect. // Force skin in effect.
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1)) if (client && (cv_forceskin.value != -1) && !(IsPlayerAdmin(playernum) && serverplayer == -1))
return false; return false;
// Can change skin in intermission and whatnot. // Can change skin in intermission and whatnot.
@ -1158,7 +1161,7 @@ static void SendNameAndColor(void)
snacpending++; snacpending++;
// Don't change name if muted // Don't change name if muted
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
CV_StealthSet(&cv_playername, player_names[consoleplayer]); CV_StealthSet(&cv_playername, player_names[consoleplayer]);
else // Cleanup name if changing it else // Cleanup name if changing it
CleanupPlayerName(consoleplayer, cv_playername.zstring); CleanupPlayerName(consoleplayer, cv_playername.zstring);
@ -1570,7 +1573,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0; mapchangepending = 0;
// spawn the server if needed // spawn the server if needed
// reset players if there is a new one // reset players if there is a new one
if (!(adminplayer == consoleplayer)) if (!IsPlayerAdmin(consoleplayer))
{ {
if (SV_SpawnServer()) if (SV_SpawnServer())
buf[0] &= ~(1<<1); buf[0] &= ~(1<<1);
@ -1628,7 +1631,7 @@ static void Command_Map_f(void)
return; return;
} }
if (client && !(adminplayer == 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"));
return; return;
@ -1760,7 +1763,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
INT16 mapnumber; INT16 mapnumber;
#endif #endif
if (playernum != serverplayer && playernum != adminplayer) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -1862,7 +1865,7 @@ static void Command_Pause(void)
else else
WRITEUINT8(cp, 0); WRITEUINT8(cp, 0);
if (cv_pause.value || server || (adminplayer == consoleplayer)) if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer)))
{ {
if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)) if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
{ {
@ -1880,7 +1883,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
UINT8 dedicatedpause = false; UINT8 dedicatedpause = false;
const char *playername; const char *playername;
if (netgame && !cv_pause.value && playernum != serverplayer && playernum != adminplayer) if (netgame && !cv_pause.value && playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal pause command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal pause command received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -2009,7 +2012,7 @@ static void Got_RandomSeed(UINT8 **cp, INT32 playernum)
*/ */
static void Command_Clearscores_f(void) static void Command_Clearscores_f(void)
{ {
if (!(server || (adminplayer == consoleplayer))) if (!(server || (IsPlayerAdmin(consoleplayer))))
return; return;
SendNetXCmd(XD_CLEARSCORES, NULL, 1); SendNetXCmd(XD_CLEARSCORES, NULL, 1);
@ -2029,7 +2032,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum)
INT32 i; INT32 i;
(void)cp; (void)cp;
if (playernum != serverplayer && playernum != adminplayer) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal clear scores command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal clear scores command received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -2250,7 +2253,7 @@ static void Command_ServerTeamChange_f(void)
UINT16 usvalue; UINT16 usvalue;
NetPacket.value.l = NetPacket.value.b = 0; NetPacket.value.l = NetPacket.value.b = 0;
if (!(server || (adminplayer == consoleplayer))) if (!(server || (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"));
return; return;
@ -2397,7 +2400,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (NetPacket.packet.verification) // Special marker that the server sent the request if (NetPacket.packet.verification) // Special marker that the server sent the request
{ {
if (playernum != serverplayer && (playernum != adminplayer)) if (playernum != serverplayer && (!IsPlayerAdmin(playernum)))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server) if (server)
@ -2436,7 +2439,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
} }
else else
{ {
if (playernum != serverplayer && (playernum != adminplayer)) if (playernum != serverplayer && (!IsPlayerAdmin(playernum)))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server) if (server)
@ -2759,13 +2762,56 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
if (!memcmp(sentmd5, finalmd5, 16)) if (!memcmp(sentmd5, finalmd5, 16))
{ {
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]); CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]);
COM_BufInsertText(va("verify %d\n", playernum)); // do this immediately COM_BufInsertText(va("promote %d\n", playernum)); // do this immediately
} }
else else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[playernum]); CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[playernum]);
#endif #endif
} }
boolean IsPlayerAdmin(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playernum == adminplayers[i])
return true;
return false;
}
void SetAdminPlayer(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playernum == adminplayers[i])
return; // Player is already admin
if (adminplayers[i] == -1)
{
adminplayers[i] = playernum; // Set the player to a free spot
break; // End the loop now. If it keeps going, the same player might get assigned to two slots.
}
}
}
void ClearAdminPlayers(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
adminplayers[i] = -1;
}
void RemoveAdminPlayer(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playernum == adminplayers[i])
adminplayers[i] = -1;
}
static void Command_Verify_f(void) static void Command_Verify_f(void)
{ {
XBOXSTATIC char buf[8]; // Should be plenty XBOXSTATIC char buf[8]; // Should be plenty
@ -2786,7 +2832,7 @@ static void Command_Verify_f(void)
if (COM_Argc() != 2) if (COM_Argc() != 2)
{ {
CONS_Printf(M_GetText("verify <node>: give admin privileges to a node\n")); CONS_Printf(M_GetText("promote <node>: give admin privileges to a node\n"));
return; return;
} }
@ -2820,7 +2866,7 @@ static void Got_Verification(UINT8 **cp, INT32 playernum)
return; return;
} }
adminplayer = num; SetAdminPlayer(num);
if (num != consoleplayer) if (num != consoleplayer)
return; return;
@ -2828,6 +2874,62 @@ static void Got_Verification(UINT8 **cp, INT32 playernum)
CONS_Printf(M_GetText("You are now a server administrator.\n")); CONS_Printf(M_GetText("You are now a server administrator.\n"));
} }
static void Command_RemoveAdmin_f(void)
{
XBOXSTATIC char buf[8]; // Should be plenty
char *temp;
INT32 playernum;
if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
}
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("demote <node>: remove admin privileges from a node\n"));
return;
}
strlcpy(buf, COM_Argv(1), sizeof(buf));
playernum = atoi(buf);
temp = buf;
WRITEUINT8(temp, playernum);
if (playeringame[playernum])
SendNetXCmd(XD_DEMOTED, buf, 1);
}
static void Got_Removal(UINT8 **cp, INT32 playernum)
{
INT16 num = READUINT8(*cp);
if (playernum != serverplayer) // it's not from the server (hacker or bug)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal demotion received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)playernum;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
return;
}
RemoveAdminPlayer(num);
if (num != consoleplayer)
return;
CONS_Printf(M_GetText("You are no longer a server administrator.\n"));
}
static void Command_MotD_f(void) static void Command_MotD_f(void)
{ {
size_t i, j; size_t i, j;
@ -2839,7 +2941,7 @@ static void Command_MotD_f(void)
return; return;
} }
if (!(server || (adminplayer == consoleplayer))) if (!(server || (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"));
return; return;
@ -2863,7 +2965,7 @@ static void Command_MotD_f(void)
} }
if ((netgame || multiplayer) && client) if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd)); SendNetXCmd(XD_SETMOTD, mymotd, i); // send the actual size of the motd string, not the full buffer's size
else else
{ {
strcpy(motd, mymotd); strcpy(motd, mymotd);
@ -2886,7 +2988,7 @@ static void Got_MotD_f(UINT8 **cp, INT32 playernum)
if (!isprint(mymotd[i]) || mymotd[i] == ';') if (!isprint(mymotd[i]) || mymotd[i] == ';')
kick = true; kick = true;
if ((playernum != serverplayer && playernum != adminplayer) || kick) if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal motd change received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal motd change received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -2923,7 +3025,7 @@ static void Command_RunSOC(void)
else else
fn = COM_Argv(1); fn = COM_Argv(1);
if (netgame && !(server || consoleplayer == adminplayer)) if (netgame && !(server || 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"));
return; return;
@ -2949,7 +3051,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
char filename[256]; char filename[256];
filestatus_t ncs = FS_NOTFOUND; filestatus_t ncs = FS_NOTFOUND;
if (playernum != serverplayer && playernum != adminplayer) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal runsoc command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal runsoc command received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -3020,7 +3122,7 @@ static void Command_Addfile(void)
if (!musiconly) if (!musiconly)
{ {
// ... But only so long as they contain nothing more then music and sprites. // ... But only so long as they contain nothing more then music and sprites.
if (netgame && !(server || adminplayer == consoleplayer)) if (netgame && !(server || 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"));
return; return;
@ -3095,7 +3197,7 @@ static void Command_Addfile(void)
WRITEMEM(buf_p, md5sum, 16); WRITEMEM(buf_p, md5sum, 16);
} }
if (adminplayer == consoleplayer && (!server)) // Request to add file if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf); SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf);
else else
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf); SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);
@ -3144,7 +3246,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean kick = false; boolean kick = false;
boolean toomany = false; boolean toomany = false;
INT32 i; INT32 i,j;
size_t packetsize = 0; size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL; serverinfo_pak *dummycheck = NULL;
@ -3163,7 +3265,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
if (!isprint(filename[i]) || filename[i] == ';') if (!isprint(filename[i]) || filename[i] == ';')
kick = true; kick = true;
if ((playernum != serverplayer && playernum != adminplayer) || kick) if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{ {
XBOXSTATIC UINT8 buf[2]; XBOXSTATIC UINT8 buf[2];
@ -3202,8 +3304,9 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
CONS_Printf("%s",message); CONS_Printf("%s",message);
if (adminplayer) for (j = 0; j < MAXPLAYERS; j++)
COM_BufAddText(va("sayto %d %s", adminplayer, message)); if (adminplayers[j])
COM_BufAddText(va("sayto %d %s", adminplayers[j], message));
return; return;
} }
@ -3318,10 +3421,51 @@ static void Command_ListWADS_f(void)
static void Command_Version_f(void) static void Command_Version_f(void)
{ {
#ifdef DEVELOP #ifdef DEVELOP
CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s)\n", compbranch, comprevision, compdate, comptime); CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime);
#else #else
CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s)\n", VERSIONSTRING, compdate, comptime, comprevision); CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision);
#endif #endif
// Base library
#if defined( HAVE_SDL)
CONS_Printf("SDL ");
#elif defined(_WINDOWS)
CONS_Printf("DD ");
#endif
// OS
// Would be nice to use SDL_GetPlatform for this
#if defined (_WIN32) || defined (_WIN64)
CONS_Printf("Windows ");
#elif defined(__linux__)
CONS_Printf("Linux ");
#elif defined(MACOSX)
CONS_Printf("macOS" );
#elif defined(UNIXCOMMON)
CONS_Printf("Unix (Common) ");
#else
CONS_Printf("Other OS ");
#endif
// Bitness
if (sizeof(void*) == 4)
CONS_Printf("32-bit ");
else if (sizeof(void*) == 8)
CONS_Printf("64-bit ");
else // 16-bit? 128-bit?
CONS_Printf("Bits Unknown ");
// No ASM?
#ifdef NOASM
CONS_Printf("\x85" "NOASM " "\x80");
#endif
// Debug build
#ifdef _DEBUG
CONS_Printf("\x85" "DEBUG " "\x80");
#endif
CONS_Printf("\n");
} }
#ifdef UPDATE_ALERT #ifdef UPDATE_ALERT
@ -3597,7 +3741,7 @@ void D_GameTypeChanged(INT32 lastgametype)
if (playeringame[i]) if (playeringame[i])
players[i].ctfteam = 0; players[i].ctfteam = 0;
if (server || (adminplayer == consoleplayer)) if (server || (IsPlayerAdmin(consoleplayer)))
{ {
CV_StealthSetValue(&cv_teamscramble, 0); CV_StealthSetValue(&cv_teamscramble, 0);
teamscramble = 0; teamscramble = 0;
@ -3680,7 +3824,7 @@ static void TeamScramble_OnChange(void)
if (!cv_teamscramble.value) if (!cv_teamscramble.value)
teamscramble = 0; teamscramble = 0;
if (!G_GametypeHasTeams() && (server || consoleplayer == adminplayer)) if (!G_GametypeHasTeams() && (server || IsPlayerAdmin(consoleplayer)))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n")); CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n"));
CV_StealthSetValue(&cv_teamscramble, 0); CV_StealthSetValue(&cv_teamscramble, 0);
@ -3859,7 +4003,7 @@ static void Command_ExitLevel_f(void)
{ {
if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug) if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug)
CONS_Printf(M_GetText("This only works in a netgame.\n")); CONS_Printf(M_GetText("This only works in a netgame.\n"));
else if (!(server || (adminplayer == consoleplayer))) else if (!(server || (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"));
else if (gamestate != GS_LEVEL || demoplayback) else if (gamestate != GS_LEVEL || demoplayback)
CONS_Printf(M_GetText("You must be in a level to use this.\n")); CONS_Printf(M_GetText("You must be in a level to use this.\n"));
@ -3875,7 +4019,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
if (gameaction == ga_completed) if (gameaction == ga_completed)
return; return;
if (playernum != serverplayer && playernum != adminplayer) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal exitlevel command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal exitlevel command received from %s\n"), player_names[playernum]);
if (server) if (server)
@ -3980,7 +4124,7 @@ static void Command_Cheats_f(void)
{ {
if (COM_CheckParm("off")) if (COM_CheckParm("off"))
{ {
if (!(server || (adminplayer == consoleplayer))) if (!(server || (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"));
else else
CV_ResetCheatNetVars(); CV_ResetCheatNetVars();
@ -3990,7 +4134,7 @@ static void Command_Cheats_f(void)
if (CV_CheatsEnabled()) if (CV_CheatsEnabled())
{ {
CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n")); CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n"));
if (server || (adminplayer == consoleplayer)) if (server || (IsPlayerAdmin(consoleplayer)))
CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n")); CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n"));
} }
else else
@ -4059,7 +4203,7 @@ static void Command_Archivetest_f(void)
*/ */
static void ForceSkin_OnChange(void) static void ForceSkin_OnChange(void)
{ {
if ((server || adminplayer == consoleplayer) && (cv_forceskin.value < -1 || cv_forceskin.value >= numskins)) if ((server || IsPlayerAdmin(consoleplayer)) && (cv_forceskin.value < -1 || cv_forceskin.value >= numskins))
{ {
if (cv_forceskin.value == -2) if (cv_forceskin.value == -2)
CV_SetValue(&cv_forceskin, numskins-1); CV_SetValue(&cv_forceskin, numskins-1);
@ -4089,7 +4233,7 @@ static void ForceSkin_OnChange(void)
//Allows the player's name to be changed if cv_mute is off. //Allows the player's name to be changed if cv_mute is off.
static void Name_OnChange(void) static void Name_OnChange(void)
{ {
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n"));
CV_StealthSet(&cv_playername, player_names[consoleplayer]); CV_StealthSet(&cv_playername, player_names[consoleplayer]);
@ -4212,7 +4356,7 @@ static void Color2_OnChange(void)
*/ */
static void Mute_OnChange(void) static void Mute_OnChange(void)
{ {
if (server || (adminplayer == consoleplayer)) if (server || (IsPlayerAdmin(consoleplayer)))
return; return;
if (cv_mute.value) if (cv_mute.value)

View file

@ -133,9 +133,10 @@ typedef enum
XD_DELFILE, // 18 XD_DELFILE, // 18
XD_SETMOTD, // 19 XD_SETMOTD, // 19
XD_SUICIDE, // 20 XD_SUICIDE, // 20
XD_DEMOTED, // 21
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
XD_LUACMD, // 21 XD_LUACMD, // 22
XD_LUAVAR, // 22 XD_LUAVAR, // 23
#endif #endif
MAXNETXCMD MAXNETXCMD
} netxcmd_t; } netxcmd_t;
@ -190,6 +191,10 @@ 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 pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
boolean IsPlayerAdmin(INT32 playernum);
void SetAdminPlayer(INT32 playernum);
void ClearAdminPlayers(void);
void RemoveAdminPlayer(INT32 playernum);
void ItemFinder_OnChange(void); void ItemFinder_OnChange(void);
void D_SetPassword(const char *pw); void D_SetPassword(const char *pw);

View file

@ -8302,10 +8302,10 @@ static inline int lib_getenum(lua_State *L)
return 0; return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1; return 1;
} else if (fastcmp(word,"admin")) { } else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
if (!playeringame[adminplayer] || adminplayer == serverplayer) if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0; return 0;
LUA_PushUserdata(L, &players[adminplayer], META_PLAYER); LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1; return 1;
} else if (fastcmp(word,"emeralds")) { } else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds); lua_pushinteger(L, emeralds);

View file

@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 201 // Game version #define VERSION 201 // Game version
#define SUBVERSION 20 // more precise version number #define SUBVERSION 21 // more precise version number
#define VERSIONSTRING "v2.1.20" #define VERSIONSTRING "v2.1.21"
#define VERSIONSTRINGW L"v2.1.20" #define VERSIONSTRINGW L"v2.1.21"
// Hey! If you change this, add 1 to the MODVERSION below! // Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates! // Otherwise we can't force updates!
#endif #endif
@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously. // Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 25 #define MODVERSION 26
// ========================================================================= // =========================================================================

View file

@ -476,7 +476,8 @@ extern consvar_t cv_timetic; // display high resolution timer
extern consvar_t cv_forceskin; // force clients to use the server's skin extern consvar_t cv_forceskin; // force clients to use the server's skin
extern consvar_t cv_downloading; // allow clients to downloading WADs. extern consvar_t cv_downloading; // allow clients to downloading WADs.
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 adminplayer, serverplayer; extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS];
/// \note put these in d_clisrv outright? /// \note put these in d_clisrv outright?

View file

@ -1858,7 +1858,7 @@ void F_CutsceneTicker(void)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (netgame && i != serverplayer && i != adminplayer) if (netgame && i != serverplayer && !IsPlayerAdmin(i))
continue; continue;
if (players[i].cmd.buttons & BT_USE) if (players[i].cmd.buttons & BT_USE)

View file

@ -352,7 +352,7 @@ consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NUL
consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasefreelook = {"chasemlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasefreelook = {"chasemlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasefreelook2 = {"chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasefreelook2 = {"chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -410,8 +410,8 @@ consvar_t cv_lookaxis = {"joyaxis_look", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL
consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
#endif #endif
consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
#if defined (_WII) || defined (WMINPUT) #if defined (_WII) || defined (WMINPUT)
@ -422,7 +422,7 @@ consvar_t cv_lookaxis2 = {"joyaxis2_look", "RStick.Y", CV_SAVE, joyaxis_cons_t,
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis2 = {"joyaxis2_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else #else
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis2 = {"joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_moveaxis2 = {"joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef _arch_dreamcast #ifdef _arch_dreamcast
consvar_t cv_sideaxis2 = {"joyaxis2_side", "Triggers", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sideaxis2 = {"joyaxis2_side", "Triggers", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -432,13 +432,13 @@ consvar_t cv_lookaxis2 = {"joyaxis2_look", "Alt Y-Axis", CV_SAVE, joyaxis_cons_t
#elif defined (_PSP) #elif defined (_PSP)
consvar_t cv_sideaxis2 = {"joyaxis2_side", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sideaxis2 = {"joyaxis2_side", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else #else
consvar_t cv_sideaxis2 = {"joyaxis2_side", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
#ifndef _XBOX #ifndef _XBOX
consvar_t cv_lookaxis2 = {"joyaxis2_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif

View file

@ -347,14 +347,14 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
numwords = COM_Argc() - usedargs; numwords = COM_Argc() - usedargs;
I_Assert(numwords > 0); I_Assert(numwords > 0);
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return; return;
} }
// Only servers/admins can CSAY. // Only servers/admins can CSAY.
if(!server && adminplayer != consoleplayer) if(!server && IsPlayerAdmin(consoleplayer))
flags &= ~HU_CSAY; flags &= ~HU_CSAY;
// We handle HU_SERVER_SAY, not the caller. // We handle HU_SERVER_SAY, not the caller.
@ -448,7 +448,7 @@ static void Command_CSay_f(void)
return; return;
} }
if(!server && adminplayer != consoleplayer) if(!server && !IsPlayerAdmin(consoleplayer))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use csay.\n")); CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use csay.\n"));
return; return;
@ -477,7 +477,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
msg = (char *)*p; msg = (char *)*p;
SKIPSTRING(*p); SKIPSTRING(*p);
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && playernum != adminplayer) if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
CONS_Alert(CONS_WARNING, cv_mute.value ? CONS_Alert(CONS_WARNING, cv_mute.value ?
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"), M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
@ -575,7 +575,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
// Give admins and remote admins their symbols. // Give admins and remote admins their symbols.
if (playernum == serverplayer) if (playernum == serverplayer)
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(adminchar) + 1, PU_STATIC, NULL); tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(adminchar) + 1, PU_STATIC, NULL);
else if (playernum == adminplayer) else if (IsPlayerAdmin(playernum))
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(remotechar) + 1, PU_STATIC, NULL); tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(remotechar) + 1, PU_STATIC, NULL);
if (tempchar) if (tempchar)
{ {
@ -710,7 +710,7 @@ static void HU_queueChatChar(char c)
} while (c); } while (c);
// last minute mute check // last minute mute check
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return; return;
@ -768,9 +768,9 @@ boolean HU_Responder(event_t *ev)
{ {
// enter chat mode // enter chat mode
if ((ev->data1 == gamecontrol[gc_talkkey][0] || ev->data1 == gamecontrol[gc_talkkey][1]) if ((ev->data1 == gamecontrol[gc_talkkey][0] || ev->data1 == gamecontrol[gc_talkkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer))) && netgame && (!cv_mute.value || server || IsPlayerAdmin(consoleplayer)))
{ {
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
return false; return false;
chat_on = true; chat_on = true;
w_chat[0] = 0; w_chat[0] = 0;
@ -778,9 +778,9 @@ boolean HU_Responder(event_t *ev)
return true; return true;
} }
if ((ev->data1 == gamecontrol[gc_teamkey][0] || ev->data1 == gamecontrol[gc_teamkey][1]) if ((ev->data1 == gamecontrol[gc_teamkey][0] || ev->data1 == gamecontrol[gc_teamkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer))) && netgame && (!cv_mute.value || server || (IsPlayerAdmin(consoleplayer))))
{ {
if (cv_mute.value && !(server || adminplayer == consoleplayer)) if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
return false; return false;
chat_on = true; chat_on = true;
w_chat[0] = 0; w_chat[0] = 0;

View file

@ -23,6 +23,9 @@
#include "m_random.h" #include "m_random.h"
#include "s_sound.h" #include "s_sound.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h"
#include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
@ -96,6 +99,16 @@ static int lib_evalMath(lua_State *L)
return 1; return 1;
} }
static int lib_isPlayerAdmin(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, IsPlayerAdmin(player-players));
return 1;
}
// M_RANDOM // M_RANDOM
////////////// //////////////
@ -2004,6 +2017,7 @@ static int lib_gTicsToMilliseconds(lua_State *L)
static luaL_Reg lib[] = { static luaL_Reg lib[] = {
{"print", lib_print}, {"print", lib_print},
{"EvalMath", lib_evalMath}, {"EvalMath", lib_evalMath},
{"IsPlayerAdmin", lib_isPlayerAdmin},
// m_random // m_random
{"P_RandomFixed",lib_pRandomFixed}, {"P_RandomFixed",lib_pRandomFixed},

View file

@ -55,7 +55,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
lua_pop(gL, 1); // pop flags lua_pop(gL, 1); // pop flags
// requires server/admin and the player is not one of them // requires server/admin and the player is not one of them
if ((flags & 1) && playernum != serverplayer && playernum != adminplayer) if ((flags & 1) && playernum != serverplayer && !IsPlayerAdmin(playernum))
goto deny; goto deny;
lua_rawgeti(gL, -1, 1); // push function from command info table lua_rawgeti(gL, -1, 1); // push function from command info table
@ -133,7 +133,7 @@ void COM_Lua_f(void)
UINT8 argc; UINT8 argc;
lua_pop(gL, 1); // pop command info table lua_pop(gL, 1); // pop command info table
if (flags & 1 && !server && adminplayer != playernum) // flag 1: only server/admin can use this command. if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command.
{ {
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"));
return; return;

View file

@ -2610,7 +2610,7 @@ void M_StartControlPanel(void)
MPauseMenu[mpause_switchteam].status = IT_DISABLED; MPauseMenu[mpause_switchteam].status = IT_DISABLED;
MPauseMenu[mpause_psetup].status = IT_DISABLED; MPauseMenu[mpause_psetup].status = IT_DISABLED;
if ((server || adminplayer == consoleplayer)) if ((server || IsPlayerAdmin(consoleplayer)))
{ {
MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL; MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL;
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
@ -3951,7 +3951,7 @@ static void M_Options(INT32 choice)
(void)choice; (void)choice;
// if the player is not admin or server, disable server options // if the player is not admin or server, disable server options
OP_MainMenu[5].status = (Playing() && !(server || adminplayer == consoleplayer)) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
// if the player is playing _at all_, disable the erase data options // if the player is playing _at all_, disable the erase data options
OP_DataOptionsMenu[1].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_DataOptionsMenu[1].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);

View file

@ -37,6 +37,7 @@
#include "d_main.h" #include "d_main.h"
#include "m_argv.h" #include "m_argv.h"
#include "i_system.h" #include "i_system.h"
#include "command.h" // cv_execversion
#include "m_anigif.h" #include "m_anigif.h"
@ -440,7 +441,18 @@ void Command_LoadConfig_f(void)
strcpy(configfile, COM_Argv(1)); strcpy(configfile, COM_Argv(1));
FIL_ForceExtension(configfile, ".cfg"); FIL_ForceExtension(configfile, ".cfg");
// temporarily reset execversion to default
cv_execversion.flags &= ~CV_HIDEN;
COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue));
CV_InitFilterVar();
// exec the config
COM_BufInsertText(va("exec \"%s\"\n", configfile)); COM_BufInsertText(va("exec \"%s\"\n", configfile));
// don't filter anymore vars and don't let this convsvar be changed
COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, MODVERSION));
cv_execversion.flags |= CV_HIDEN;
} }
/** Saves the current configuration and loads another. /** Saves the current configuration and loads another.
@ -477,10 +489,23 @@ void M_FirstLoadConfig(void)
// load default control // load default control
G_Controldefault(); G_Controldefault();
// register execversion here before we load any configs
CV_RegisterVar(&cv_execversion);
// temporarily reset execversion to default
// we shouldn't need to do this, but JUST in case...
cv_execversion.flags &= ~CV_HIDEN;
COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue));
CV_InitFilterVar();
// load config, make sure those commands doesnt require the screen... // load config, make sure those commands doesnt require the screen...
COM_BufInsertText(va("exec \"%s\"\n", configfile)); COM_BufInsertText(va("exec \"%s\"\n", configfile));
// no COM_BufExecute() needed; that does it right away // no COM_BufExecute() needed; that does it right away
// don't filter anymore vars and don't let this convsvar be changed
COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, MODVERSION));
cv_execversion.flags |= CV_HIDEN;
// make sure I_Quit() will write back the correct config // make sure I_Quit() will write back the correct config
// (do not write back the config if it crash before) // (do not write back the config if it crash before)
gameconfig_loaded = true; gameconfig_loaded = true;
@ -536,6 +561,10 @@ void M_SaveConfig(const char *filename)
// header message // header message
fprintf(f, "// SRB2 configuration file.\n"); fprintf(f, "// SRB2 configuration file.\n");
// print execversion FIRST, because subsequent consvars need to be filtered
// always print current MODVERSION
fprintf(f, "%s \"%d\"\n", cv_execversion.name, MODVERSION);
// FIXME: save key aliases if ever implemented.. // FIXME: save key aliases if ever implemented..
CV_SaveVariables(f); CV_SaveVariables(f);

View file

@ -2448,7 +2448,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname)
if (P_IsLocalPlayer(player)) if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname);
else if(server || adminplayer == consoleplayer) else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname);
SetPlayerSkinByNum(playernum, 0); SetPlayerSkinByNum(playernum, 0);
@ -2506,7 +2506,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (P_IsLocalPlayer(player)) if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum); CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum);
else if(server || adminplayer == consoleplayer) else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum); CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
} }

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20; CURRENT_PROJECT_VERSION = 2.1.21;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20; CURRENT_PROJECT_VERSION = 2.1.21;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20; CURRENT_PROJECT_VERSION = 2.1.21;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20; CURRENT_PROJECT_VERSION = 2.1.21;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (