summaryrefslogtreecommitdiff
path: root/src/game/g_admin.c
diff options
context:
space:
mode:
authorPaweł Redman <pawel@redman.xyz>2017-04-13 11:30:00 +0000
committer/dev/humancontroller <devhc@example.com>2017-04-15 12:06:43 +0200
commit5ad9e26c3be1f2ebc6cdb340b685aef30ae16db7 (patch)
tree5ee97c52196122bd8356ad8e09403332e7712fcd /src/game/g_admin.c
parent45973dc48641365b31475733bce7af9c3b8603a6 (diff)
import the cQVM game module
replacing the existing one
Diffstat (limited to 'src/game/g_admin.c')
-rw-r--r--src/game/g_admin.c2907
1 files changed, 1945 insertions, 962 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c
index f9c5f84..de59a47 100644
--- a/src/game/g_admin.c
+++ b/src/game/g_admin.c
@@ -80,6 +80,16 @@ g_admin_cmd_t g_admin_cmds[ ] =
"[^3name|slot#|IP^7] (^5time^7) (^5reason^7)"
},
+ {"bring", G_admin_bring, "bring",
+ "This will bring you to a players location.",
+ "[^3name|slot#^7]"
+ },
+
+ {"bubble", G_admin_bubble, "bubble",
+ "draw attention to a player with bubbles",
+ "[^3name|slot#^7]"
+ },
+
{"buildlog", G_admin_buildlog, "buildlog",
"display a list of recent builds and deconstructs, optionally specifying"
" a team",
@@ -108,26 +118,31 @@ g_admin_cmd_t g_admin_cmds[ ] =
"[^3name|slot#^7]"
},
+ {"denyweapon", G_admin_denyweapon, "denyweapon",
+ "take away a player's ability to use a weapon or class",
+ "[^3name|slot#^7] [^3class|weapon^7]"
+ },
+
{"designate", G_admin_designate, "designate",
"give the player designated builder privileges",
"[^3name|slot#^7]"
},
-
+
{"devmap", G_admin_devmap, "devmap",
"load a map with cheats (and optionally force layout)",
"[^3mapname^7] (^5layout^7)"
},
- {"denyweapon", G_admin_denyweapon, "denyweapon",
- "take away a player's ability to use a weapon or class",
- "[^3name|slot#^7] [^3class|weapon^7]"
- },
-
{"drop", G_admin_drop, "drop",
"kick a client from the server without log",
"[^3name|slot#^7] [^3message^7]"
},
+ {"expire", G_admin_expire, "expire",
+ "Expires up to 5 level 1 admins with !seen times older than g_adminExpireTime",
+ "[^5confirm^7]"
+ },
+
{"flag", G_admin_flag, "flag",
"add an admin flag to a player, prefix flag with '-' to disallow the flag. "
"console can use this command on admin levels by prefacing a '*' to the admin level value.",
@@ -138,7 +153,7 @@ g_admin_cmd_t g_admin_cmds[ ] =
"list all flags understood by this server",
""
},
-
+
{"help", G_admin_help, "help",
"display commands available to you or help on a specific command",
"(^5command^7)"
@@ -148,12 +163,17 @@ g_admin_cmd_t g_admin_cmds[ ] =
"display the contents of server info files",
"(^5subject^7)"
},
-
+
+ {"immunity", G_admin_immunity, "immunity",
+ "give a player ban immunity",
+ "[^3+|-^7](^5slot#^7)"
+ },
+
{"invisible", G_admin_invisible, "invisible",
"hides a player so they cannot be seen in playerlists",
""
},
-
+
{"kick", G_admin_kick, "kick",
"kick a player with an optional reason",
"[^3name|slot#^7] (^5reason^7)"
@@ -224,9 +244,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
""
},
- {"nobuild", G_admin_nobuild, "nobuild",
- "set nobuild markers to prevent players from building in an area",
- "(^5area^7) (^5height^7)"
+ {"outlaw", G_admin_outlaw, "outlaw",
+ "adjust a player's bleed counter, usually to make their base turn on them."
+ " bleed value can be '?' to query their current value, a number to add and activate bleed status,"
+ " +num or -num will silently adjust their current bleed value, 0 will pardon them",
+ "(^5name|slot^7) (^5bleed value)"
},
{"passvote", G_admin_passvote, "passvote",
@@ -240,6 +262,12 @@ g_admin_cmd_t g_admin_cmds[ ] =
"(^5name|slot|*^7)"
},
+ {"practice", G_admin_practice, "practice",
+ "set practice mode for player names with 'clan tag', "
+ "these players will be allowed to join any team regardless of balance. "
+ "'map count' is number of maps to maintain practice mode",
+ "[^3clan tag|off^7] [^3map count^7])"
+ },
{"putteam", G_admin_putteam, "putteam",
"move a player to a specified team",
@@ -253,7 +281,7 @@ g_admin_cmd_t g_admin_cmds[ ] =
{"register", G_admin_register, "register",
"Registers your name to protect it from being used by others or updates your admin name to your current name.",
- ""
+ "[^3level^7] [^3password^7]"
},
{"rename", G_admin_rename, "rename",
@@ -299,12 +327,13 @@ g_admin_cmd_t g_admin_cmds[ ] =
{"spec999", G_admin_spec999, "spec999",
"move 999 pingers to the spectator team",
- ""
- },
-
+ ""},
+
+ //kev: a bit of a hack, but there is no real point to
+ //creating a new admin flag for this, so i stole it from !help
{"specme", G_admin_putmespec, "specme",
- "moves you to the spectators",
- ""
+ "moves you to the spectators (can be done silently with the 's' argument)",
+ "(^5s^7)"
},
{"subnetban", G_admin_subnetban, "subnetban",
@@ -316,7 +345,7 @@ g_admin_cmd_t g_admin_cmds[ ] =
"\n ^1WARNING:^7 Use of this command may make your admin.dat incompatible with other game.qvms"
},
- {"suspendban", G_admin_suspendban, "ban",
+ {"suspendban", G_admin_suspendban, "suspendban",
"suspend a ban for a length of time. time is specified as numbers "
"followed by units 'w' (weeks), 'd' (days), 'h' (hours) or 'm' (minutes),"
" or seconds if no units are specified",
@@ -325,7 +354,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
{"time", G_admin_time, "time",
"show the current local server time",
- ""
+ ""},
+
+ {"tklog", G_admin_tklog, "tklog",
+ "list recent teamkill activity",
+ "(^5start id#|name|-skip#^7) (^5search skip#^7)"
},
{"unban", G_admin_unban, "ban",
@@ -337,13 +370,13 @@ g_admin_cmd_t g_admin_cmds[ ] =
"revoke designated builder privileges",
"[^3name|slot#^7]"
},
-
+
{"unflag", G_admin_flag, "flag",
"clears an admin flag from a player. "
"console can use this command on admin levels by prefacing a '*' to the admin level value.",
"[^3name|slot#|admin#|*adminlevel^7] (^5+^7|^5-^7)[^3flag^7]"
},
-
+
{"unlock", G_admin_unlock, "lock",
"unlock a locked team",
"[^3a|h^7]"
@@ -354,6 +387,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
"[^3name|slot#^7]"
},
+ {"nobuild", G_admin_nobuild, "nobuild",
+ "Enable and control nobuild mode.",
+ "[^3on|off|save|add|del|list|mode|zone|+|-|go^7]"
+ },
+
{"unpause", G_admin_pause, "pause",
"allow a player to interact with the game."
" * will unpause all players, using no argument will unpause game clock",
@@ -376,6 +414,12 @@ g_admin_ban_t *g_admin_bans[ MAX_ADMIN_BANS ];
g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ];
g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ];
+static int admin_adminlog_index = 0;
+g_admin_adminlog_t *g_admin_adminlog[ MAX_ADMIN_ADMINLOGS ];
+
+static int admin_tklog_index = 0;
+g_admin_tklog_t *g_admin_tklog[ MAX_ADMIN_TKLOGS ];
+
// match a certain flag within these flags
// return state of whether flag was found or not,
// set *perm to indicate whether found flag was + or -
@@ -404,16 +448,12 @@ static qboolean admin_permission( char *flags, const char *flag, qboolean *perm
*perm = base_perm;
return qtrue;
}
-
return qfalse;
}
-static int admin_adminlog_index = 0;
-g_admin_adminlog_t *g_admin_adminlog[ MAX_ADMIN_ADMINLOGS ];
-
// This function should only be used directly when the client is connecting and thus has no GUID.
// Else, use G_admin_permission()
-qboolean G_admin_permission_guid( char *guid, const char* flag )
+qboolean G_admin_permission_guid( char *guid, const char *flag )
{
int i;
int l = 0;
@@ -436,8 +476,7 @@ qboolean G_admin_permission_guid( char *guid, const char* flag )
for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
{
if( g_admin_levels[ i ]->level == l )
- return admin_permission( g_admin_levels[ i ]->flags, flag, &perm ) &&
- perm;
+ return admin_permission( g_admin_levels[ i ]->flags, flag, &perm ) && perm;
}
return qfalse;
}
@@ -542,18 +581,13 @@ static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
{
int i;
int alevel = 0;
- int alevel2 = 0;
+ qboolean perm = qfalse;
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
{
if( !Q_stricmp( admin_guid, g_admin_admins[ i ]->guid ) )
{
alevel = g_admin_admins[ i ]->level;
-
- // Novelty Levels should be equivelant to level 1
- if( alevel > 9 )
- alevel = 1;
-
break;
}
}
@@ -561,17 +595,9 @@ static qboolean admin_higher_guid( char *admin_guid, char *victim_guid )
{
if( !Q_stricmp( victim_guid, g_admin_admins[ i ]->guid ) )
{
- alevel2 = g_admin_admins[ i ]->level;
-
- // Novelty Levels should be equivelant to level 1
- if( alevel2 > 9 )
- alevel2 = 1;
-
- if( alevel < alevel2 )
- return qfalse;
-
- if( strstr( g_admin_admins[ i ]->flags, va( "%s", ADMF_IMMUTABLE ) ) )
+ if( alevel < g_admin_admins[ i ]->level )
return qfalse;
+ return ( !admin_permission( g_admin_admins[ i ]->flags, ADMF_IMMUTABLE, &perm ) || !perm );
}
}
return qtrue;
@@ -619,7 +645,7 @@ static void admin_writeconfig( void )
{
fileHandle_t f;
int len, i;
- int t, expiretime;
+ int t;
char levels[ MAX_STRING_CHARS ] = {""};
if( !g_admin.string[ 0 ] )
@@ -650,19 +676,9 @@ static void admin_writeconfig( void )
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
{
// don't write level 0 users
- if( g_admin_admins[ i ]->level < 1 )
+ if( g_admin_admins[ i ]->level == 0 )
continue;
- //if set dont write admins that havent been seen in a while
- expiretime = G_admin_parse_time( g_adminExpireTime.string );
- if( expiretime > 0 ) {
- //only expire level 1 people
- if( t - expiretime > g_admin_admins[ i ]->seen && g_admin_admins[ i ]->level == 1 ) {
- G_Printf("Admin %s has been expired.\n", g_admin_admins[ i ]->name );
- continue;
- }
- }
-
trap_FS_Write( "[admin]\n", 8, f );
trap_FS_Write( "name = ", 10, f );
admin_writeconfig_string( g_admin_admins[ i ]->name, f );
@@ -672,8 +688,6 @@ static void admin_writeconfig( void )
admin_writeconfig_int( g_admin_admins[ i ]->level, f );
trap_FS_Write( "flags = ", 10, f );
admin_writeconfig_string( g_admin_admins[ i ]->flags, f );
- trap_FS_Write( "seen = ", 10, f );
- admin_writeconfig_int( g_admin_admins[ i ]->seen, f );
trap_FS_Write( "\n", 1, f );
}
for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
@@ -697,7 +711,8 @@ static void admin_writeconfig( void )
admin_writeconfig_string( g_admin_bans[ i ]->made, f );
trap_FS_Write( "expires = ", 10, f );
admin_writeconfig_int( g_admin_bans[ i ]->expires, f );
- if( g_admin_bans[ i ]->suspend > t ) {
+ if( g_admin_bans[ i ]->suspend > t )
+ {
trap_FS_Write( "suspend = ", 10, f );
admin_writeconfig_int( g_admin_bans[ i ]->suspend, f );
}
@@ -778,6 +793,253 @@ static void admin_readconfig_int( char **cnf, int *v )
*v = atoi( t );
}
+void G_admin_chat_writeconfig( void )
+{
+ fileHandle_t f;
+ int len;
+ char keybuf[ 16 ];
+ int i, j;
+ qboolean found;
+
+ G_admin_karma_sync( );
+
+ if( !g_chat.string[ 0 ] )
+ {
+ G_Printf( "WARNING: g_chat is not set. "
+ " channel subscriptions will not be saved to a file.\n" );
+ return;
+ }
+
+ // check that there is something to save
+ found = qfalse;
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && !found; i++ )
+ {
+ if( g_admin_admins[ i ]->level == 0 )
+ continue;
+ for( j = 0; j < CHAT_MAXCHAN; j++ )
+ {
+ if( g_admin_admins[ i ]->chat[ j ][ 0 ] )
+ found = qtrue;
+ }
+ if(g_admin_admins[ i ]->seen )
+ found = qtrue;
+ }
+ if( !found )
+ {
+ G_Printf( "Cowardly refusing to create an empty chat file.\n" );
+ return;
+ }
+
+ len = trap_FS_FOpenFile( g_chat.string, &f, FS_WRITE );
+ if( len < 0 )
+ {
+ G_Printf( "chat_writeconfig: could not open g_chat file \"%s\"\n",
+ g_chat.string );
+ return;
+ }
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ // don't write level 0 users
+ if( g_admin_admins[ i ]->level == 0 )
+ continue;
+
+ // don't write users not joined to a channel
+ found = qfalse;
+ for( j = 0; j < CHAT_MAXCHAN; j++ )
+ {
+ if( g_admin_admins[ i ]->chat[ j ][ 0 ] )
+ found = qtrue;
+ }
+ if( !found && !g_admin_admins[ i ]->seen )
+ continue;
+
+ trap_FS_Write( "[chat]\n", 7, f );
+ trap_FS_Write( "guid = ", 10, f );
+ admin_writeconfig_string( g_admin_admins[ i ]->guid, f );
+ trap_FS_Write( "seen = ", 10, f );
+ admin_writeconfig_int( g_admin_admins[ i ]->seen, f );
+ trap_FS_Write( "karma = ", 10, f );
+ admin_writeconfig_int( g_admin_admins[ i ]->karma, f );
+
+ for( j = 0 ; j < CHAT_MAXCHAN; j++ )
+ {
+ if( g_admin_admins[ i ]->chat[ j ][ 0 ] )
+ {
+ Com_sprintf( keybuf, sizeof( keybuf ), "%d = ", j );
+ trap_FS_Write( keybuf, 10, f );
+ admin_writeconfig_string( g_admin_admins[ i ]->chat[ j ], f );
+ }
+ }
+
+ trap_FS_Write( "\n", 1, f );
+ }
+ trap_FS_FCloseFile( f );
+}
+
+qboolean G_admin_chat_readconfig( gentity_t *ent )
+{
+ g_admin_admin_t *a = NULL;
+ fileHandle_t f;
+ int len;
+ char *cnf, *cnf2;
+ char *t;
+ int uc = 0, cc = 0;
+ qboolean chat_open;
+ char guid[ 33 ];
+ int i;
+
+ if( !g_chat.string[ 0 ] )
+ {
+ ADMP( "chat_readconfig: g_chat is not set, not loading channel subscriptions "
+ "from a file\n" );
+ return qfalse;
+ }
+
+ len = trap_FS_FOpenFile( g_chat.string, &f, FS_READ ) ;
+ if( len < 0 )
+ {
+ ADMP( va( "chat_readconfig: could not open chat config file %s\n",
+ g_chat.string ) );
+ return qfalse;
+ }
+ cnf = G_Alloc( len + 1 );
+ cnf2 = cnf;
+ trap_FS_Read( cnf, len, f );
+ *( cnf + len ) = '\0';
+ trap_FS_FCloseFile( f );
+
+ t = COM_Parse( &cnf );
+ chat_open = qfalse;
+ while( *t )
+ {
+ if( !Q_stricmp( t, "[chat]" ) )
+ {
+ chat_open = qtrue;
+ a = NULL;
+ }
+ else if( chat_open )
+ {
+ int chan;
+
+ if( !Q_stricmp( t, "guid" ) )
+ {
+ admin_readconfig_string( &cnf, guid, sizeof( guid ) );
+ for( i = 0 ; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
+ {
+ if( !Q_stricmp( guid, g_admin_admins[ i ]->guid ) )
+ {
+ a = g_admin_admins[ i ];
+ memset( a->chat, 0, sizeof( a->chat) );
+ uc++;
+ break;
+ }
+ }
+ }
+ else if( a == NULL )
+ {
+ // no guid match, ignored
+ }
+ else if( !Q_stricmp( t, "seen" ) )
+ {
+ admin_readconfig_int( &cnf, &a->seen );
+ }
+ else if( !Q_stricmp( t, "karma" ) )
+ {
+ admin_readconfig_int( &cnf, &a->karma );
+ }
+ else if( *t >= '0' && *t <= '9' )
+ {
+ chan = atoi( t );
+ if( chan >= 0 && chan < CHAT_MAXCHAN && a )
+ {
+ admin_readconfig_string( &cnf, a->chat[ chan ], sizeof( a->chat[ chan ] ) );
+ cc++;
+ }
+ }
+ else
+ {
+ ADMP( va( "chat_readconfig: [chat] parse error near %s on line %d\n",
+ t, COM_GetCurrentParseLine() ) );
+ }
+ }
+
+ t = COM_Parse( &cnf );
+ }
+
+ G_Free( cnf2 );
+ ADMP( va( "chat_readconfig: loaded %d users with %d channels\n", uc, cc ) );
+ return qtrue;
+}
+
+void G_admin_chat_sync( gentity_t *ent )
+{
+ gentity_t *target;
+ int i, j;
+ qboolean rejoin = qfalse;
+
+ if( !ent || !ent->client || ent->client->pers.adminLevel < 1 )
+ return;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
+ {
+ if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ {
+ ent->client->pers.karma = g_admin_admins[ i ]->karma;
+ for( j = 0; j < CHAT_MAXCHAN; j++ )
+ {
+ Q_strncpyz( ent->client->pers.chat[ j ],
+ g_admin_admins[ i ]->chat[ j ],
+ sizeof( g_admin_admins[ i ]->chat[ j ] ) );
+ }
+ rejoin = qtrue;
+ break;
+ }
+ }
+
+ if( !rejoin )
+ return;
+
+ for( j = 0; j < CHAT_MAXCHAN; j++ )
+ {
+ if( !ent->client->pers.chat[ j ][ 0 ] )
+ continue;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ target = &g_entities[ i ];
+ if( target && target->client &&
+ target->client->pers.connected == CON_CONNECTED &&
+ !Q_stricmp( target->client->pers.chat[ j ], ent->client->pers.chat[ j ] ) )
+ {
+ trap_SendServerCommand( i, va( "print \"join: %s^7 has rejoined channel #%d\n\"",
+ ent->client->pers.netname, j ) );
+ }
+ }
+ }
+}
+
+void G_admin_chat_update( gentity_t *ent, int chan )
+{
+ int i;
+
+ if( !ent || !ent->client || ent->client->pers.adminLevel < 1 )
+ return;
+
+ if( chan < 0 || chan > CHAT_MAXCHAN - 1 )
+ return;
+
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
+ {
+ if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ {
+ Q_strncpyz( g_admin_admins[ i ]->chat[ chan ],
+ ent->client->pers.chat[ chan ],
+ sizeof( g_admin_admins[ i ]->chat[ chan ] ) );
+ return;
+ }
+ }
+}
+
// if we can't parse any levels from readconfig, set up default
// ones to make new installs easier for admins
static void admin_default_levels( void )
@@ -828,7 +1090,7 @@ static void admin_default_levels( void )
sizeof( l->name ) );
Q_strncpyz( g_admin_levels[ 4 ]->flags,
"listplayers admintest help specme time putteam spec999 kick mute showbans "
- "ban namelog warn denybuild ADMINCHAT SEESFULLLISTPLAYERS",
+ "ban namelog warn denybuild invisible ADMINCHAT SEESFULLLISTPLAYERS",
sizeof( l->flags ) );
Q_strncpyz( g_admin_levels[ 5 ]->name, "^1Server Operator",
@@ -897,7 +1159,7 @@ void G_admin_set_adminname( gentity_t *ent )
}
}
-// Get an admin's registered name
+// get an admin's realname
const char *G_admin_get_adminname( gentity_t *ent )
{
int i;
@@ -914,8 +1176,6 @@ const char *G_admin_get_adminname( gentity_t *ent )
return ent->client->pers.netname;
}
-// Get an admin's name to print as the user of various commands,
-// obeying admin stealth settings when necessary
char* G_admin_adminPrintName( gentity_t *ent )
{
char *out;
@@ -1110,26 +1370,27 @@ static int admin_listadmins( gentity_t *ent, int start, char *search, int minlev
break;
}
}
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
+ ADMBP( va( "%4i %4i %s^7 (*%s) ^1%1s ^7%s^7\n",
i,
l,
lname,
guid_stub,
+ ( G_admin_permission( &g_entities[ i ], ADMF_BAN_IMMUNITY ) ) ? "I" : "",
vic->client->pers.netname ) );
drawn++;
}
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]
&& drawn < MAX_ADMIN_LISTITEMS; i++ )
- if( g_admin_admins[ i ]->level >= minlevel )
+ if( ( minlevel > 0 && g_admin_admins[ i ]->level >= minlevel ) ||
+ ( minlevel < 0 && g_admin_admins[ i ]->level <= minlevel ) ||
+ ( minlevel == 0 && g_admin_admins[ i ]->level != 0 ) )
{
-
if( start )
{
start--;
continue;
}
-
if( search[ 0 ] )
{
G_SanitiseString( g_admin_admins[ i ]->name, name, sizeof( name ) );
@@ -1174,11 +1435,12 @@ static int admin_listadmins( gentity_t *ent, int start, char *search, int minlev
break;
}
}
- ADMBP( va( "%4i %4i %s^7 (*%s) %s^7\n",
+ ADMBP( va( "%4i %4i %s^7 (*%s) ^1%1s ^7%s^7\n",
( i + MAX_CLIENTS ),
g_admin_admins[ i ]->level,
lname,
guid_stub,
+ ( G_admin_permission_guid( g_admin_admins[ i ]->guid, ADMF_BAN_IMMUNITY ) ) ? "I" : "",
g_admin_admins[ i ]->name ) );
drawn++;
}
@@ -1223,6 +1485,7 @@ qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
int t;
char notice[51];
qboolean ignoreIP = qfalse;
+ qboolean banned = qfalse;
trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
@@ -1252,17 +1515,15 @@ qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
if(!IP[k]) continue;
userIP |= IP[k] << 8*(k-1);
}
- ignoreIP = G_admin_permission_guid( guid , ADMF_BAN_IMMUNITY );
+ ignoreIP = G_admin_permission_guid( guid, ADMF_BAN_IMMUNITY );
for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
{
// 0 is for perm ban
if( g_admin_bans[ i ]->expires != 0 &&
( g_admin_bans[ i ]->expires - t ) < 1 )
continue;
- //if suspend time is over continue
if( g_admin_bans[ i ]->suspend >= t )
continue;
-
if( !ignoreIP )
{
tempIP = userIP;
@@ -1295,47 +1556,38 @@ qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
if( intIP == tempIP || mask == 0 )
{
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
-
- // flood protected
- if( t - lastConnectTime >= 300 ||
- Q_stricmp( lastConnectIP, ip ) )
- {
- lastConnectTime = t;
- Q_strncpyz( lastConnectIP, ip, sizeof( lastConnectIP ) );
-
- G_WarningsPrintf(
- "ban",
- "Banned player %s^7 (%s^7) tried to connect (ban #%i on %s by %s^7 expires %s reason: %s^7 )\n",
- Info_ValueForKey( userinfo, "name" ),
- g_admin_bans[ i ]->name,
- i+1,
- ip,
- g_admin_bans[ i ]->banner,
- duration,
- g_admin_bans[ i ]->reason );
- }
-
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration,
- notice
- );
G_LogPrintf("Banned player tried to connect from IP %s\n", ip);
- return qtrue;
+ banned = qtrue;
}
}
- if( *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
+ if( !banned && *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
+ {
+ G_LogPrintf("Banned player tried to connect with GUID %s\n", guid);
+ banned = qtrue;
+ }
+ if( banned )
{
char duration[ 32 ];
G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
duration, sizeof( duration ) );
+
+ // flood protected
+ if( t - lastConnectTime >= 300 ||
+ Q_stricmp( lastConnectIP, ip ) )
+ {
+ lastConnectTime = t;
+ Q_strncpyz( lastConnectIP, ip, sizeof( lastConnectIP ) );
+
+ G_AdminsPrintf(
+ "Banned player %s^7 (%s^7) tried to connect (ban #%i on %s by %s^7 expires %s reason: %s^7 )\n",
+ Info_ValueForKey( userinfo, "name" ),
+ g_admin_bans[ i ]->name,
+ i+1,
+ ip,
+ g_admin_bans[ i ]->banner,
+ duration,
+ g_admin_bans[ i ]->reason );
+ }
Com_sprintf(
reason,
rlen,
@@ -1344,7 +1596,6 @@ qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen )
g_admin_bans[ i ]->reason,
duration
);
- G_Printf("Banned player tried to connect with GUID %s\n", guid);
return qtrue;
}
}
@@ -1469,10 +1720,7 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
char n2[ MAX_NAME_LENGTH ];
int clientNum = ( client - level.clients );
- if ( client->sess.invisible == qfalse )
- {
- G_admin_seen_update( client->pers.guid );
- }
+ G_admin_seen_update( client, disconnect );
G_SanitiseString( client->pers.netname, n1, sizeof( n1 ) );
for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
@@ -1539,11 +1787,6 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
G_AdminsPrintf( "^7%s^7's Putteam spectator has been restored\n", client->pers.netname );
g_admin_namelog[ i ]->specExpires = 0;
}
- if( g_admin_namelog[ i ]->voteCount > 0 )
- {
- client->pers.voteCount = g_admin_namelog[ i ]->voteCount;
- g_admin_namelog[ i ]->voteCount = 0;
- }
}
else
{
@@ -1573,12 +1816,9 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
{
g_admin_namelog[ i ]->specExpires = client->pers.specExpires;
}
- if( client->pers.voteCount > 0 )
- {
- g_admin_namelog[ i ]->voteCount = client->pers.voteCount;
- }
}
+
return;
}
}
@@ -1698,10 +1938,6 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
{
admin_readconfig_string( &cnf, a->flags, sizeof( a->flags ) );
}
- else if( !Q_stricmp( t, "seen" ) )
- {
- admin_readconfig_int( &cnf, &a->seen );
- }
else
{
ADMP( va( "^3!readconfig: ^7[admin] parse error near %s on line %d\n",
@@ -1863,6 +2099,9 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
for( i = 0; i < level.maxclients; i++ )
if( level.clients[ i ].pers.connected != CON_DISCONNECTED )
level.clients[ i ].pers.adminLevel = G_admin_level( &g_entities[ i ] );
+
+ G_admin_chat_readconfig( ent );
+
return qtrue;
}
@@ -1874,7 +2113,6 @@ qboolean G_admin_time( gentity_t *ent, int skiparg )
t = trap_RealTime( &qt );
ADMP( va( "^3!time: ^7local time is %02i:%02i:%02i\n",
qt.tm_hour, qt.tm_min, qt.tm_sec ) );
-
return qtrue;
}
@@ -2138,379 +2376,6 @@ qboolean G_admin_setlevel( gentity_t *ent, int skiparg )
return qtrue;
}
-static int SortFlags( const void *pa, const void *pb )
-{
- char *a = (char *)pa;
- char *b = (char *)pb;
-
- if( *a == '-' || *a == '+' )
- a++;
- if( *b == '-' || *b == '+' )
- b++;
- return strcmp(a, b);
-}
-
-#define MAX_USER_FLAGS 200
-const char *G_admin_user_flag( char *oldflags, char *flag, qboolean add, qboolean clear,
- char *newflags, int size )
-{
- char *token, *token_p;
- char *key;
- char head_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
- char tail_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
- char allflag[ MAX_ADMIN_FLAG_LEN ];
- char newflag[ MAX_ADMIN_FLAG_LEN ];
- int head_count = 0;
- int tail_count = 0;
- qboolean flagset = qfalse;
- int i;
-
- if( !flag[ 0 ] )
- {
- return "invalid admin flag";
- }
-
- allflag[ 0 ] = '\0';
- token_p = oldflags;
- while( *( token = COM_Parse( &token_p ) ) )
- {
- key = token;
- if( *key == '-' || *key == '+' )
- key++;
-
- if( !strcmp( key, flag ) )
- {
- if( flagset )
- continue;
- flagset = qtrue;
- if( clear )
- {
- // clearing ALLFLAGS will result in clearing any following flags
- if( !strcmp( key, ADMF_ALLFLAGS ) )
- break;
- else
- continue;
- }
- Com_sprintf( newflag, sizeof( newflag ), "%s%s",
- ( add ) ? "+" : "-", key );
- }
- else
- {
- Q_strncpyz( newflag, token, sizeof( newflag ) );
- }
-
- if( !strcmp( key, ADMF_ALLFLAGS ) )
- {
- if( !allflag[ 0 ] )
- Q_strncpyz( allflag, newflag, sizeof( allflag ) );
- continue;
- }
-
- if( !allflag[ 0 ] )
- {
- if( head_count < MAX_USER_FLAGS )
- {
- Q_strncpyz( head_flags[ head_count ], newflag,
- sizeof( head_flags[ head_count ] ) );
- head_count++;
- }
- }
- else
- {
- if( tail_count < MAX_USER_FLAGS )
- {
- Q_strncpyz( tail_flags[ tail_count ], newflag,
- sizeof( tail_flags[ tail_count ] ) );
- tail_count++;
- }
- }
- }
-
- if( !flagset && !clear )
- {
- if( !strcmp( flag, ADMF_ALLFLAGS ) )
- {
- Com_sprintf( allflag, sizeof( allflag ), "%s%s",
- ( add ) ? "" : "-", ADMF_ALLFLAGS );
- }
- else if( !allflag[ 0 ] )
- {
- if( head_count < MAX_USER_FLAGS )
- {
- Com_sprintf( head_flags[ head_count ], sizeof( head_flags[ head_count ] ),
- "%s%s", ( add ) ? "" : "-", flag );
- head_count++;
- }
- }
- else
- {
- if( tail_count < MAX_USER_FLAGS )
- {
- Com_sprintf( tail_flags[ tail_count ], sizeof( tail_flags[ tail_count ] ),
- "%s%s", ( add ) ? "+" : "-", flag );
- tail_count++;
- }
- }
- }
-
- qsort( head_flags, head_count, sizeof( head_flags[ 0 ] ), SortFlags );
- qsort( tail_flags, tail_count, sizeof( tail_flags[ 0 ] ), SortFlags );
-
- // rebuild flags
- newflags[ 0 ] = '\0';
- for( i = 0; i < head_count; i++ )
- {
- Q_strcat( newflags, size,
- va( "%s%s", ( i ) ? " ": "", head_flags[ i ] ) );
- }
- if( allflag[ 0 ] )
- {
- Q_strcat( newflags, size,
- va( "%s%s", ( newflags[ 0 ] ) ? " ": "", allflag ) );
-
- for( i = 0; i < tail_count; i++ )
- {
- Q_strcat( newflags, size,
- va( " %s", tail_flags[ i ] ) );
- }
- }
-
- return NULL;
-}
-
-typedef struct {
- char *flag;
- char *description;
-} AdminFlagListEntry_t;
-static AdminFlagListEntry_t adminFlagList[] =
-{
- { ADMF_ACTIVITY, "inactivity rules do not apply" },
- { ADMF_ADMINCHAT, "can see and use admin chat" },
- { ADMF_ALLFLAGS, "has all flags and can use any command" },
- { ADMF_BAN_IMMUNITY, "immune from IP bans" },
- { ADMF_CAN_PERM_BAN, "can permanently ban players" },
- { ADMF_DBUILDER, "permanent designated builder" },
- { ADMF_FORCETEAMCHANGE, "team balance rules do not apply" },
- { ADMF_INCOGNITO, "does not show as admin in !listplayers" },
- { ADMF_IMMUNITY, "cannot be vote kicked or muted" },
- { ADMF_IMMUTABLE, "admin commands cannot be used on them" },
- { ADMF_NOCENSORFLOOD, "no flood protection" },
- { ADMF_NO_VOTE_LIMIT, "vote limitations do not apply" },
- { ADMF_SEESFULLLISTPLAYERS, "sees all info in !listplayers" },
- { ADMF_SPEC_ALLCHAT, "can see team chat as spectator" },
- { ADMF_ADMINSTEALTH, "uses admin stealth" },
- { ADMF_TEAMCHANGEFREE, "keeps credits on team switch" },
- { ADMF_TEAMCHAT_CMD, "can run commands from team chat" },
- { ADMF_UNACCOUNTABLE, "does not need to specify reason for kick/ban" },
- { ADMF_NO_CHAT, "can not talk" },
- { ADMF_NO_VOTE, "can not call votes" }
-};
-static int adminNumFlags= sizeof( adminFlagList ) / sizeof( adminFlagList[ 0 ] );
-
-#define MAX_LISTCOMMANDS 128
-qboolean G_admin_flaglist( gentity_t *ent, int skiparg )
-{
- qboolean shown[ MAX_LISTCOMMANDS ];
- int i, j;
- int count = 0;
-
- ADMBP_begin();
-
- ADMBP( "^3Ability flags:\n" );
-
- for( i = 0; i < adminNumFlags; i++ )
- {
- ADMBP( va( " %s%-20s ^7%s\n",
- ( adminFlagList[ i ].flag[ 0 ] != '.' ) ? "^5" : "^1",
- adminFlagList[ i ].flag,
- adminFlagList[ i ].description ) );
- }
-
- ADMBP( "^3Command flags:\n" );
-
- memset( shown, 0, sizeof( shown ) );
- for( i = 0; i < adminNumCmds; i++ )
- {
- if( i < MAX_LISTCOMMANDS && shown[ i ] )
- continue;
- ADMBP( va( " ^5%-20s^7", g_admin_cmds[ i ].flag ) );
- for( j = i; j < adminNumCmds; j++ )
- {
- if( !strcmp( g_admin_cmds[ j ].flag, g_admin_cmds[ i ].flag ) )
- {
- ADMBP( va( " %s", g_admin_cmds[ j ].keyword ) );
- if( j < MAX_LISTCOMMANDS )
- shown[ j ] = qtrue;
- }
- }
- ADMBP( "\n" );
- count++;
- }
-
- ADMBP( va( "^3!flaglist: ^7listed %d abilities and %d command flags\n",
- adminNumFlags, count ) );
-
- ADMBP_end();
-
- return qtrue;
-}
-
-qboolean G_admin_flag( gentity_t *ent, int skiparg )
-{
- char command[ MAX_ADMIN_CMD_LEN ], *cmd;
- char name[ MAX_NAME_LENGTH ];
- char flagbuf[ MAX_ADMIN_FLAG_LEN ];
- char *flag;
- int id;
- char adminname[ MAX_NAME_LENGTH ] = {""};
- const char *result;
- qboolean add = qtrue;
- qboolean clear = qfalse;
- int admin_level = -1;
- int i, level;
-
- G_SayArgv( skiparg, command, sizeof( command ) );
- cmd = command;
- if( *cmd == '!' )
- cmd++;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( va( "^3!%s: ^7usage: !%s slot# flag\n", cmd, cmd ) );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( name[ 0 ] == '*' )
- {
- if( ent )
- {
- ADMP( va( "^3!%s: only console can change admin level flags\n", cmd ) );
- return qfalse;
- }
- id = atoi( name + 1 );
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_levels[ i ]->level == id )
- {
- admin_level = i;
- break;
- }
- }
- if( admin_level < 0 )
- {
- ADMP( va( "^3!%s: admin level %d does not exist\n", cmd, id ) );
- return qfalse;
- }
- Com_sprintf( adminname, sizeof( adminname ), "admin level %d", id );
- }
- else
- {
- id = G_admin_find_admin_slot( ent, name, cmd, adminname, sizeof( adminname ) );
- if( id < 0 )
- return qfalse;
-
- if( ent && !admin_higher_guid( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
- {
- ADMP( va( "^3%s:^7 your intended victim has a higher admin level than you\n", cmd ) );
- return qfalse;
- }
- }
-
- if( G_SayArgc() < 3 + skiparg )
- {
- flag = "";
- level = 0;
- if( admin_level < 0 )
- {
- for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
- {
- if( g_admin_admins[ id ]->level == g_admin_levels[ i ]->level )
- {
- flag = g_admin_levels[ i ]->flags;
- level = g_admin_admins[ id ]->level;
- break;
- }
- }
- ADMP( va( "^3%s:^7 flags for %s^7 are '^3%s^7'\n",
- cmd, adminname, g_admin_admins[ id ]->flags) );
- }
- else
- {
- flag = g_admin_levels[ admin_level ]->flags;
- level = g_admin_levels[ admin_level ]->level;
- }
- ADMP( va( "^3%s:^7 level %d flags are '%s'\n",
- cmd, level, flag ) );
-
- return qtrue;
- }
-
- G_SayArgv( 2 + skiparg, flagbuf, sizeof( flagbuf ) );
- flag = flagbuf;
- if( flag[ 0 ] == '-' || flag[ 0 ] == '+' )
- {
- add = ( flag[ 0 ] == '+' );
- flag++;
- }
- if( ent && !Q_stricmp( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
- {
- ADMP( va( "^3%s:^7 you may not change your own flags (use rcon)\n", cmd ) );
- return qfalse;
- }
- if( flag[ 0 ] != '.' && !G_admin_permission( ent, flag ) )
- {
- ADMP( va( "^3%s:^7 you can only change flags that you also have\n", cmd ) );
- return qfalse;
- }
-
- if( !Q_stricmp( cmd, "unflag" ) )
- {
- clear = qtrue;
- }
-
- if( admin_level < 0 )
- {
- result = G_admin_user_flag( g_admin_admins[ id ]->flags, flag, add, clear,
- g_admin_admins[ id ]->flags, sizeof( g_admin_admins[ id ]->flags ) );
- }
- else
- {
- result = G_admin_user_flag( g_admin_levels[ admin_level ]->flags, flag, add, clear,
- g_admin_levels[ admin_level ]->flags,
- sizeof( g_admin_levels[ admin_level ]->flags ) );
- }
- if( result )
- {
- ADMP( va( "^3!flag: ^7an error occured setting flag '^3%s^7', %s\n",
- flag, result ) );
- return qfalse;
- }
-
- if( !Q_stricmp( cmd, "flag" ) )
- {
- G_AdminsPrintf( "^3!%s: ^7%s^7 was %s admin flag '%s' by %s\n",
- cmd, adminname,
- ( add ) ? "given" : "denied",
- flag,
- ( ent ) ? ent->client->pers.netname : "console" );
- }
- else
- {
- G_AdminsPrintf( "^3!%s: ^7admin flag '%s' for %s^7 cleared by %s\n",
- cmd, flag, adminname,
- ( ent ) ? ent->client->pers.netname : "console" );
- }
-
- if( !g_admin.string[ 0 ] )
- ADMP( va( "^3!%s: ^7WARNING g_admin not set, not saving admin record "
- "to a file\n", cmd ) );
- else
- admin_writeconfig();
-
- return qtrue;
-}
-
int G_admin_parse_time( const char *time )
{
int seconds = 0, num = 0;
@@ -2544,6 +2409,49 @@ int G_admin_parse_time( const char *time )
return seconds;
}
+static void admin_check_duplicate_ban( int ban )
+{
+ qtime_t qt;
+ int t;
+ int i, j;
+ qboolean immune;
+
+ if ( ban < 0 || ban >= MAX_ADMIN_BANS || !g_admin_bans[ ban ] )
+ return;
+
+ t = trap_RealTime( &qt );
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ if( g_admin_bans[ i ]->expires != 0
+ && ( g_admin_bans[ i ]->expires - t ) < 1 )
+ {
+ continue;
+ }
+
+ if( i != ban &&
+ strstr( g_admin_bans[ ban ]->ip, g_admin_bans[ i ]->ip ) == g_admin_bans[ ban ]->ip )
+ {
+ immune = qfalse;
+
+ for( j = 0; j < MAX_ADMIN_ADMINS && g_admin_admins[ j ]; j++ )
+ {
+ if( !Q_stricmp( g_admin_bans[ ban ]->guid, g_admin_admins[ j ]->guid ) &&
+ G_admin_permission_guid( g_admin_admins[ j ]->guid, ADMF_BAN_IMMUNITY ) )
+ {
+ immune = qtrue;
+ }
+ }
+
+ G_AdminsPrintf( "new ban #%d duplicates %sban #%d (%s^7)%s.\n",
+ ban + 1,
+ ( g_admin_bans[ i ]->suspend > t ) ? "SUSPENDED " : "",
+ i + 1,
+ g_admin_bans[ i ]->name,
+ ( immune ) ? ", player has immunity" : "" );
+ }
+ }
+}
+
static qboolean admin_create_ban( gentity_t *ent,
char *netname,
char *guid,
@@ -2597,6 +2505,82 @@ static qboolean admin_create_ban( gentity_t *ent,
return qfalse;
}
g_admin_bans[ i ] = b;
+
+ admin_check_duplicate_ban( i );
+
+ return qtrue;
+}
+
+static qboolean admin_create_ban_check_repeats( gentity_t *ent,
+ char *netname,
+ char *guid,
+ char *ip,
+ int seconds,
+ char *reason )
+{
+ qboolean repeatBan = qfalse;
+ qboolean isKick = qfalse;
+ qtime_t qt;
+ int t;
+ int i;
+
+ t = trap_RealTime( &qt );
+
+ if( seconds >= G_admin_parse_time( g_adminTempBan.string ) - 60 &&
+ seconds <= G_admin_parse_time( g_adminTempBan.string ) + 60 )
+ isKick = qtrue;
+
+ if( g_adminBanRepeatKicks.integer && isKick )
+ {
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ] && !repeatBan; i++ )
+ {
+ if( g_admin_bans[ i ]->expires != 0 &&
+ g_admin_bans[ i ]->expires - t < 1 )
+ continue;
+
+ if( !Q_stricmp( ip, g_admin_bans[ i ]->ip ) ||
+ ( guid[0] != 'X' && !Q_stricmp( guid, g_admin_bans[ i ]->guid) ))
+ {
+ char duration[ 32 ];
+
+ g_admin_bans[ i ]->suspend = 0;
+ g_admin_bans[ i ]->expires += g_adminBanRepeatKicks.integer * 60 * 60;
+ repeatBan = qtrue;
+
+ G_admin_duration( ( g_admin_bans[ i ]->expires - t ), duration, sizeof( duration ) );
+ trap_SendServerCommand( -1,
+ va( "print \"^3autoban: ^7%s^7 has been auto-banned. duration: %s, reason: repeated kicks\n\"",
+ netname, duration ) );
+
+ return qtrue;
+ }
+ }
+ }
+
+ if( !admin_create_ban( ent, netname, guid, ip, seconds, reason ) )
+ return qfalse;
+
+ if( g_adminBanRepeatKicks.integer && seconds > 0 && isKick )
+ {
+ int newestBan = -1;
+ int length;
+
+ length = g_adminBanRepeatKicks.integer * 60 * 60;
+ if( admin_create_ban( ent, netname, guid, ip, length, reason ) )
+ {
+ for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
+ {
+ newestBan = i;
+ }
+ if( newestBan >= 0 &&
+ !Q_stricmp( ip, g_admin_bans[ newestBan ]->ip ) )
+ {
+ g_admin_bans[ newestBan ]->suspend = t + length;
+ Q_strncpyz( g_admin_bans[ newestBan ]->banner, "^3auto-banner", sizeof( g_admin_bans[ newestBan ]->banner ) );
+ }
+ }
+ }
+
return qtrue;
}
@@ -2634,7 +2618,8 @@ qboolean G_admin_kick( gentity_t *ent, int skiparg )
return qfalse;
}
vic = &g_entities[ pids[ 0 ] ];
- admin_create_ban( ent,
+ G_admin_autorevert( vic );
+ admin_create_ban_check_repeats( ent,
vic->client->pers.netname,
vic->client->pers.guid,
vic->client->pers.ip, G_admin_parse_time( g_adminTempBan.string ),
@@ -2642,10 +2627,20 @@ qboolean G_admin_kick( gentity_t *ent, int skiparg )
if( g_admin.string[ 0 ] )
admin_writeconfig();
+ vic->client->pers.karma -= 5000;
+
trap_SendServerCommand( pids[ 0 ],
va( "disconnect \"You have been kicked.\n%s^7\nreason:\n%s\n%s\"",
( ent ) ? va( "admin:\n%s", G_admin_adminPrintName( ent ) ) : "admin\nconsole",
( *reason ) ? reason : "kicked by admin", notice ) );
+
+ G_LogPrintf( "kick: %i %i [%s] (%s) %s^7 %s^7\n",
+ vic->client->ps.clientNum,
+ G_admin_parse_time( g_adminTempBan.string ),
+ vic->client->pers.ip,
+ vic->client->pers.guid,
+ vic->client->pers.netname,
+ ( *reason ) ? reason : "automatic temp ban created by kick" );
trap_DropClient( pids[ 0 ], va( "kicked%s^7, reason: %s",
( ent ) ? va( " by %s", G_admin_adminPrintName( ent ) ) : " by console",
@@ -2669,6 +2664,7 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg )
char s2[ MAX_NAME_LENGTH ];
char guid_stub[ 9 ];
char notice[51];
+ gentity_t *vic;
trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
@@ -2823,7 +2819,7 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg )
return qfalse;
}
- admin_create_ban( ent,
+ admin_create_ban_check_repeats( ent,
g_admin_namelog[ logmatch ]->name[ 0 ],
g_admin_namelog[ logmatch ]->guid,
g_admin_namelog[ logmatch ]->ip,
@@ -2836,6 +2832,13 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg )
else
admin_writeconfig();
+ G_LogPrintf( "ban: %i %i [%s] (%s) %s^7 %s^7\n",
+ g_admin_namelog[ logmatch ]->slot, seconds,
+ g_admin_namelog[ logmatch ]->ip,
+ g_admin_namelog[ logmatch ]->guid,
+ g_admin_namelog[ logmatch ]->name[ 0 ],
+ ( *reason ) ? reason : "banned by admin" );
+
if( g_admin_namelog[ logmatch ]->slot == -1 )
{
// client is already disconnected so stop here
@@ -2847,6 +2850,11 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg )
( *reason ) ? reason : "banned by admin" ) );
return qtrue;
}
+ vic = &g_entities[ g_admin_namelog[ logmatch ]->slot ];
+ G_admin_autorevert( vic );
+
+ if( g_karma.integer )
+ vic->client->pers.karma -= 5000;
trap_SendServerCommand( g_admin_namelog[ logmatch ]->slot,
va( "disconnect \"You have been banned.\n"
@@ -3022,6 +3030,7 @@ qboolean G_admin_subnetban( gentity_t *ent, int skiparg )
ADMP( "^3!subnetban: ^7Only console may ban such a large network. Regular admins may only ban >=16.\n" );
return qfalse;
}
+
if( strcmp(exl, "!") )
{
ADMP( "^3!subnetban: ^1WARNING:^7 you are about to ban a large network, use !subnetban [ban] [mask] ! to force^7\n" );
@@ -3065,12 +3074,12 @@ qboolean G_admin_subnetban( gentity_t *ent, int skiparg )
{
Q_strncpyz(
cIPRlow,
- va("%u.%u.%u.%u", (IPRlow & (255 << 24)) >> 24, (IPRlow & (255 << 16)) >> 16, (IPRlow & (255 << 8)) >> 8, IPRlow & 255),
+ va("%i.%i.%i.%i", (IPRlow & (255 << 24)) >> 24, (IPRlow & (255 << 16)) >> 16, (IPRlow & (255 << 8)) >> 8, IPRlow & 255),
sizeof( cIPRlow )
);
Q_strncpyz(
cIPRhigh,
- va("%u.%u.%u.%u", (IPRhigh & (255 << 24)) >> 24, (IPRhigh & (255 << 16)) >> 16, (IPRhigh & (255 << 8)) >> 8, IPRhigh & 255),
+ va("%i.%i.%i.%i", (IPRhigh & (255 << 24)) >> 24, (IPRhigh & (255 << 16)) >> 16, (IPRhigh & (255 << 8)) >> 8, IPRhigh & 255),
sizeof( cIPRhigh )
);
}
@@ -3097,16 +3106,15 @@ qboolean G_admin_subnetban( gentity_t *ent, int skiparg )
return qtrue;
}
+
qboolean G_admin_suspendban( gentity_t *ent, int skiparg )
{
int bnum;
int length;
- int timenow = 0;
int expires = 0;
char *arg;
char bs[ 5 ];
char duration[ 32 ];
- qtime_t qt;
if( G_SayArgc() < 3 + skiparg )
{
@@ -3127,9 +3135,7 @@ qboolean G_admin_suspendban( gentity_t *ent, int skiparg )
}
arg = G_SayConcatArgs( 2 + skiparg );
- timenow = trap_RealTime( &qt );
length = G_admin_parse_time( arg );
-
if( length < 0 )
{
ADMP( "^3!suspendban: ^7invalid length\n" );
@@ -3140,16 +3146,13 @@ qboolean G_admin_suspendban( gentity_t *ent, int skiparg )
length = MAX_ADMIN_BANSUSPEND_DAYS * 24 * 60 * 60;
ADMP( va( "^3!suspendban: ^7maximum ban suspension is %d days\n",
MAX_ADMIN_BANSUSPEND_DAYS ) );
- } else if( g_admin_bans[ bnum - 1 ]->expires > 0 && length + timenow > g_admin_bans[ bnum - 1 ]->expires ) {
- length = g_admin_bans[ bnum - 1 ]->expires - timenow;
- G_admin_duration( length , duration, sizeof( duration ) );
- ADMP( va( "^3!suspendban: ^7Suspension Duration trimmed to Ban duration: %s\n",
- duration ) );
}
if ( length > 0 )
{
- expires = timenow + length;
+ qtime_t qt;
+
+ expires = trap_RealTime( &qt ) + length;
}
if( g_admin_bans[ bnum - 1 ]->suspend == expires )
{
@@ -3225,93 +3228,6 @@ qboolean G_admin_unban( gentity_t *ent, int skiparg )
return qtrue;
}
-qboolean G_admin_putteam( gentity_t *ent, int skiparg )
-{
- int pids[ MAX_CLIENTS ];
- char name[ MAX_NAME_LENGTH ], team[ 7 ], err[ MAX_STRING_CHARS ];
- gentity_t *vic;
- pTeam_t teamnum = PTE_NONE;
- char teamdesc[ 32 ] = {"spectators"};
- char secs[ 7 ];
- int seconds = 0;
- qboolean useDuration = qfalse;
-
- G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- G_SayArgv( 2 + skiparg, team, sizeof( team ) );
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!putteam: ^7usage: !putteam [name] [h|a|s] (duration)\n" );
- return qfalse;
- }
-
- if( G_ClientNumbersFromString( name, pids ) != 1 )
- {
- G_MatchOnePlayer( pids, err, sizeof( err ) );
- ADMP( va( "^3!putteam: ^7%s\n", err ) );
- return qfalse;
- }
- if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
- {
- ADMP( "^3!putteam: ^7sorry, but your intended victim has a higher "
- " admin level than you\n" );
- return qfalse;
- }
- vic = &g_entities[ pids[ 0 ] ];
-
- if ( vic->client->sess.invisible == qtrue )
- {
- ADMP( "^3!putteam: ^7invisible players cannot join a team\n" );
- return qfalse;
- }
-
- switch( team[ 0 ] )
- {
- case 'a':
- teamnum = PTE_ALIENS;
- Q_strncpyz( teamdesc, "aliens", sizeof( teamdesc ) );
- break;
- case 'h':
- teamnum = PTE_HUMANS;
- Q_strncpyz( teamdesc, "humans", sizeof( teamdesc ) );
- break;
- case 's':
- teamnum = PTE_NONE;
- break;
- default:
- ADMP( va( "^3!putteam: ^7unknown team %c\n", team[ 0 ] ) );
- return qfalse;
- }
- //duration code
- if( G_SayArgc() > 3 + skiparg ) {
- //can only lock players in spectator
- if ( teamnum != PTE_NONE )
- {
- ADMP( "^3!putteam: ^7You can only lock a player into the spectators team\n" );
- return qfalse;
- }
- G_SayArgv( 3 + skiparg, secs, sizeof( secs ) );
- seconds = G_admin_parse_time( secs );
- useDuration = qtrue;
- }
-
- if( vic->client->pers.teamSelection == teamnum && teamnum != PTE_NONE )
- {
- ADMP( va( "^3!putteam: ^7%s ^7is already on the %s team\n", vic->client->pers.netname, teamdesc ) );
- return qfalse;
- }
-
- if( useDuration == qtrue && seconds > 0 ) {
- vic->client->pers.specExpires = level.time + ( seconds * 1000 );
- }
- G_ChangeTeam( vic, teamnum );
-
- AP( va( "print \"^3!putteam: ^7%s^7 put %s^7 on to the %s team%s\n\"",
- ( ent ) ? G_admin_adminPrintName( ent ) : "console",
- vic->client->pers.netname, teamdesc,
- ( seconds ) ? va( " for %i seconds", seconds ) : "" ) );
- return qtrue;
-}
-
qboolean G_admin_seen(gentity_t *ent, int skiparg )
{
char name[ MAX_NAME_LENGTH ];
@@ -3362,11 +3278,8 @@ qboolean G_admin_seen(gentity_t *ent, int skiparg )
if( i == id || (search[ 0 ] && strstr( name, search ) ) )
{
- if ( vic->client->sess.invisible == qfalse )
- {
- ADMBP( va( "^3%4d ^7%s^7 is currently playing\n", i, vic->client->pers.netname ) );
- count++;
- }
+ ADMBP( va( "%4d %s^7 is currently playing\n", i, vic->client->pers.netname ) );
+ count++;
}
}
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] && count < 10; i++ )
@@ -3384,11 +3297,8 @@ qboolean G_admin_seen(gentity_t *ent, int skiparg )
if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid )
&& strstr( name, search ) )
{
- if ( vic->client->sess.invisible == qfalse )
- {
- ison = qtrue;
- break;
- }
+ ison = qtrue;
+ break;
}
}
@@ -3396,7 +3306,7 @@ qboolean G_admin_seen(gentity_t *ent, int skiparg )
{
if( id == -1 )
continue;
- ADMBP( va( "^3%4d ^7%s^7 is currently playing\n",
+ ADMBP( va( "%4d %s^7 is currently playing\n",
i + MAX_CLIENTS, g_admin_admins[ i ]->name ) );
}
else
@@ -3422,10 +3332,42 @@ qboolean G_admin_seen(gentity_t *ent, int skiparg )
return qtrue;
}
-void G_admin_seen_update( char *guid )
+void G_admin_karma_sync( void )
{
+ gclient_t *p;
+ int i, j;
+
+ if( !g_karma.integer )
+ return;
+
+ for( i = 0; i < level.maxclients; i++ )
+ {
+ p = &level.clients[ i ];
+
+ if( p->pers.connected != CON_CONNECTED &&
+ p->pers.connected != CON_CONNECTING )
+ continue;
+ if( p->pers.adminLevel < 1 )
+ continue;
+
+ for( j = 0; j < MAX_ADMIN_ADMINS && g_admin_admins[ j ]; j++ )
+ {
+ if( !Q_stricmp( g_admin_admins[ j ]->guid, p->pers.guid ) )
+ {
+ if( p->pers.karma )
+ g_admin_admins[ j ]->karma = p->pers.karma;
+ break;
+ }
+ }
+ }
+}
+
+void G_admin_seen_update( gclient_t *client, qboolean disconnect )
+{
+ char *guid;
int i;
+ guid = client->pers.guid;
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
{
if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
@@ -3433,11 +3375,198 @@ void G_admin_seen_update( char *guid )
qtime_t qt;
g_admin_admins[ i ]->seen = trap_RealTime( &qt );
+ if ( disconnect && client->pers.karma )
+ g_admin_admins[ i ]->karma = client->pers.karma;
return;
}
}
}
+typedef struct
+{
+ g_admin_admin_t *admin;
+ int id;
+}
+g_admin_sort_t;
+
+static int SortSeenTimes( const void *av, const void *bv)
+{
+ const g_admin_sort_t *a = av;
+ const g_admin_sort_t *b = bv;
+
+ if( !a->admin || !b->admin )
+ return 0;
+
+ if( a->admin->seen > b->admin->seen )
+ return 1;
+ if( a->admin->seen < b->admin->seen )
+ return -1;
+
+ return 0;
+}
+
+qboolean G_admin_expire( gentity_t *ent, int skiparg )
+{
+ g_admin_sort_t sort_list[ MAX_ADMIN_ADMINS ];
+ char arg[ MAX_ADMIN_CMD_LEN ];
+ qboolean confirm = qfalse;
+ qtime_t qt;
+ int t;
+ int count = 0;
+ int max = 5;
+ int i;
+
+ if( g_adminExpireTime.integer < 1 )
+ {
+ ADMP( "^3!expire: ^7expire is disabled\n" );
+ return qfalse;
+ }
+
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ G_SayArgv( skiparg + 1, arg, sizeof( arg ) );
+ if( !Q_stricmp( arg, "confirm" ) )
+ confirm = qtrue;
+ }
+
+ t = trap_RealTime( &qt );
+
+ memset( sort_list, 0, sizeof( sort_list ) );
+ for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
+ {
+ sort_list[ i ].admin = g_admin_admins[ i ];
+ sort_list[ i ].id = MAX_CLIENTS + i;
+ count++;
+ }
+
+ qsort( sort_list, count, sizeof( sort_list[ 0 ] ), SortSeenTimes );
+
+ ADMBP_begin();
+ for( i = 0; i < count && max > 0 ; i++ )
+ {
+ if( !sort_list[ i ].admin )
+ continue;
+ if( sort_list[ i ].admin->level != 1 )
+ continue;
+ if( t - sort_list[ i ].admin->seen > g_adminExpireTime.integer * 86400 )
+ {
+ char sduration[ 32 ];
+
+ max--;
+ G_admin_duration( t - sort_list[ i ].admin->seen, sduration, sizeof( sduration ) );
+
+ if( confirm )
+ {
+ trap_SendConsoleCommand( EXEC_APPEND, va( "!setlevel %d 0;", sort_list[ i ].id ) );
+ }
+ else
+ {
+ ADMBP( va( " ^7%d %s^7 last seen %s%s\n",
+ sort_list[ i ].id,
+ sort_list[ i ].admin->name,
+ (sort_list[ i ].admin->seen ) ? sduration : "",
+ (sort_list[ i ].admin->seen ) ? " ago" : "time is unknown" ) );
+ }
+ }
+ }
+
+ ADMBP( va( "^3!expire: ^7%s %d level 1 admin(s) older than %d days\n",
+ ( confirm ) ? "expired" : "listed",
+ 5 - max, g_adminExpireTime.integer ) );
+ if ( !confirm )
+ ADMBP( "^3!expire: ^7to make this permanent use '^2!expire confirm^7'\n" );
+
+ ADMBP_end();
+ return qtrue;
+}
+
+qboolean G_admin_putteam( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ];
+ char name[ MAX_NAME_LENGTH ], team[ 7 ], err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+ pTeam_t teamnum = PTE_NONE;
+ char teamdesc[ 32 ] = {"spectators"};
+ char secs[ 7 ];
+ int seconds = 0;
+ qboolean useDuration = qfalse;
+
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ G_SayArgv( 2 + skiparg, team, sizeof( team ) );
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!putteam: ^7usage: !putteam [name] [h|a|s] (duration)\n" );
+ return qfalse;
+ }
+
+ if( G_ClientNumbersFromString( name, pids ) != 1 )
+ {
+ G_MatchOnePlayer( pids, err, sizeof( err ) );
+ ADMP( va( "^3!putteam: ^7%s\n", err ) );
+ return qfalse;
+ }
+ if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ {
+ ADMP( "^3!putteam: ^7sorry, but your intended victim has a higher "
+ " admin level than you\n" );
+ return qfalse;
+ }
+ vic = &g_entities[ pids[ 0 ] ];
+
+ if ( vic->client->sess.invisible == qtrue )
+ {
+ ADMP( "^3!putteam: ^7invisible players cannot join a team\n" );
+ return qfalse;
+ }
+
+ switch( team[ 0 ] )
+ {
+ case 'a':
+ teamnum = PTE_ALIENS;
+ Q_strncpyz( teamdesc, "aliens", sizeof( teamdesc ) );
+ break;
+ case 'h':
+ teamnum = PTE_HUMANS;
+ Q_strncpyz( teamdesc, "humans", sizeof( teamdesc ) );
+ break;
+ case 's':
+ teamnum = PTE_NONE;
+ break;
+ default:
+ ADMP( va( "^3!putteam: ^7unknown team %c\n", team[ 0 ] ) );
+ return qfalse;
+ }
+ //duration code
+ if( G_SayArgc() > 3 + skiparg ) {
+ //can only lock players in spectator
+ if ( teamnum != PTE_NONE )
+ {
+ ADMP( "^3!putteam: ^7You can only lock a player into the spectators team\n" );
+ return qfalse;
+ }
+ G_SayArgv( 3 + skiparg, secs, sizeof( secs ) );
+ seconds = G_admin_parse_time( secs );
+ useDuration = qtrue;
+ }
+
+ if( vic->client->pers.teamSelection == teamnum && teamnum != PTE_NONE )
+ {
+ ADMP( va( "^3!putteam: ^7%s ^7is already on the %s team\n", vic->client->pers.netname, teamdesc ) );
+ return qfalse;
+ }
+
+ if( useDuration == qtrue && seconds > 0 ) {
+ vic->client->pers.specExpires = level.time + ( seconds * 1000 );
+ }
+ G_ChangeTeam( vic, teamnum );
+
+ AP( va( "print \"^3!putteam: ^7%s^7 put %s^7 on to the %s team%s\n\"",
+ ( ent ) ? G_admin_adminPrintName( ent ) : "console",
+ vic->client->pers.netname, teamdesc,
+ ( seconds ) ? va( " for %i seconds", seconds ) : "" ) );
+ return qtrue;
+}
+
void G_admin_adminlog_cleanup( void )
{
int i;
@@ -3469,7 +3598,6 @@ void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skipar
!Q_stricmp( command, "listplayers" ) ||
!Q_stricmp( command, "namelog" ) ||
!Q_stricmp( command, "showbans" ) ||
- !Q_stricmp( command, "seen" ) ||
!Q_stricmp( command, "time" ) )
return;
@@ -3722,6 +3850,261 @@ qboolean G_admin_adminlog( gentity_t *ent, int skiparg )
return qtrue;
}
+void G_admin_tklog_cleanup( void )
+{
+ int i;
+
+ for( i = 0; i < MAX_ADMIN_TKLOGS && g_admin_tklog[ i ]; i++ )
+ {
+ G_Free( g_admin_tklog[ i ] );
+ g_admin_tklog[ i ] = NULL;
+ }
+
+ admin_tklog_index = 0;
+}
+
+void G_admin_tklog_log( gentity_t *attacker, gentity_t *victim, int meansOfDeath )
+{
+ g_admin_tklog_t *tklog;
+ int previous;
+ int count = 1;
+
+ if( !attacker )
+ return;
+
+ previous = admin_tklog_index - 1;
+ if( previous < 0 )
+ previous = MAX_ADMIN_TKLOGS - 1;
+
+ if( g_admin_tklog[ previous ] )
+ count = g_admin_tklog[ previous ]->id + 1;
+
+ if( g_admin_tklog[ admin_tklog_index ] )
+ tklog = g_admin_tklog[ admin_tklog_index ];
+ else
+ tklog = G_Alloc( sizeof( g_admin_tklog_t ) );
+
+ memset( tklog, 0, sizeof( g_admin_tklog_t ) );
+ tklog->id = count;
+ tklog->time = level.time - level.startTime;
+ Q_strncpyz( tklog->name, attacker->client->pers.netname, sizeof( tklog->name ) );
+
+ if( victim )
+ {
+ Q_strncpyz( tklog->victim, victim->client->pers.netname, sizeof( tklog->victim ) );
+ tklog->damage = victim->client->tkcredits[ attacker->s.number ];
+ tklog->value = victim->client->ps.stats[ STAT_MAX_HEALTH ];
+ }
+ else
+ {
+ Q_strncpyz( tklog->victim, "^3BLEEDING", sizeof( tklog->victim ) );
+ tklog->damage = attacker->client->pers.statscounters.spreebleeds;
+ tklog->value = g_bleedingSpree.integer * 100;
+ }
+
+ tklog->team = attacker->client->ps.stats[ STAT_PTEAM ];
+ if( meansOfDeath == MOD_GRENADE )
+ tklog->weapon = WP_GRENADE;
+ else if( tklog->team == PTE_HUMANS )
+ tklog->weapon = attacker->s.weapon;
+ else
+ tklog->weapon = attacker->client->ps.stats[ STAT_PCLASS ];
+
+ g_admin_tklog[ admin_tklog_index ] = tklog;
+ admin_tklog_index++;
+ if( admin_tklog_index >= MAX_ADMIN_TKLOGS )
+ admin_tklog_index = 0;
+}
+
+qboolean G_admin_tklog( gentity_t *ent, int skiparg )
+{
+ g_admin_tklog_t *results[ 10 ];
+ int result_index = 0;
+ char *search_name = NULL;
+ int index;
+ int skip = 0;
+ int skipped = 0;
+ int checked = 0;
+ char n1[ MAX_NAME_LENGTH ];
+ char fmt_name[ 16 ];
+ char argbuf[ 32 ];
+ char *weaponName;
+ int name_length = 10;
+ int max_id = 0;
+ int i;
+ qboolean match;
+
+ memset( results, 0, sizeof( results ) );
+
+ index = admin_tklog_index;
+ for( i = 0; i < 10; i++ )
+ {
+ int prev;
+
+ prev = index - 1;
+ if( prev < 0 )
+ prev = MAX_ADMIN_TKLOGS - 1;
+ if( !g_admin_tklog[ prev ] )
+ break;
+ if( g_admin_tklog[ prev ]->id > max_id )
+ max_id = g_admin_tklog[ prev ]->id;
+ index = prev;
+ }
+
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, argbuf, sizeof( argbuf ) );
+ if( ( *argbuf >= '0' && *argbuf <= '9' ) || *argbuf == '-' )
+ {
+ int id;
+
+ id = atoi( argbuf );
+ if( id < 0 )
+ id += ( max_id - 9 );
+ else if( id <= max_id - MAX_ADMIN_TKLOGS )
+ id = max_id - MAX_ADMIN_TKLOGS + 1;
+
+ if( id + 9 >= max_id )
+ id = max_id - 9;
+ if( id < 1 )
+ id = 1;
+ for( i = 0; i < MAX_ADMIN_TKLOGS; i++ )
+ {
+ if( g_admin_tklog[ i ]->id == id )
+ {
+ index = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ search_name = argbuf;
+ }
+
+ if( G_SayArgc() > 2 + skiparg && ( search_name ) )
+ {
+ char skipbuf[ 4 ];
+ G_SayArgv( 2 + skiparg, skipbuf, sizeof( skipbuf ) );
+ skip = atoi( skipbuf );
+ }
+ }
+
+ if( search_name )
+ {
+ g_admin_tklog_t *result_swap[ 10 ];
+
+ memset( &result_swap, 0, sizeof( result_swap ) );
+
+ index = admin_tklog_index - 1;
+ if( index < 0 )
+ index = MAX_ADMIN_TKLOGS - 1;
+
+ while( g_admin_tklog[ index ] &&
+ checked < MAX_ADMIN_TKLOGS &&
+ result_index < 10 )
+ {
+ match = qfalse;
+
+ G_SanitiseString( g_admin_tklog[ index ]->name, n1, sizeof( n1 ) );
+ if( strstr( n1, search_name ) )
+ match = qtrue;
+
+ if( match && skip > 0 )
+ {
+ match = qfalse;
+ skip--;
+ skipped++;
+ }
+ if( match )
+ {
+ result_swap[ result_index ] = g_admin_tklog[ index ];
+ result_index++;
+ }
+
+ checked++;
+ index--;
+ if( index < 0 )
+ index = MAX_ADMIN_TKLOGS - 1;
+ }
+ // search runs backwards, turn it around
+ for( i = 0; i < result_index; i++ )
+ results[ i ] = result_swap[ result_index - i - 1 ];
+ }
+ else
+ {
+ while( g_admin_tklog[ index ] && result_index < 10 )
+ {
+ results[ result_index ] = g_admin_tklog[ index ];
+ result_index++;
+ index++;
+ if( index >= MAX_ADMIN_TKLOGS )
+ index = 0;
+ }
+ }
+
+ for( i = 0; results[ i ] && i < 10; i++ )
+ {
+ int l;
+
+ G_DecolorString( results[ i ]->name, n1 );
+ l = strlen( n1 );
+ if( l > name_length )
+ name_length = l;
+ }
+ ADMBP_begin( );
+ for( i = 0; results[ i ] && i < 10; i++ )
+ {
+ int t;
+
+ t = results[ i ]->time / 1000;
+
+ G_DecolorString( results[ i ]->name, n1 );
+ Com_sprintf( fmt_name, sizeof( fmt_name ), "%%%ds",
+ ( name_length + strlen( results[ i ]->name ) - strlen( n1 ) ) );
+ Com_sprintf( n1, sizeof( n1 ), fmt_name, results[ i ]->name );
+
+ if( results[ i ]->team == PTE_HUMANS )
+ weaponName = BG_FindNameForWeapon( results[ i ]->weapon );
+ else
+ weaponName = BG_FindNameForClassNum( results[ i ]->weapon );
+
+ ADMBP( va( "^7%3d %3d:%02d %s^7 %3d / %3d %10s %s^7\n",
+ results[ i ]->id,
+ t / 60, t % 60,
+ n1,
+ results[ i ]->damage,
+ results[ i ]->value,
+ weaponName,
+ results[ i ]->victim ) );
+ }
+ if( search_name )
+ {
+ ADMBP( va( "^3!tklog:^7 Showing %d matches for '%s^7'.",
+ result_index,
+ argbuf ) );
+ if( checked < MAX_ADMIN_TKLOGS && g_admin_tklog[ checked ] )
+ ADMBP( va( " run '!tklog %s^7 %d' to see more",
+ argbuf,
+ skipped + result_index ) );
+ ADMBP( "\n" );
+ }
+ else if ( results[ 0 ] )
+ {
+ ADMBP( va( "^3!tklog:^7 Showing %d - %d of %d.\n",
+ results[ 0 ]->id,
+ results[ result_index - 1 ]->id,
+ max_id ) );
+ }
+ else
+ {
+ ADMBP( "^3!tklog:^7 log is empty.\n" );
+ }
+ ADMBP_end( );
+
+ return qtrue;
+}
+
qboolean G_admin_map( gentity_t *ent, int skiparg )
{
char map[ MAX_QPATH ];
@@ -3947,6 +4330,9 @@ qboolean G_admin_maplog( gentity_t *ent, int skiparg )
case 'M':
result = "^6admin changed map";
break;
+ case 'l':
+ result = "^2layout vote";
+ break;
case 'D':
result = "^6admin loaded devmap";
break;
@@ -3986,6 +4372,10 @@ qboolean G_admin_maplog( gentity_t *ent, int skiparg )
ptr = end;
count++;
}
+
+ if( g_nextMap.string[ 0 ] )
+ ADMBP( va( "^5NextMap override: %s\n", g_nextMap.string ) );
+
ADMBP_end( );
return qtrue;
@@ -4013,7 +4403,7 @@ qboolean G_admin_demo( gentity_t *ent, int skiparg )
{
if( !ent )
{
- ADMP( "!demo: console can not use demo.\n" );
+ ADMP( "!demo: console can not use demo.\n");
return qfalse;
}
@@ -4415,29 +4805,34 @@ qboolean G_admin_listadmins( gentity_t *ent, int skiparg )
int start = 0;
qboolean numeric = qtrue;
int drawn = 0;
- int minlevel = 1;
+ int minlevel = 0;
+ char *direction = "(all levels)";
if( G_SayArgc() == 3 + skiparg )
{
G_SayArgv( 2 + skiparg, s, sizeof( s ) );
- if( s[ 0 ] >= '0' && s[ 0] <= '9' )
+ if( ( s[ 0 ] >= '0' && s[ 0] <= '9' ) || s[ 0 ] == '-' )
{
minlevel = atoi( s );
- if( minlevel < 1 )
- minlevel = 1;
+ if( minlevel > 0 )
+ direction = "or greater";
+ else if( minlevel < 0)
+ direction = "or lesser";
}
}
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
{
- if( g_admin_admins[ i ]->level >= minlevel )
+ if( ( minlevel == 0 && g_admin_admins[ i ]->level != 0 ) ||
+ ( minlevel > 0 && g_admin_admins[ i ]->level >= minlevel ) ||
+ ( minlevel < 0 && g_admin_admins[ i ]->level <= minlevel ) )
found++;
}
if( !found )
{
- if( minlevel > 1 )
+ if( minlevel != 0 )
{
- ADMP( va( "^3!listadmins: ^7no admins level %i or greater found\n", minlevel ) );
+ ADMP( va( "^3!listadmins: ^7no admins level %i %s found\n", minlevel, direction ) );
}
else
{
@@ -4476,27 +4871,28 @@ qboolean G_admin_listadmins( gentity_t *ent, int skiparg )
{
if( drawn <= 20 )
{
- ADMP( va( "^3!listadmins:^7 found %d admins level %i or greater matching '%s^7'\n",
- drawn, minlevel, search ) );
+ ADMP( va( "^3!listadmins:^7 found %d admins level %i %s matching '%s^7'\n",
+ drawn, minlevel, direction, search ) );
}
else
{
- ADMP( va( "^3!listadmins:^7 found >20 admins level %i or greater matching '%s^7. Try a more narrow search.'\n",
- minlevel, search ) );
+ ADMP( va( "^3!listadmins:^7 found >20 admins level %i %s matching '%s^7. Try a more narrow search.'\n",
+ minlevel, direction, search ) );
}
}
else
{
ADMBP_begin();
- ADMBP( va( "^3!listadmins:^7 showing admins level %i or greater %d - %d of %d. ",
+ ADMBP( va( "^3!listadmins:^7 showing admins level %i %s %d - %d of %d. ",
minlevel,
+ direction,
( found ) ? ( start + 1 ) : 0,
( ( start + MAX_ADMIN_LISTITEMS ) > found ) ?
found : ( start + MAX_ADMIN_LISTITEMS ),
found ) );
if( ( start + MAX_ADMIN_LISTITEMS ) < found )
{
- if( minlevel > 1)
+ if( minlevel != 0 )
{
ADMBP( va( "run '!listadmins %d %d' to see more",
( start + MAX_ADMIN_LISTITEMS + 1 ), minlevel ) );
@@ -4564,27 +4960,29 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
char lname[ MAX_NAME_LENGTH ];
char lname2[ MAX_NAME_LENGTH ];
char guid_stub[ 9 ];
- char muted[ 2 ], denied[ 2 ], dbuilder[ 2 ], misc[ 2 ];
+ char muted[ 2 ], denied[ 2 ], dbuilder[ 2 ], immune[ 2 ];
int l;
char lname_fmt[ 5 ];
+ char karma[ 8 ];
+ //get amount of invisible players
for( i = 0; i < level.maxclients; i++ ) {
p = &level.clients[ i ];
if ( p->sess.invisible == qtrue )
invisiblePlayers++;
}
-
+
ADMBP_begin();
- ADMBP( va( "^3!listplayers^7: %i players connected:\n",
+ ADMBP( va( "^3!listplayers^7: %d players connected:\n",
level.numConnectedClients - invisiblePlayers ) );
for( i = 0; i < level.maxclients; i++ )
{
p = &level.clients[ i ];
-
+
// Ignore invisible players
if ( p->sess.invisible == qtrue )
continue;
-
+
Q_strncpyz( t, "S", sizeof( t ) );
Q_strncpyz( c, S_COLOR_YELLOW, sizeof( c ) );
if( p->pers.teamSelection == PTE_HUMANS )
@@ -4613,6 +5011,10 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
guid_stub[ j ] = '\0';
muted[ 0 ] = '\0';
+ if( G_admin_permission( &g_entities[ i ], ADMF_NO_VOTE ) )
+ {
+ Q_strncpyz( muted, "V", sizeof( muted ) );
+ }
if( p->pers.muted )
{
Q_strncpyz( muted, "M", sizeof( muted ) );
@@ -4641,15 +5043,16 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
Q_strncpyz( dbuilder, "D", sizeof( dbuilder ) );
}
}
-
- misc[ 0 ] = '\0';
+ immune[ 0 ] = '\0';
if( G_admin_permission( &g_entities[ i ], ADMF_BAN_IMMUNITY ) )
{
- // use Misc slot for Immunity player status
- Q_strncpyz( misc, "I", sizeof( misc ) );
- } else if( p->pers.paused ) {
- // use Misc slot for paused player status
- Q_strncpyz( misc, "P", sizeof( misc ) );
+ Q_strncpyz( immune, "I", sizeof( immune ) );
+ }
+
+ if( p->pers.paused )
+ {
+ // use immunity slot for paused player status
+ Q_strncpyz( immune, "L", sizeof( immune ) );
}
l = 0;
@@ -4693,19 +5096,25 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
}
+ if( g_karma.integer )
+ Com_sprintf( karma, sizeof( karma ), " %4i", p->pers.karma / 1000 );
+ else
+ karma[ 0 ] = '\0';
+
if( G_admin_permission(ent, ADMF_SEESFULLLISTPLAYERS ) ) {
- ADMBP( va( "%2i %s%s^7 %-2i %s^7 (*%s) ^1%1s%1s%1s%1s^7 %s^7 %s%s^7%s\n",
+ ADMBP( va( "%2i %s%s^7%s %-2i %s^7 (*%s) ^1%1s%1s%1s%1s^7 %s^7 %s%s^7%s\n",
i,
c,
t,
+ karma,
l,
( *lname ) ? lname2 : "",
guid_stub,
+ immune,
muted,
dbuilder,
denied,
- misc,
p->pers.netname,
( *n ) ? "(a.k.a. " : "",
n,
@@ -4714,10 +5123,11 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg )
}
else
{
- ADMBP( va( "%2i %s%s^7 ^1%1s%1s%1s^7 %s^7\n",
+ ADMBP( va( "%2i %s%s^7%s ^1%1s%1s%1s^7 %s^7\n",
i,
c,
t,
+ karma,
muted,
dbuilder,
denied,
@@ -4870,52 +5280,6 @@ qboolean G_admin_listrotation( gentity_t *ent, int skiparg )
statusColor = 7;
status = "vote";
}
- } else if( !Q_stricmp( mapRotations.rotations[ i ].maps[ j ].name, "*RANDOM*" ) )
- {
- char slotMap[ 64 ];
- int lineLen = 0;
- int k;
-
- trap_Cvar_VariableStringBuffer( "mapname", slotMap, sizeof( slotMap ) );
- mapnames[ 0 ] = '\0';
- for( k = 0; k < mapRotations.rotations[ i ].maps[ j ].numConditions; k++ )
- {
- char *thisMap;
- int mc = 7;
-
- if( mapRotations.rotations[ i ].maps[ j ].conditions[ k ].lhs != MCV_SELECTEDRANDOM )
- continue;
-
- thisMap = mapRotations.rotations[ i ].maps[ j ].conditions[ k ].dest;
- lineLen += strlen( thisMap ) + 1;
-
- if( currentMap == j && !Q_stricmp( thisMap, slotMap ) )
- mc = 3;
- Q_strcat( mapnames, sizeof( mapnames ), va( "^7%s%s^%i%s",
- ( k ) ? ", " : "",
- ( lineLen > 50 ) ? "\n " : "",
- mc, thisMap ) );
- if( lineLen > 50 )
- lineLen = strlen( thisMap ) + 2;
- else
- lineLen++;
- }
-
- if( currentMap == j )
- {
- statusColor = 3;
- status = "current slot";
- }
- else if( !k )
- {
- statusColor = 1;
- status = "empty Random";
- }
- else
- {
- statusColor = 7;
- status = "Random";
- }
}
else if ( currentMap == j )
{
@@ -4980,16 +5344,13 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
char name_match[ MAX_NAME_LENGTH ] = {""};
int show_count = 0;
qboolean subnetfilter = qfalse;
+ int line_color;
+ int dummy;
t = trap_RealTime( NULL );
for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
{
- if( g_admin_bans[ i ]->expires != 0
- && ( g_admin_bans[ i ]->expires - t ) < 1 )
- {
- continue;
- }
found++;
}
@@ -5067,7 +5428,6 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
else
{
int mask = -1;
- int dummy;
int scanflen = 0;
scanflen = sscanf( g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &dummy, &dummy, &dummy, &dummy, &mask );
if( scanflen == 5 && mask < 32 )
@@ -5114,7 +5474,6 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
else
{
int mask = -1;
- int dummy;
int scanflen = 0;
scanflen = sscanf( g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &dummy, &dummy, &dummy, &dummy, &mask );
if( scanflen != 5 || mask >= 32 )
@@ -5141,42 +5500,54 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
made++;
}
- if( g_admin_bans[ i ]->expires != 0
- && ( g_admin_bans[ i ]->expires - t ) < 1 )
+ if( g_admin_bans[ i ]->expires == 0 ||
+ g_admin_bans[ i ]->expires > t )
{
- Com_sprintf( duration, sizeof( duration ), "^1*EXPIRED*^7" );
- } else {
secs = ( g_admin_bans[ i ]->expires - t );
G_admin_duration( secs, duration, sizeof( duration ) );
+ if( sscanf( g_admin_bans[ i ]->ip, "%d.%d.%d.%d/%d", &dummy, &dummy, &dummy, &dummy, &dummy ) != 4 )
+ line_color = 1;
+ else if( g_admin_bans[ i ]->suspend > t )
+ line_color = 5;
+ else
+ line_color = 7;
+ }
+ else
+ {
+ Q_strncpyz( duration, "expired", sizeof( duration ) );
+ line_color = 5;
}
suspended[ 0 ] = '\0';
if( g_admin_bans[ i ]->suspend > t )
{
G_admin_duration( g_admin_bans[ i ]->suspend - t, sduration, sizeof( sduration ) );
- Com_sprintf( suspended, sizeof( suspended ), "^3*SUSPENDED*^7 for %s^7",
+ Com_sprintf( suspended, sizeof( suspended ), "^5 | - SUSPENDED for %s\n",
sduration );
}
G_DecolorString( g_admin_bans[ i ]->name, n1 );
- Com_sprintf( name_fmt, sizeof( name_fmt ), "%%%is",
+ Com_sprintf( name_fmt, sizeof( name_fmt ), "%%-%is",
( max_name + strlen( g_admin_bans[ i ]->name ) - strlen( n1 ) ) );
Com_sprintf( n1, sizeof( n1 ), name_fmt, g_admin_bans[ i ]->name );
G_DecolorString( g_admin_bans[ i ]->banner, n2 );
- Com_sprintf( banner_fmt, sizeof( banner_fmt ), "%%%is",
+ Com_sprintf( banner_fmt, sizeof( banner_fmt ), "%%-%is",
( max_banner + strlen( g_admin_bans[ i ]->banner ) - strlen( n2 ) ) );
- Com_sprintf( n2, sizeof( n2 ), banner_fmt, g_admin_bans[ i ]->banner );
+ Com_sprintf( n2, sizeof( n2 ), banner_fmt, g_admin_bans[ i ]->banner );
bannerslevel = g_admin_bans[ i ]->bannerlevel;
- ADMBP( va( "%4i %s^7 %-15s %-8s %-10s\n | %-15s^7 Level:%2i\n | %s\n \\__ %s\n",
+ ADMBP( va( "^%i%4i ^7%s^%i %-15s %-8s ^7%s^7 %2i^%i %-10s\n%s^5 \\__ %s\n",
+ line_color,
( i + 1 ),
n1,
+ line_color,
g_admin_bans[ i ]->ip,
date,
- duration,
n2,
bannerslevel,
+ line_color,
+ duration,
suspended,
g_admin_bans[ i ]->reason ) );
@@ -5209,8 +5580,9 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
if( ( start + MAX_ADMIN_SHOWBANS ) < found )
{
- ADMBP( va( "run !showbans %d %s to see more",
+ ADMBP( va( "run !showbans %d%s%s to see more",
( start + MAX_ADMIN_SHOWBANS + 1 ),
+ (filter[0]) ? " " : "",
(filter[0]) ? filter : "" ) );
}
ADMBP( "\n" );
@@ -5221,8 +5593,7 @@ qboolean G_admin_showbans( gentity_t *ent, int skiparg )
qboolean G_admin_help( gentity_t *ent, int skiparg )
{
int i;
- int count = 0;
- int commandsPerLine = 6;
+ char additional[ MAX_STRING_CHARS ] = "";
if( G_SayArgc() < 2 + skiparg )
{
@@ -5259,102 +5630,39 @@ qboolean G_admin_help( gentity_t *ent, int skiparg )
j = 0;
}
}
-
+
+ if( ent && g_markDeconstruct.integer == 2 )
+ strcat( additional, " /mark" );
+ if( ent )
+ strcat( additional, " /builder /say_area" );
+ if( g_publicSayadmins.integer || G_admin_permission( ent, ADMF_ADMINCHAT ) )
+ strcat( additional, " /a /say_admins" );
+ if( g_privateMessages.integer )
+ strcat( additional, " /m" );
+ if( ent && g_actionPrefix.string[0] )
+ strcat( additional, " /me /mt /me_team" );
+ if( ent && g_myStats.integer )
+ strcat( additional, " /mystats" );
+ if( ent && g_teamStatus.integer )
+ strcat( additional, " /teamstatus" );
+ if( ent && ent->client )
+ {
+ if( ent->client->pers.designatedBuilder )
+ {
+ strcat( additional, " /protect /resign" );
+ }
+ }
+ if( ent && g_allowShare.integer )
+ strcat( additional, " /share /donate" );
+
if( count )
ADMBP( "\n" );
ADMBP( va( "^3!help: ^7%i available commands\n", count ) );
ADMBP( "run !help [^3command^7] for help with a specific command.\n" );
- ADMBP( "The following non-standard /commands may also be available to you: \n" );
- count = 1;
-
- if( ent && g_AllStats.integer ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "allstats" ) );
- count++;
- }
- if ( ent ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "builder" ) );
- count++;
- }
- if( ent && g_allowVote.integer && G_admin_permission( ent, ADMF_NO_VOTE ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "callvote" ) );
- count++;
- }
- if( ent && g_allowVote.integer && G_admin_permission( ent, ADMF_NO_VOTE ) && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "callteamvote" ) );
- count++;
- }
- if( ent && g_allowShare.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "donate" ) );
- count++;
- }
- if( g_privateMessages.integer ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "m" ) );
- count++;
- }
- if( ent && g_markDeconstruct.integer == 2 && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mark" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "me" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "me_team" ) );
- count++;
- }
- if( ent && g_actionPrefix.string[0] && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mt" ) );
- count++;
- }
- if( ent && g_myStats.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "mystats" ) );
- count++;
- }
- if( ent->client->pers.designatedBuilder && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "protect" ) );
- count++;
- }
- if( ent->client->pers.designatedBuilder && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "resign" ) );
- count++;
- }
- if( g_publicSayadmins.integer || G_admin_permission( ent, ADMF_ADMINCHAT ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "say_admins" ) );
- count++;
- }
- if( ent && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "say_area" ) );
- count++;
- }
- if( ent && g_allowShare.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "share" ) );
- count++;
- }
- if( ent && g_teamStatus.integer && ( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS || ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) {
- if( count > commandsPerLine && ( count % commandsPerLine ) == 1 ) ADMBP( "\n" );
- ADMBP( va( "^5/%-12s", "teamstatus" ) );
- count++;
- }
- ADMBP( "\n" );
+ ADMBP( va( "\nThe following non-standard /commands may also be available to you: \n^3%s\n",
+ additional ) );
ADMBP_end();
-
+
return qtrue;
}
else
@@ -5490,6 +5798,10 @@ qboolean G_admin_cancelvote( gentity_t *ent, int skiparg )
ADMP( "^3!cancelvote^7: no vote in progress\n" );
return qfalse;
}
+ if( !Q_strncmp( level.voteDisplayString, "Extend", 6 ) &&
+ level.extend_vote_count > 0 )
+ level.extend_vote_count--;
+
level.voteNo = level.numConnectedClients;
level.voteYes = 0;
CheckVote( );
@@ -5679,11 +5991,81 @@ qboolean G_admin_pause( gentity_t *ent, int skiparg )
vic->client->pers.netname,
( ent ) ? ent->client->pers.netname : "console" ) );
}
- ClientUserinfoChanged( pids[ i ], qfalse );
}
return qtrue;
}
+qboolean G_admin_practice( gentity_t *ent, int skiparg )
+{
+ char clantag[ MAX_NAME_LENGTH ];
+ char mapsarg[ 8 ];
+ int maps;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ if( g_practiceCount.integer )
+ {
+ AP( va( "print \"^3practice:^7 practice mode is in effect for the next %d maps\n\"",
+ g_practiceCount.integer ) );
+ ADMP( va( "^3!practice: ^7practice mode set to %s^7 for next %d maps\n",
+ g_practiceText.string, g_practiceCount.integer ) );
+ }
+ else
+ {
+ ADMP( "^3!practice: ^7practice mode is off\n" );
+ }
+ return qfalse;
+ }
+
+ G_SayArgv( 1 + skiparg, clantag, sizeof( clantag ) );
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ if( !Q_stricmp( clantag, "off" ) )
+ {
+ if( g_practiceCount.integer )
+ {
+ trap_Cvar_Set( "g_practiceCount", "0" );
+ AP( va ("print \"^3!practice: ^7 practice mode turned off by %s^7\n\"",
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ ADMP( "^3!practice: ^7practice mode set to off\n" );
+ return qtrue;
+ }
+ else
+ {
+ ADMP( "^3!practice: ^7practice mode already off\n" );
+ }
+ }
+ else
+ {
+ ADMP( "^3!practice: ^7usage: practice [clan tag] [map count]\n" );
+ }
+ return qfalse;
+ }
+ G_SayArgv( 2 + skiparg, mapsarg, sizeof( mapsarg ) );
+ maps = atoi( mapsarg );
+
+ if( !clantag[ 0 ] )
+ {
+ ADMP( "^3!practice: ^7no clan tag specified\n" );
+ return qfalse;
+ }
+ if( maps < 1 || maps > 8 )
+ {
+ ADMP( "^3!practice: ^7map count must be between 1 and 8\n" );
+ return qfalse;
+ }
+
+ trap_Cvar_Set( "g_practiceText", clantag );
+ trap_Cvar_Set( "g_practiceCount", va( "%d", maps ) );
+
+ AP( va( "print \"^3practice:^7 %s^7 has activated practice mode for the next %d maps\n\"",
+ ( ent ) ? ent->client->pers.netname : "console",
+ maps ) );
+
+ return qtrue;
+}
+
qboolean G_admin_spec999( gentity_t *ent, int skiparg )
{
int i;
@@ -5711,13 +6093,47 @@ qboolean G_admin_spec999( gentity_t *ent, int skiparg )
qboolean G_admin_register(gentity_t *ent, int skiparg ){
int level = 0;
+ int max;
+ char buffer [ 64 ];
if( !ent ) return qtrue;
level = G_admin_level(ent);
- if( level == 0 )
- level = 1;
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ G_SayArgv( 1 + skiparg, buffer, sizeof( buffer ) );
+ max = atoi( buffer );
+
+ if( G_SayArgc() > 2 + skiparg )
+ {
+ G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
+ if( g_adminRegisterAdminPass.string[ 0 ] && Q_stricmp( g_adminRegisterAdminPass.string, "none" ) &&
+ Q_stricmp( g_adminRegisterAdminPass.string, buffer) )
+ {
+ ADMP( "Invalid password.\n" );
+ return qfalse;
+ }
+ if (max > g_adminRegisterAdminLevel.integer)
+ max = g_adminRegisterAdminLevel.integer;
+ if( level <= g_adminRegisterAdminLevel.integer )
+ level = max;
+ }
+ else
+ {
+ if( max > g_adminRegisterLevel.integer )
+ max = g_adminRegisterLevel.integer;
+ if( max >= 0 && level >= 0 && level <= g_adminRegisterLevel.integer )
+ level = max;
+ }
+ }
+ else
+ {
+ max = 1;
+ }
+
+ if( level >= 0 && level < max )
+ level = max;
if( !Q_stricmp( ent->client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) )
{
@@ -5886,140 +6302,6 @@ qboolean G_admin_restart( gentity_t *ent, int skiparg )
return qtrue;
}
-qboolean G_admin_nobuild( gentity_t *ent, int skiparg )
-{
- char buffer[ MAX_STRING_CHARS ];
- int i, tmp;
-
- if( G_SayArgc() < 2 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild (^5enable / disable / log / remove / save^7)\n" );
- return qfalse;
- }
-
- G_SayArgv( 1 + skiparg, buffer, sizeof( buffer ) );
-
- if( !Q_stricmp( buffer, "enable" ) || !Q_stricmp( buffer, "Enable" ) )
- {
- if( G_SayArgc() < 4 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild enable (^5area^7) (^5height^7)\n" );
- return qfalse;
- }
-
- if( !level.noBuilding )
- {
-
- level.noBuilding = qtrue;
-
- // Grab and set the area
- G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer );
- level.nbArea = tmp;
-
- // Grab and set the height
- G_SayArgv( 3 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer );
- level.nbHeight = tmp;
-
- ADMP( "^3!nobuild: ^7nobuild is now enabled, please place a buildable to spawn a marker\n" );
- return qtrue;
- }
- else
- {
- ADMP( "^3!nobuild: ^7nobuild is already enabled. type !nobuild disable to disable nobuild mode.\n" );
- return qfalse;
- }
- }
-
- if( !Q_stricmp( buffer, "disable" ) || !Q_stricmp( buffer, "Disable" ) )
- {
- if( level.noBuilding )
- {
- level.noBuilding = qfalse;
- level.nbArea = 0.0f;
- level.nbHeight = 0.0f;
- ADMP( "^3!nobuild: ^7nobuild is now disabled\n" );
- return qtrue;
- }
- else
- {
- ADMP( "^3!nobuild: ^7nobuild is disabled. type !nobuild enable (^5area^7) (^5height^7) to enable nobuild mode.\n" );
- return qfalse;
- }
- }
-
- if( !Q_stricmp( buffer, "log" ) || !Q_stricmp( buffer, "Log" ) )
- {
- ADMBP_begin();
-
- tmp = 0;
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker == NULL )
- continue;
-
- // This will display a start at 1, and not 0. This is to stop confusion by server ops
- ADMBP( va( "^7#%i at origin (^5%f %f %f^7)^7\n", i + 1, level.nbMarkers[ i ].Origin[0], level.nbMarkers[ i ].Origin[1], level.nbMarkers[ i ].Origin[2] ) );
- tmp++;
- }
- ADMBP( va( "^3!nobuild:^7 displaying %i marker(s)\n", tmp ) );
-
- ADMBP_end();
- return qtrue;
- }
-
- if( !Q_stricmp( buffer, "remove" ) || !Q_stricmp( buffer, "Remove" ) )
- {
- if( G_SayArgc() < 3 + skiparg )
- {
- ADMP( "^3!nobuild: ^7usage: !nobuild remove (^5marker #^7)\n" );
- return qfalse;
- }
-
- G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) );
- tmp = atoi( buffer ) - 1;
- // ^ that was to work with the display number...
-
- if( level.nbMarkers[ tmp ].Marker == NULL )
- {
- ADMP( "^3!nobuild: ^7that is not a valid marker number\n" );
- return qfalse;
- }
- // Donno why im doing this, but lets clear this...
- level.nbMarkers[ tmp ].Marker->noBuild.isNB = qfalse;
- level.nbMarkers[ tmp ].Marker->noBuild.Area = 0.0f;
- level.nbMarkers[ tmp ].Marker->noBuild.Height = 0.0f;
-
- // Free the entitiy and null it out...
- G_FreeEntity( level.nbMarkers[ tmp ].Marker );
- level.nbMarkers[ tmp ].Marker = NULL;
-
- // That is to work with the display number...
- ADMP( va( "^3!nobuild:^7 marker %i has been removed\n", tmp + 1 ) );
- return qtrue;
- }
-
- if( !Q_stricmp( buffer, "save" ) || !Q_stricmp( buffer, "Save" ) )
- {
- int i, tmp;
-
- G_NobuildSave( );
-
- tmp = 0;
- for( i = 0; i < MAX_GENTITIES; i++ )
- {
- if( level.nbMarkers[ i ].Marker == NULL )
- continue;
-
- tmp++;
- }
- ADMP( va( "^3!nobuild:^7 %i nobuild markers have been saved\n", tmp ) );
- return qtrue;
- }
- return qfalse;
-}
-
qboolean G_admin_nextmap( gentity_t *ent, int skiparg )
{
AP( va( "print \"^3!nextmap: ^7%s^7 decided to load the next map\n\"",
@@ -6244,6 +6526,441 @@ qboolean G_admin_designate( gentity_t *ent, int skiparg )
return qtrue;
}
+static int SortFlags( const void *pa, const void *pb )
+{
+ char *a = (char *)pa;
+ char *b = (char *)pb;
+
+ if( *a == '-' || *a == '+' )
+ a++;
+ if( *b == '-' || *b == '+' )
+ b++;
+ return strcmp(a, b);
+}
+
+#define MAX_USER_FLAGS 200
+const char *G_admin_user_flag( char *oldflags, char *flag, qboolean add, qboolean clear,
+ char *newflags, int size )
+{
+ char *token, *token_p;
+ char *key;
+ char head_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
+ char tail_flags[ MAX_USER_FLAGS ][ MAX_ADMIN_FLAG_LEN ];
+ char allflag[ MAX_ADMIN_FLAG_LEN ];
+ char newflag[ MAX_ADMIN_FLAG_LEN ];
+ int head_count = 0;
+ int tail_count = 0;
+ qboolean flagset = qfalse;
+ int i;
+
+ if( !flag[ 0 ] )
+ {
+ return "invalid admin flag";
+ }
+
+ allflag[ 0 ] = '\0';
+ token_p = oldflags;
+ while( *( token = COM_Parse( &token_p ) ) )
+ {
+ key = token;
+ if( *key == '-' || *key == '+' )
+ key++;
+
+ if( !strcmp( key, flag ) )
+ {
+ if( flagset )
+ continue;
+ flagset = qtrue;
+ if( clear )
+ {
+ // clearing ALLFlAGS will result in clearing any following flags
+ if( !strcmp( key, ADMF_ALLFLAGS ) )
+ break;
+ else
+ continue;
+ }
+ Com_sprintf( newflag, sizeof( newflag ), "%s%s",
+ ( add ) ? "+" : "-", key );
+ }
+ else
+ {
+ Q_strncpyz( newflag, token, sizeof( newflag ) );
+ }
+
+ if( !strcmp( key, ADMF_ALLFLAGS ) )
+ {
+ if( !allflag[ 0 ] )
+ Q_strncpyz( allflag, newflag, sizeof( allflag ) );
+ continue;
+ }
+
+ if( !allflag[ 0 ] )
+ {
+ if( head_count < MAX_USER_FLAGS )
+ {
+ Q_strncpyz( head_flags[ head_count ], newflag,
+ sizeof( head_flags[ head_count ] ) );
+ head_count++;
+ }
+ }
+ else
+ {
+ if( tail_count < MAX_USER_FLAGS )
+ {
+ Q_strncpyz( tail_flags[ tail_count ], newflag,
+ sizeof( tail_flags[ tail_count ] ) );
+ tail_count++;
+ }
+ }
+ }
+
+ if( !flagset && !clear )
+ {
+ if( !strcmp( flag, ADMF_ALLFLAGS ) )
+ {
+ Com_sprintf( allflag, sizeof( allflag ), "%s%s",
+ ( add ) ? "" : "-", ADMF_ALLFLAGS );
+ }
+ else if( !allflag[ 0 ] )
+ {
+ if( head_count < MAX_USER_FLAGS )
+ {
+ Com_sprintf( head_flags[ head_count ], sizeof( head_flags[ head_count ] ),
+ "%s%s", ( add ) ? "" : "-", flag );
+ head_count++;
+ }
+ }
+ else
+ {
+ if( tail_count < MAX_USER_FLAGS )
+ {
+ Com_sprintf( tail_flags[ tail_count ], sizeof( tail_flags[ tail_count ] ),
+ "%s%s", ( add ) ? "+" : "-", flag );
+ tail_count++;
+ }
+ }
+ }
+
+ qsort( head_flags, head_count, sizeof( head_flags[ 0 ] ), SortFlags );
+ qsort( tail_flags, tail_count, sizeof( tail_flags[ 0 ] ), SortFlags );
+
+ // rebuild flags
+ newflags[ 0 ] = '\0';
+ for( i = 0; i < head_count; i++ )
+ {
+ Q_strcat( newflags, size,
+ va( "%s%s", ( i ) ? " ": "", head_flags[ i ] ) );
+ }
+ if( allflag[ 0 ] )
+ {
+ Q_strcat( newflags, size,
+ va( "%s%s", ( newflags[ 0 ] ) ? " ": "", allflag ) );
+
+ for( i = 0; i < tail_count; i++ )
+ {
+ Q_strcat( newflags, size,
+ va( " %s", tail_flags[ i ] ) );
+ }
+ }
+
+ return NULL;
+}
+
+
+typedef struct {
+ char *flag;
+ char *description;
+} AdminFlagListEntry_t;
+static AdminFlagListEntry_t adminFlagList[] =
+{
+ { ADMF_ACTIVITY, "inactivity rules do not apply" },
+ { ADMF_ADMINCHAT, "can see and use admin chat" },
+ { ADMF_ALLFLAGS, "has all flags and can use any command" },
+ { ADMF_BAN_IMMUNITY, "immune from IP bans" },
+ { ADMF_CAN_PERM_BAN, "can permanently ban players" },
+ { ADMF_DBUILDER, "permanent designated builder" },
+ { ADMF_FORCETEAMCHANGE, "team balance rules do not apply" },
+ { ADMF_INCOGNITO, "does not show as admin in !listplayers" },
+ { ADMF_IMMUNITY, "cannot be vote kicked or muted" },
+ { ADMF_IMMUTABLE, "admin commands cannot be used on them" },
+ { ADMF_NOCENSORFLOOD, "no flood protection" },
+ { ADMF_NO_VOTE_LIMIT, "vote limitations do not apply" },
+ { ADMF_SEESFULLLISTPLAYERS, "sees all info in !listplayers" },
+ { ADMF_SPEC_ALLCHAT, "can see team chat as spectator" },
+ { ADMF_ADMINSTEALTH, "uses admin stealth" },
+ { ADMF_TEAMCHANGEFREE, "keeps credits on team switch" },
+ { ADMF_TEAMCHAT_CMD, "can run commands from team chat" },
+ { ADMF_UNACCOUNTABLE, "does not need to specify reason for kick/ban" },
+ { ADMF_NO_CHAT, "can not talk" },
+ { ADMF_NO_VOTE, "can not call votes" }
+};
+static int adminNumFlags= sizeof( adminFlagList ) / sizeof( adminFlagList[ 0 ] );
+
+#define MAX_LISTCOMMANDS 128
+qboolean G_admin_flaglist( gentity_t *ent, int skiparg )
+{
+ qboolean shown[ MAX_LISTCOMMANDS ];
+ int i, j;
+ int count = 0;
+
+ ADMBP_begin();
+
+ ADMBP( "^3Ability flags:\n" );
+
+ for( i = 0; i < adminNumFlags; i++ )
+ {
+ ADMBP( va( " %s%-20s ^7%s\n",
+ ( adminFlagList[ i ].flag[ 0 ] != '.' ) ? "^5" : "^1",
+ adminFlagList[ i ].flag,
+ adminFlagList[ i ].description ) );
+ }
+
+ ADMBP( "^3Command flags:\n" );
+
+ memset( shown, 0, sizeof( shown ) );
+ for( i = 0; i < adminNumCmds; i++ )
+ {
+ if( i < MAX_LISTCOMMANDS && shown[ i ] )
+ continue;
+ ADMBP( va( " ^5%-20s^7", g_admin_cmds[ i ].flag ) );
+ for( j = i; j < adminNumCmds; j++ )
+ {
+ if( !strcmp( g_admin_cmds[ j ].flag, g_admin_cmds[ i ].flag ) )
+ {
+ ADMBP( va( " %s", g_admin_cmds[ j ].keyword ) );
+ if( j < MAX_LISTCOMMANDS )
+ shown[ j ] = qtrue;
+ }
+ }
+ ADMBP( "\n" );
+ count++;
+ }
+
+ ADMBP( va( "^3!flaglist: ^7listed %d abilities and %d command flags\n",
+ adminNumFlags, count ) );
+
+ ADMBP_end();
+
+ return qtrue;
+}
+
+qboolean G_admin_flag( gentity_t *ent, int skiparg )
+{
+ char command[ MAX_ADMIN_CMD_LEN ], *cmd;
+ char name[ MAX_NAME_LENGTH ];
+ char flagbuf[ MAX_ADMIN_FLAG_LEN ];
+ char *flag;
+ int id;
+ char adminname[ MAX_NAME_LENGTH ] = {""};
+ const char *result;
+ qboolean add = qtrue;
+ qboolean clear = qfalse;
+ int admin_level = -1;
+ int i, level;
+
+ G_SayArgv( skiparg, command, sizeof( command ) );
+ cmd = command;
+ if( *cmd == '!' )
+ cmd++;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( va( "^3!%s: ^7usage: !%s slot# flag\n", cmd, cmd ) );
+ return qfalse;
+ }
+
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( name[ 0 ] == '*' )
+ {
+ if( ent )
+ {
+ ADMP( va( "^3!%s: only console can change admin level flags\n", cmd ) );
+ return qfalse;
+ }
+ id = atoi( name + 1 );
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ if( g_admin_levels[ i ]->level == id )
+ {
+ admin_level = i;
+ break;
+ }
+ }
+ if( admin_level < 0 )
+ {
+ ADMP( va( "^3!%s: admin level %d does not exist\n", cmd, id ) );
+ return qfalse;
+ }
+ Com_sprintf( adminname, sizeof( adminname ), "admin level %d", id );
+ }
+ else
+ {
+ id = G_admin_find_admin_slot( ent, name, cmd, adminname, sizeof( adminname ) );
+ if( id < 0 )
+ return qfalse;
+
+ if( ent && !admin_higher_guid( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
+ {
+ ADMP( va( "^3%s:^7 your intended victim has a higher admin level than you\n", cmd ) );
+ return qfalse;
+ }
+ }
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ flag = "";
+ level = 0;
+ if( admin_level < 0 )
+ {
+ for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ )
+ {
+ if( g_admin_admins[ id ]->level == g_admin_levels[ i ]->level )
+ {
+ flag = g_admin_levels[ i ]->flags;
+ level = g_admin_admins[ id ]->level;
+ break;
+ }
+ }
+ ADMP( va( "^3%s:^7 flags for %s^7 are '^3%s^7'\n",
+ cmd, adminname, g_admin_admins[ id ]->flags) );
+ }
+ else
+ {
+ flag = g_admin_levels[ admin_level ]->flags;
+ level = g_admin_levels[ admin_level ]->level;
+ }
+ ADMP( va( "^3%s:^7 level %d flags are '%s'\n",
+ cmd, level, flag ) );
+
+ return qtrue;
+ }
+
+ G_SayArgv( 2 + skiparg, flagbuf, sizeof( flagbuf ) );
+ flag = flagbuf;
+ if( flag[ 0 ] == '-' || flag[ 0 ] == '+' )
+ {
+ add = ( flag[ 0 ] == '+' );
+ flag++;
+ }
+ if( ent && !Q_stricmp( ent->client->pers.guid, g_admin_admins[ id ]->guid ) )
+ {
+ ADMP( va( "^3%s:^7 you may not change your own flags (use rcon)\n", cmd ) );
+ return qfalse;
+ }
+ if( flag[ 0 ] != '.' && !G_admin_permission( ent, flag ) )
+ {
+ ADMP( va( "^3%s:^7 you can only change flags that you also have\n", cmd ) );
+ return qfalse;
+ }
+
+ if( !Q_stricmp( cmd, "unflag" ) )
+ {
+ clear = qtrue;
+ }
+
+ if( admin_level < 0 )
+ {
+ result = G_admin_user_flag( g_admin_admins[ id ]->flags, flag, add, clear,
+ g_admin_admins[ id ]->flags, sizeof( g_admin_admins[ id ]->flags ) );
+ }
+ else
+ {
+ result = G_admin_user_flag( g_admin_levels[ admin_level ]->flags, flag, add, clear,
+ g_admin_levels[ admin_level ]->flags,
+ sizeof( g_admin_levels[ admin_level ]->flags ) );
+ }
+ if( result )
+ {
+ ADMP( va( "^3!flag: ^7an error occured setting flag '^3%s^7', %s\n",
+ flag, result ) );
+ return qfalse;
+ }
+
+ if( !Q_stricmp( cmd, "flag" ) )
+ {
+ G_AdminsPrintf( "^3!%s: ^7%s^7 was %s admin flag '%s' by %s\n",
+ cmd, adminname,
+ ( add ) ? "given" : "denied",
+ flag,
+ ( ent ) ? ent->client->pers.netname : "console" );
+ }
+ else
+ {
+ G_AdminsPrintf( "^3!%s: ^7admin flag '%s' for %s^7 cleared by %s\n",
+ cmd, flag, adminname,
+ ( ent ) ? ent->client->pers.netname : "console" );
+ }
+
+ if( !g_admin.string[ 0 ] )
+ ADMP( va( "^3!%s: ^7WARNING g_admin not set, not saving admin record "
+ "to a file\n", cmd ) );
+ else
+ admin_writeconfig();
+
+ return qtrue;
+}
+
+qboolean G_admin_immunity( gentity_t *ent, int skiparg )
+{
+ char command[ MAX_ADMIN_CMD_LEN ];
+ char *cmd, *action;
+ int id;
+ char adminname[ MAX_NAME_LENGTH ] = {""};
+ const char *result;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!immunity: ^7usage: immunity [+|-]slot#\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, command, sizeof( command ) );
+ cmd = command;
+ action = command;
+ if( *cmd == '+' || *cmd == '-' ) cmd++;
+
+ id = G_admin_find_admin_slot( ent, cmd, "immunity", adminname, sizeof( adminname ) );
+ if( id < 0 )
+ return qfalse;
+
+ if( *action != '+' && *action != '-' )
+ {
+ ADMP( va( "^3immunity:^7 ban immunity for %s^7 is %s, prepend + or - to the slot number to change.\n",
+ adminname,
+ ( G_admin_permission_guid( g_admin_admins[ id ]->guid, ADMF_BAN_IMMUNITY ) ) ? "on" : "off" ) );
+ return qfalse;
+ }
+
+ result = G_admin_user_flag( g_admin_admins[ id ]->flags,
+ ADMF_BAN_IMMUNITY, qtrue, ( *action != '+' ),
+ g_admin_admins[ id ]->flags, sizeof( g_admin_admins[ id ]->flags ) );
+ if( result )
+ {
+ ADMP( va( "^3!immunity: ^7an error occured setting flag, %s\n", result ) );
+ return qfalse;
+ }
+
+ if( *action == '+' )
+ {
+ AP( va(
+ "print \"^3!immunity: ^7%s^7 was given ban immunity by %s\n\"",
+ adminname, ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+ else
+ {
+ AP( va(
+ "print \"^3!immunity: ^7ban immunity for %s^7 removed by %s\n\"",
+ adminname, ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+
+ if( !g_admin.string[ 0 ] )
+ ADMP( "^3!immunity: ^7WARNING g_admin not set, not saving admin record "
+ "to a file\n" );
+ else
+ admin_writeconfig();
+
+ return qtrue;
+}
+
//!Warn by Gate (Daniel Evans)
qboolean G_admin_warn( gentity_t *ent, int skiparg )
{//mostly copy and paste with the proper lines altered from !mute and !kick
@@ -6284,9 +7001,47 @@ qboolean G_admin_warn( gentity_t *ent, int skiparg )
( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );//console announcement
return qtrue;
}
+
+qboolean G_admin_bring( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ];
+ char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+
+ if( !ent )
+ {
+ ADMP( "^3!bring: ^7console cannot use this command\n" );
+ return qfalse;
+ }
+ if( ent->client->pers.teamSelection != PTE_NONE )
+ {
+ ADMP( "^3!bring: ^7you can only use this command from spectator\n" );
+ return qfalse;
+ }
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!bring: ^7usage: !bring [name|slot#]\n" );
+ return qfalse;
+ }
+
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( G_ClientNumbersFromString( name, pids ) != 1 )
+ {
+ G_MatchOnePlayer( pids, err, sizeof( err ) );
+ ADMP( va( "^3!bring: ^7%s\n", err ) );
+ return qfalse;
+ }
+
+ vic = &g_entities[ pids[ 0 ] ];
+ VectorCopy( vic->client->ps.origin, ent->client->ps.origin );
+
+ return qtrue;
+}
qboolean G_admin_putmespec( gentity_t *ent, int skiparg )
{
+ int cs_offset;
+
if( !ent )
{
ADMP( "!specme: sorry, but console isn't allowed on the spectators team\n");
@@ -6302,6 +7057,15 @@ qboolean G_admin_putmespec( gentity_t *ent, int skiparg )
if(ent->client->pers.teamSelection == PTE_NONE)
return qfalse;
+ if( ent->client->pers.teamSelection == PTE_ALIENS )
+ cs_offset = 1;
+ else
+ cs_offset = 0;
+ if( level.teamVoteTime[ cs_offset ] )
+ {
+ trap_SendServerCommand( ent-g_entities, "print \"Can not leave team during a team vote\n\"" );
+ return qfalse;
+ }
//guard against build timer exploit
if( ent->client->pers.teamSelection != PTE_NONE && ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
( ent->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ||
@@ -6315,10 +7079,119 @@ qboolean G_admin_putmespec( gentity_t *ent, int skiparg )
}
G_ChangeTeam( ent, PTE_NONE );
+
+ // check for silent '!specme s' - requires !kick permission
+ if( G_SayArgc() > 1 + skiparg )
+ {
+ char arg[ 2 ];
+
+ G_SayArgv( 1 + skiparg, arg, sizeof( arg ) );
+ if( ( arg[ 0 ] == 's' || arg[ 0 ] == 'S' ) && G_admin_permission( ent, "kick" ) )
+ {
+ ADMP("^3!specme: ^7 You have silently joined the spectators\n");
+ return qtrue;
+ }
+ }
+
AP( va("print \"^3!specme: ^7%s^7 decided to join the spectators\n\"", ent->client->pers.netname ) );
return qtrue;
}
+qboolean G_admin_outlaw( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ];
+ char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ char valuebuf[ 8 ];
+ gentity_t *vic;
+ int points;
+ qboolean activate = qtrue;
+
+ if( !g_bleedingSpree.integer )
+ {
+ ADMP( "^3!outlaw: ^7bleeding sprees are disabled\n" );
+ return qfalse;
+ }
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!outlaw: ^7usage: !outlaw [name|slot#] (value)\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( G_ClientNumbersFromString( name, pids ) != 1 )
+ {
+ G_MatchOnePlayer( pids, err, sizeof( err ) );
+ ADMP( va( "^3!mute: ^7%s\n", err ) );
+ return qfalse;
+ }
+ vic = &g_entities[ pids[ 0 ] ];
+
+ if( G_SayArgc() > 2 + skiparg )
+ {
+ G_SayArgv( 2 + skiparg, valuebuf, sizeof( valuebuf ) );
+ if( valuebuf[ 0 ] == '?' )
+ {
+ ADMP( va( "^3!outlaw: ^7%s^7's bleeder value is %d\n",
+ vic->client->pers.netname,
+ vic->client->pers.statscounters.spreebleeds ) );
+ return qtrue;
+ }
+ if( valuebuf[ 0 ] == '+' || valuebuf[ 0 ] == '-' )
+ {
+ activate = qfalse;
+ }
+ points = atoi( valuebuf );
+ }
+ else
+ {
+ points = ( g_bleedingSpree.integer + 1 ) * 100;
+ }
+
+ if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ {
+ ADMP( "^3!outlaw: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
+ return qfalse;
+ }
+ if( points )
+ {
+ vic->client->pers.statscounters.spreebleeds += points;
+ if( vic->client->pers.statscounters.spreebleeds < 1 )
+ vic->client->pers.statscounters.spreebleeds = 1;
+ if( activate && !vic->client->pers.bleeder )
+ {
+ vic->client->pers.bleeder = qtrue;
+ level.bleeders++;
+
+ AP( va( "print \"^3!outlaw: ^7%s^7 has been designated an outlaw by ^7%s\n\"",
+ vic->client->pers.netname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+ else
+ {
+ AP( va( "print \"^3!outlaw: ^7%s^7 bleeder value has been adjusted by ^7%s\n\"",
+ vic->client->pers.netname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ ADMP( va( "^3!outlaw: ^7%s^7's bleeder value is now %d\n",
+ vic->client->pers.netname,
+ vic->client->pers.statscounters.spreebleeds ) );
+ }
+ }
+ else
+ {
+ vic->client->pers.statscounters.spreebleeds = 0;
+ if( vic->client->pers.bleeder )
+ vic->client->pers.bleeder = qfalse;
+ if( level.bleeders )
+ level.bleeders--;
+
+ AP( va( "print \"^3!outlaw: ^7%s^7 has been pardoned by ^7%s\n\"",
+ vic->client->pers.netname,
+ ( ent ) ? ent->client->pers.netname : "console" ) );
+ }
+ return qtrue;
+}
+
qboolean G_admin_slap( gentity_t *ent, int skiparg )
{
int pids[ MAX_CLIENTS ];
@@ -6452,6 +7325,45 @@ qboolean G_admin_drop( gentity_t *ent, int skiparg )
return qtrue;
}
+qboolean G_admin_bubble( gentity_t *ent, int skiparg )
+{
+ int pids[ MAX_CLIENTS ];
+ char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!bubble: ^7usage: !bubble [name|slot#]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, name, sizeof( name ) );
+ if( G_ClientNumbersFromString( name, pids ) != 1 )
+ {
+ G_MatchOnePlayer( pids, err, sizeof( err ) );
+ ADMP( va( "^3!bubble: ^7%s\n", err ) );
+ return qfalse;
+ }
+ if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) )
+ {
+ ADMP( "^3!bubble: ^7sorry, but your intended victim has a higher admin"
+ " level than you\n" );
+ return qfalse;
+ }
+
+ vic = &g_entities[ pids[ 0 ] ];
+ if( vic->client->pers.bubbleTime )
+ vic->client->pers.bubbleTime = 0;
+ else
+ vic->client->pers.bubbleTime = level.time + 500;
+
+ AP( va( "print \"^3!bubble: ^7bubbles %s for %s^7 by %s\n\"",
+ ( vic->client->pers.bubbleTime ) ? "enabled" : "disabled",
+ vic->client->pers.netname,
+ ( ent ) ? G_admin_adminPrintName( ent ) : "console" ) );
+
+ return qtrue;
+}
+
qboolean G_admin_buildlog( gentity_t *ent, int skiparg )
{
#define LOG_DISPLAY_LENGTH 10
@@ -6663,6 +7575,34 @@ qboolean G_admin_buildlog( gentity_t *ent, int skiparg )
return qtrue;
}
+int G_admin_autorevert( gentity_t *ent )
+{
+ int count = 0;
+ int max;
+ buildHistory_t *ptr;
+
+ if( !g_autoRevert.integer )
+ return 0;
+ if( !g_buildLogMaxLength.integer )
+ return 0;
+
+ max = g_autoRevert.integer;
+ ptr = level.buildHistory;
+ while( ptr && count < max )
+ {
+ if( ptr->ent == ent && ptr->time > level.time - (60000 * 5) &&
+ ( ptr->fate == BF_TEAMKILLED || ptr->fate == BF_DECONNED ) )
+ {
+ trap_SendConsoleCommand( EXEC_APPEND, va("!revert #%d\n", ptr->ID) );
+ count++;
+ }
+
+ ptr = ptr->next;
+ }
+
+ return count;
+}
+
qboolean G_admin_revert( gentity_t *ent, int skiparg )
{
int i = 0, j = 0, repeat = 1, ID = 0, len, matchlen=0;
@@ -6805,33 +7745,6 @@ qboolean G_admin_revert( gentity_t *ent, int skiparg )
return qfalse;
}
}
- // Prevent teleport glitch when reverting an occupied hovel
- if( targ->s.modelindex == BA_A_HOVEL &&
- targ->active )
- {
- gentity_t *builder = targ->builder;
- vec3_t newOrigin;
- vec3_t newAngles;
-
- VectorCopy( targ->s.angles, newAngles );
- newAngles[ ROLL ] = 0;
-
- VectorCopy( targ->s.origin, newOrigin );
- VectorMA( newOrigin, 1.0f, targ->s.origin2, newOrigin );
-
- //prevent lerping
- builder->client->ps.eFlags ^= EF_TELEPORT_BIT;
- builder->client->ps.eFlags &= ~EF_NODRAW;
- G_UnlaggedClear( builder );
-
- G_SetOrigin( builder, newOrigin );
- VectorCopy( newOrigin, builder->client->ps.origin );
- G_SetClientViewAngle( builder, newAngles );
-
- //client leaves hovel
- builder->client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING;
- }
-
// if we haven't returned yet then we're good to go, free it
G_FreeEntity( targ );
// put the marked buildables back and mark them again
@@ -7225,6 +8138,76 @@ qboolean G_admin_L1(gentity_t *ent, int skiparg ){
return qtrue;
}
+qboolean G_admin_nobuild(gentity_t *ent, int skiparg )
+{
+ char func[ 32 ];
+
+ if( ent && ent->client->pers.teamSelection != PTE_NONE )
+ {
+ ADMP( "^3!bring: ^7you can only use this command from spectator\n" );
+ return qfalse;
+ }
+
+ if( G_SayArgc() < 2 + skiparg )
+ {
+ ADMP( "^3!nobuild: ^7usage: !nobuild [on|off|save|add|del|list|mode|zone|+|-|go]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, func, sizeof( func ) );
+
+ if( !Q_stricmp( func, "on" ) )
+ {
+ nobuild_set( qtrue, ent );
+ }
+ else if( !Q_stricmp( func, "off" ) )
+ {
+ nobuild_set( qfalse, ent );
+ }
+ else if( !Q_stricmp( func, "save" ) )
+ {
+ nobuild_save( );
+ }
+ else if( !Q_stricmp( func, "list" ) )
+ {
+ nobuild_list( ent );
+ }
+ else if( !Q_stricmp( func, "add" ) )
+ {
+ nobuild_add( ent );
+ }
+ else if( !Q_stricmp( func, "del" ) )
+ {
+ nobuild_del( ent );
+ }
+ else if( !Q_stricmp( func, "zone" ) )
+ {
+ nobuild_command( ent, qtrue, qfalse, 0.0f );
+ }
+ else if( !Q_stricmp( func, "mode" ) )
+ {
+ nobuild_command( ent, qfalse, qtrue, 0.0f );
+ }
+ else if( !Q_stricmp( func, "+" ) )
+ {
+ nobuild_command( ent, qfalse, qfalse, 8.0f );
+ }
+ else if( !Q_stricmp( func, "-" ) )
+ {
+ nobuild_command( ent, qfalse, qfalse, -8.0f );
+ }
+ else if( !Q_stricmp( func, "go" ) )
+ {
+ nobuild_go( ent );
+ }
+ else
+ {
+ ADMP( "^3!nobuild: ^7usage: !nobuild [on|off|save|add|del|list|mode|zone|+|-|go]\n" );
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
qboolean G_admin_invisible( gentity_t *ent, int skiparg )
{
if( !ent )