1.5.2 Release!

-----
Added !info line endings fix
Added chat channels
Added console checking to !demo
Added !flag series
Added sprees
Added new wiki pages chat and !flag, with documentation about their respective Features.wiki
This commit is contained in:
Paradox460 committed 2008-04-04 02:59:00 +00:00
1 parent 329aefb0d1
commit 1933b4fb90
8 files changed
+1031 -67

No files matched your search

+6
View File
@@ -935,6 +935,12 @@ void ClientTimerActions( gentity_t *ent, int msec )
}
}
}
// spree decay
if( ent->client->pers.statscounters.spreefeeds > 1 )
ent->client->pers.statscounters.spreefeeds -= 2;
if( ent->client->pers.statscounters.spreekills > 1 )
ent->client->pers.statscounters.spreekills -= 2;
// turn off life support when a team admits defeat
if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS &&
+624 -62
View File
@@ -104,7 +104,7 @@ g_admin_cmd_t g_admin_cmds[ ] =
"[^3name|slot#^7] [^3#^7]"
},
{"demo", G_admin_demo, "W",
{"demo", G_admin_demo, "~",
"turn admin chat off for the caller so it does not appear in demos. "
"this is a toggle use !demo again to turn warnings back on",
""
@@ -144,7 +144,12 @@ g_admin_cmd_t g_admin_cmds[ ] =
"cause a player to explode. Caution: damages surrounding players and structures.",
"[^3name|slot#^7]"
},
{"flag", G_admin_flag, "f",
"add an admin flag to a player, prefix flag with '-' to disallow",
"[^5slot#^7] [^3-^7][^3flag^7]"
},
{"forcespec", G_admin_forcespec, "F",
"disable joining of teams for a player",
"[^3name|slot#^7]"
@@ -281,6 +286,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
"(^5xnum^7) (^5#ID^7) (^5-name|num^7) (^5a|h^7)"
},
{"seen", G_admin_seen, "D",
"find the last time a player was on the server",
"[^3name|admin#^7]"
},
{"setlevel", G_admin_setlevel, "s",
"sets the admin level of a player",
"[^3name|slot#|admin#^7] [^3level^7]"
@@ -347,6 +357,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
"revoke designated builder privileges",
"[^3name|slot#^7]"
},
{"unflag", G_admin_flag, "f",
"clears an admin flag from a player",
"[^5slot#^7] [^3flag^7]"
},
{"unforcespec", G_admin_unforcespec, "F",
"enable joining of teams for a player",
@@ -784,6 +799,219 @@ 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;
if( !g_chat.string[ 0 ] )
{
G_Printf( "WARNING: g_chat is not set. "
" channel subscriptions will not be saved to a 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 < 1 )
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 );
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( !Q_stricmp( t, "seen" ) )
{
admin_readconfig_int( &cnf, &a->seen );
}
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 ) )
{
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 )
@@ -1372,6 +1600,8 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect )
char n2[ MAX_NAME_LENGTH ];
int clientNum = ( client - level.clients );
G_admin_seen_update( client->pers.guid );
G_SanitiseName( client->pers.netname, n1 );
for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )
{
@@ -1637,6 +1867,7 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
*a->guid = '\0';
a->level = 0;
*a->flags = '\0';
a->seen = 0;
admin_open = qtrue;
}
else if( !Q_stricmp( t, "[ban]" ) )
@@ -1695,6 +1926,9 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg )
admin_level_maxname = strlen( n );
}
}
G_admin_chat_readconfig( ent );
return qtrue;
}
@@ -3604,6 +3838,10 @@ void G_admin_info_parse( char *unparsed, char *dest, int maxlength )
cursor++; //skip me
}
}
else if( unparsed[cursor] == '\r' )
{
i--; // skip unprintable characters for this cycle
}
else if( unparsed[cursor] == '$' )
{ //read variable
if( unparsed[1+cursor++] == '{' ) cursor++; // skip $ and { if there
@@ -5748,6 +5986,126 @@ qboolean G_admin_L0(gentity_t *ent, int skiparg ){
return qtrue;
}
qboolean G_admin_seen(gentity_t *ent, int skiparg )
{
char name[ MAX_NAME_LENGTH ];
char search[ MAX_NAME_LENGTH ];
char sduration[ 32 ];
qboolean numeric = qtrue;
int i, j;
int id = -1;
int count = 0;
int t;
qtime_t qt;
gentity_t *vic;
qboolean ison;
if( G_SayArgc() < 2 + skiparg )
{
ADMP( "^3!seen: ^7usage: !seen [name|admin#]\n" );
return qfalse;
}
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
G_SanitiseName( name, search );
for( i = 0; i < sizeof( search ) && search[ i ] ; i++ )
{
if( search[ i ] < '0' || search[ i ] > '9' )
{
numeric = qfalse;
break;
}
}
if( numeric )
{
id = atoi( name );
search[ 0 ] = '\0';
}
ADMBP_begin();
t = trap_RealTime( &qt );
for( i = 0; i < level.maxclients && count < 10; i ++ )
{
vic = &g_entities[ i ];
if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
continue;
G_SanitiseName( vic->client->pers.netname, name );
if( i == id || (search[ 0 ] && strstr( name, search ) ) )
{
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++ )
{
G_SanitiseName( g_admin_admins[ i ]->name, name );
if( i + MAX_CLIENTS == id || (search[ 0 ] && strstr( name, search ) ) )
{
ison = qfalse;
for( j = 0; j < level.maxclients; j++ )
{
vic = &g_entities[ j ];
if( !vic->client || vic->client->pers.connected != CON_CONNECTED )
continue;
G_SanitiseName( vic->client->pers.netname, name );
if( !Q_stricmp( vic->client->pers.guid, g_admin_admins[ i ]->guid )
&& strstr( name, search ) )
{
ison = qtrue;
break;
}
}
if( ison )
{
if( id == -1 )
continue;
ADMBP( va( "%4d %s^7 is currently playing\n",
i + MAX_CLIENTS, g_admin_admins[ i ]->name ) );
}
else
{
G_admin_duration( t - g_admin_admins[ i ]->seen,
sduration, sizeof( sduration ) );
ADMBP( va( "%4d %s^7 last seen %s%s\n",
i + MAX_CLIENTS, g_admin_admins[ i ]->name ,
( g_admin_admins[ i ]->seen ) ? sduration : "",
( g_admin_admins[ i ]->seen ) ? " ago" : "time is unknown" ) );
}
count++;
}
}
if( search[ 0 ] )
ADMBP( va( "^3!seen:^7 found %d player%s matching '%s'\n",
count, (count == 1) ? "" : "s", search ) );
else if ( !count )
ADMBP( "^3!seen:^7 no one connectd by that slot number\n" );
ADMBP_end();
return qtrue;
}
void G_admin_seen_update( char *guid )
{
int i;
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ] ; i++ )
{
if( !Q_stricmp( g_admin_admins[ i ]->guid, guid ) )
{
qtime_t qt;
g_admin_admins[ i ]->seen = trap_RealTime( &qt );
return;
}
}
}
void G_admin_adminlog_cleanup( void )
{
int i;
@@ -6278,31 +6636,125 @@ qboolean G_admin_listmaps( gentity_t *ent, int skiparg )
return qtrue;
}
qboolean G_admin_immunity( gentity_t *ent, int skiparg )
const char *G_admin_user_flag( int id, char flag, qboolean add, qboolean clear )
{
char command[ MAX_ADMIN_CMD_LEN ];
char *cmd, *p, *action;
char guid[ 33 ];
int id;
int i, j;
char c;
gentity_t *vic;
char adminname[ MAX_NAME_LENGTH ] = {""};
char oldflags[ MAX_ADMIN_FLAGS ];
char *newflags;
qboolean numeric = qtrue;
char add_flags[ MAX_ADMIN_FLAGS ];
char sub_flags[ MAX_ADMIN_FLAGS ];
char *flags;
int add_count = 0;
int sub_count = 0;
qboolean wildcard = qfalse;
qboolean allowed = qtrue;
if( G_SayArgc() < 2 + skiparg )
if( id < 0 || id >= MAX_ADMIN_ADMINS
|| g_admin_admins[ id ] == NULL )
{
ADMP( "^3!immunity: ^7usage: immunity [+|-]slot#\n" );
return qfalse;
return "admin id out of range";
}
G_SayArgv( 1 + skiparg, command, sizeof( command ) );
cmd = command;
action = command;
if( *cmd == '+' || *cmd == '-' ) cmd++;
p = cmd;
if( flag == '-' || flag == '+' || flag == '*')
{
return "invalid admin flag";
}
flags = g_admin_admins[ id ]->flags;
while( *flags )
{
if( *flags == '*' )
{
wildcard = qtrue;
allowed = qfalse;
}
else if( *flags == '-' )
{
allowed = qfalse;
}
else if( *flags == '+' )
{
allowed = qtrue;
}
else if( *flags != flag )
{
if( allowed )
{
if( add_count < MAX_ADMIN_FLAGS - 1 )
{
add_flags[ add_count ] = *flags;
add_count++;
}
}
else
{
if( sub_count < MAX_ADMIN_FLAGS - 1 )
{
sub_flags[ sub_count ] = *flags;
sub_count++;
}
}
}
flags++;
}
if( !clear )
{
if( add )
{
if( flag == '*' )
{
wildcard = qtrue;
}
else if( add_count < MAX_ADMIN_FLAGS - 1 )
{
add_flags[ add_count ] = flag;
add_count++;
}
}
else
{
if( flag == '*' )
{
wildcard = qfalse;
}
else if( sub_count < MAX_ADMIN_FLAGS - 1 )
{
sub_flags[ sub_count ] = flag;
sub_count++;
}
}
}
add_flags[ add_count ] = '\0';
sub_flags[ sub_count ] = '\0';
if( add_count + sub_count + ( (wildcard || sub_count) ? 1 : 0 ) + 1 > MAX_ADMIN_FLAGS )
{
return "maximum admin flags exceeded";
}
Com_sprintf( g_admin_admins[ id ]->flags, sizeof(g_admin_admins[ id ]->flags),
"%s%s%s%s",
add_flags,
( wildcard ) ? "*" : "",
( sub_count && !wildcard ) ? "-" : "",
sub_flags );
return NULL;
}
int G_admin_find_slot( gentity_t *ent, char *cmd, char *name, char *nick, int nick_len )
{
char guid[ 33 ];
char *p;
int id;
int i;
qboolean numeric = qtrue;
gentity_t *vic;
if ( nick )
nick[ 0 ] = '\0';
p = name;
while ( *p )
{
if( *p < '0' || *p > '9' )
@@ -6312,26 +6764,26 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg )
}
p++;
}
if( !numeric || *cmd == '\0' )
if( !numeric || name[ 0 ] == '\0' )
{
ADMP( "^3!immunity:^7 invalid slot number\n." );
return qfalse;
ADMP( va( "^3!%s:^7 invalid slot number\n.", cmd ) );
return -1;
}
id = atoi( cmd );
guid[ 0 ] = '\0';
id = atoi( name );
if( id >= 0 && id < level.maxclients )
{
vic = &g_entities[ id ];
if( !vic || !(vic->client) || vic->client->pers.connected != CON_CONNECTED )
{
ADMP( "^3!immunity:^7 no one connectd by that slot number\n" );
ADMP( va( "^3!%s:^7 no one connected by that slot number\n", cmd ) );
return qfalse;
}
Q_strncpyz( guid, vic->client->pers.guid, sizeof( guid ) );
if( *guid == '\0' )
if( *guid == 'X' )
{
ADMP( va( "^3!immunity:^7 player in slot %d has no GUID.\n", id ) );
ADMP( va( "^3!%s:^7 player in slot %d has no GUID.\n", cmd, id ) );
return qfalse;
}
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
@@ -6339,7 +6791,8 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg )
if( !Q_stricmp( guid, g_admin_admins[ i ]->guid ) )
{
id = i + MAX_CLIENTS;
Q_strncpyz( adminname, vic->client->pers.netname, sizeof( adminname ) );
if( nick )
Q_strncpyz( nick, vic->client->pers.netname, nick_len );
break;
}
}
@@ -6347,17 +6800,140 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg )
if( id < MAX_CLIENTS || id >= MAX_CLIENTS + MAX_ADMIN_ADMINS
|| g_admin_admins[ id - MAX_CLIENTS ] == NULL )
{
ADMP( "^3!immunity:^7 no match. use !listplayers or !listadmins to "
"find an appropriate slot # to use.\n" );
if( *guid )
ADMP( va( "^3!%s:^7 player is not !registered\n", cmd ) );
else
ADMP( va( "^3!%s:^7 no match. use !listplayers or !listadmins to "
"find an appropriate slot # to use.\n", cmd ) );
return -1;
}
id -= MAX_CLIENTS;
if ( nick && !nick[ 0 ] )
{
Q_strncpyz( nick, g_admin_admins[ id ]->name, nick_len );
}
return id;
}
qboolean G_admin_flag( gentity_t *ent, int skiparg )
{
char command[ MAX_ADMIN_CMD_LEN ], *cmd;
char name[ MAX_NAME_LENGTH ];
char flagbuf[ 4 ], *flag;
int id;
char adminname[ MAX_NAME_LENGTH ] = {""};
const char *result;
qboolean add = qtrue;
qboolean clear = qfalse;
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;
}
id -= MAX_CLIENTS;
if ( !(*adminname) )
{
Q_strncpyz( adminname, g_admin_admins[ id ]->name, sizeof( adminname ) );
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
id = G_admin_find_slot( ent, cmd, name, 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 then you\n", cmd ) );
return qfalse;
}
if( G_SayArgc() < 3 + skiparg )
{
ADMP( va( "^3%s:^7 flags for %s^7 are '^3%s^7'\n",
cmd, adminname, g_admin_admins[ id ]->flags ) );
return qtrue;
}
G_SayArgv( 2 + skiparg, flagbuf, sizeof( flagbuf ) );
flag = flagbuf;
if( flag[ 0 ] == '-' && flag[ 1 ] != '\0' )
{
add = qfalse;
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( !G_admin_permission( ent, flag[ 0 ] ) )
{
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;
}
result = G_admin_user_flag( id, flag[ 0 ], add, clear );
if( result )
{
ADMP( va( "^3!immunity: ^7an error occured setting flag '^3%c^7', %s\n",
flag[ 0 ], result ) );
return qfalse;
}
if( !Q_stricmp( cmd, "flag" ) )
{
AP( va(
"print \"^3!%s: ^7%s^7 was %s admin flag '%c' by %s\n\"",
cmd, adminname,
( add ) ? "given" : "denied",
flag[ 0 ],
( ent ) ? ent->client->pers.netname : "console" ) );
}
else
{
AP( va(
"print \"^3!%s: ^7admin flag '%c' for %s^7 cleared by %s\n\"",
cmd, flag[ 0 ], 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_slot( ent, "immunity", cmd, adminname, sizeof( adminname ) );
if( id < 0 )
return qfalse;
if( *action != '+' && *action != '-' )
{
@@ -6367,32 +6943,12 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg )
return qfalse;
}
Q_strncpyz( oldflags, g_admin_admins[ id ]->flags, sizeof( oldflags ) );
newflags = g_admin_admins[ id ]->flags;
i = j = 0;
while( i < MAX_ADMIN_FLAGS - 1 && oldflags[ i ] )
result = G_admin_user_flag( id, ADMF_BANIMMUNITY, qtrue, ( *action != '+' ) );
if( result )
{
c = oldflags[ i ];
if( c != ADMF_BANIMMUNITY )
{
newflags[ j ] = c;
j++;
}
i++;
ADMP( va( "^3!immunity: ^7an error occured setting flag, %s\n", result ) );
return qfalse;
}
if( *action == '+' )
{
if( j < MAX_ADMIN_FLAGS - 1 )
{
newflags[ j ] = ADMF_BANIMMUNITY;
j++;
}
else
{
ADMP( "^3!immunity:^7 flag count exceeded, no actual ban immunity.\n" );
}
}
newflags[ j ] = '\0';
if( *action == '+' )
{
@@ -6408,7 +6964,7 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg )
}
if( !g_admin.string[ 0 ] )
ADMP( "^3!setlevel: ^7WARNING g_admin not set, not saving admin record "
ADMP( "^3!immunity: ^7WARNING g_admin not set, not saving admin record "
"to a file\n" );
else
admin_writeconfig();
@@ -6486,6 +7042,12 @@ qboolean G_admin_suspendban( gentity_t *ent, int skiparg )
qboolean G_admin_demo( gentity_t *ent, int skiparg )
{
if( !ent )
{
ADMP( "!demo: console can not use demo.\n");
return qfalse;
}
ent->client->pers.ignoreAdminWarnings = !( ent->client->pers.ignoreAdminWarnings );
ADMP( va( "^3!demo: ^7your visibility of admin chat is now %s\n",
+14
View File
@@ -45,6 +45,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MAX_ADMIN_BANSUSPEND_DAYS 14
#define CHAT_MAXCHAN 10
#define CHAT_MAXPASS 12
/*
* 1 - cannot be vote kicked, vote muted
* 2 - cannot be censored or flood protected TODO
@@ -114,6 +117,8 @@ typedef struct g_admin_admin
char name[ MAX_NAME_LENGTH ];
int level;
char flags[ MAX_ADMIN_FLAGS ];
int seen;
char chat[ CHAT_MAXCHAN ][ CHAT_MAXPASS ];
}
g_admin_admin_t;
@@ -214,7 +219,10 @@ qboolean G_admin_buildlog( gentity_t *ent, int skiparg );
qboolean G_admin_revert( gentity_t *ent, int skiparg );
qboolean G_admin_slap( gentity_t *ent, int skiparg );
qboolean G_admin_L0( gentity_t *ent, int skiparg );
qboolean G_admin_seen(gentity_t *ent, int skiparg );
void G_admin_seen_update( char *guid );
qboolean G_admin_listmaps( gentity_t *ent, int skiparg );
qboolean G_admin_flag( gentity_t *ent, int skiparg );
qboolean G_admin_immunity( gentity_t *ent, int skiparg );
qboolean G_admin_suspendban( gentity_t *ent, int skiparg );
qboolean G_admin_demo( gentity_t *ent, int skiparg );
@@ -224,6 +232,12 @@ void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skipar
qboolean G_admin_maplog( gentity_t *ent, int skiparg );
void G_admin_maplog_update( void );
void G_admin_maplog_result( char *flag );
void G_admin_chat_writeconfig( void );
qboolean G_admin_chat_readconfig( gentity_t *ent );
void G_admin_chat_sync( gentity_t *ent );
void G_admin_chat_update( gentity_t *ent, int chan );
//all of my commands WEEEEEEEEEE
qboolean G_admin_switch( gentity_t *ent, int skiparg );
qboolean G_admin_mix( gentity_t *ent, int skiparg );
+3
View File
@@ -1532,6 +1532,9 @@ void ClientBegin( int clientNum )
// name can change between ClientConnect() and ClientBegin()
G_admin_namelog_update( client, qfalse );
// rejoin any saved chat channels
G_admin_chat_sync( ent );
// request the clients PTR code
trap_SendServerCommand( ent - g_entities, "ptrcrequest" );
+297 -1
View File
@@ -1375,6 +1375,223 @@ static void Cmd_Tell_f( gentity_t *ent )
G_Say( ent, ent, SAY_TELL, p );
}
void Cmd_Join_f( gentity_t *ent )
{
char pass[CHAT_MAXPASS];
char arg[MAX_TOKEN_CHARS];
int chan;
int i;
gentity_t *target;
if( g_floodMinTime.integer &&
G_Flood_Limited( ent ) )
{
trap_SendServerCommand( ent-g_entities,
"print \"Your chat is flood-limited; wait before chatting again\n\"" );
return;
}
if( trap_Argc( ) < 2 )
{
char message[ 64 ];
int n;
n = 0;
for( i = 0; i < CHAT_MAXCHAN && n < 64 - 3; i++ )
{
if( ent->client->pers.chat[i][0] )
{
message[ n ] = ' '; n++;
message[ n ] = '0' + i; n++;
}
}
if( n == 0)
Com_sprintf( message, sizeof( message ), " no channels, use: /join [0-%d] (password)", CHAT_MAXCHAN - 1 );
else
message[ n ] = '\0';
trap_SendServerCommand( ent-g_entities, va( "print \"joined in:%s\n\"", message ) );
return;
}
trap_Argv( 1, arg, sizeof( arg ) );
chan = atoi( arg );
if( chan < 0 || chan >= CHAT_MAXCHAN )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"^3/join^7: invalid channel, usage: /join [0-%d] (password)\n\"", CHAT_MAXCHAN - 1 ) );
return;
}
trap_Argv( 2, pass, sizeof( pass ) );
if( pass[0] == '\0' )
Q_strncpyz( pass, "default", sizeof( pass ) );
if( !Q_stricmp( ent->client->pers.chat[chan], pass ) )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"^3/join^7: already join to channel %d\n\"", chan ) );
return;
}
G_LogPrintf( "join: channel %d %s^7\n", chan, ent->client->pers.netname );
Q_strncpyz( ent->client->pers.chat[chan], pass, sizeof( ent->client->pers.chat[chan] ) );
G_admin_chat_update( ent, chan );
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[ chan ], pass ) )
{
trap_SendServerCommand( i, va( "print \"join: %s^7 has joined channel #%d\n\"",
ent->client->pers.netname, chan ) );
}
}
}
void Cmd_Part_f( gentity_t *ent )
{
char arg[MAX_TOKEN_CHARS];
int chan;
int i;
gentity_t *target;
if( trap_Argc( ) < 2 )
{
trap_SendServerCommand( ent-g_entities, va( "print \"^3/part^7 usage: /part [0-%d]\n\"", CHAT_MAXCHAN - 1 ) );
return;
}
if( g_floodMinTime.integer &&
G_Flood_Limited( ent ) )
{
trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
return;
}
trap_Argv( 1, arg, sizeof( arg ) );
chan = atoi( arg );
if( chan < 0 || chan >= CHAT_MAXCHAN )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"^3/part^7: invalid channel, available channels are 0 to %d\n\"", CHAT_MAXCHAN - 1 ) );
return;
}
if( ent->client->pers.chat[chan][0] == '\0' )
{
trap_SendServerCommand( ent-g_entities,
"print \"^3/part^7: not in that channel\n\"" );
return;
}
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[ chan ], ent->client->pers.chat[ chan ] ) )
{
trap_SendServerCommand( i, va( "print \"part: %s^7 has left channel #%d\n\"",
ent->client->pers.netname, chan ) );
}
}
G_LogPrintf( "part: channel %d %s^7\n", chan, ent->client->pers.netname );
Q_strncpyz( ent->client->pers.chat[chan], "", sizeof( ent->client->pers.chat[chan] ) );
G_admin_chat_update( ent, chan );
}
void Cmd_Channel_f( gentity_t *ent )
{
char arg[MAX_TOKEN_CHARS];
char str[MAX_STRING_CHARS];
char *p;
char location[ 64 ];
char escaped[ 64 ];
int chan;
int i;
int num = 0;
qboolean who = qfalse;
gentity_t *target;
if( g_floodMinTime.integer &&
G_Flood_Limited( ent ) )
{
trap_SendServerCommand( ent-g_entities, "print \"Your chat is flood-limited; wait before chatting again\n\"" );
return;
}
trap_Argv( 0, arg, sizeof( arg ) );
chan = atoi( arg );
if( chan < 0 || chan >= CHAT_MAXCHAN ||
ent->client->pers.chat[chan][0] == '\0' )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"^3/%s^7: you are not joined to that channel, use /join\n\"", arg ) );
return;
}
p = ConcatArgs( 1 );
if( !p || p[0] == '\0' )
who = qtrue;
if( Team_GetLocationMsg( ent, location, sizeof( location ) ) )
{
Com_sprintf( escaped, sizeof( escaped ), " (^4%s^7)", location );
}
else
{
escaped[ 0 ] = '\0';
}
str[ 0 ] = '\0';
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[ chan ], ent->client->pers.chat[ chan ] ) )
{
if( num > 0 )
Q_strcat( str, sizeof( str ), "^7, " );
Q_strcat( str, sizeof( str ), target->client->pers.netname );
num++;
}
}
if( who )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"channel ^3%d^7 has %s%s and contains %d player%s%s%s\n\"",
chan,
( !Q_stricmp( ent->client->pers.chat[ chan ], "default" ) ) ? "no password" : "password ",
( !Q_stricmp( ent->client->pers.chat[ chan ], "default" ) ) ? "" : ent->client->pers.chat[ chan ],
num,
( num == 1 ) ? "" : "s",
( num ) ? ": " : "",
str ) );
return;
}
G_LogPrintf( "channel%d: %s^7 %s\n", chan, ent->client->pers.netname, p );
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[ chan ], ent->client->pers.chat[ chan ] ) )
{
trap_SendServerCommand( i, va( "print \"(^1#%d^7 %d) [%s^7]%s: ^1%s^7\n\"",
chan, num, ent->client->pers.netname,
( OnSameTeam( target, ent ) ) ? escaped : "",
p ) );
}
}
}
/*
==================
Cmd_Where_f
@@ -2650,7 +2867,39 @@ void Cmd_Destroy_f( gentity_t *ent )
BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) );
return;
}
// Prevent destruction of critical buildables (per g_deconTime)
if( g_deconTime.integer &&
( traceEnt->s.modelindex == BA_A_OVERMIND || traceEnt->s.modelindex == BA_H_REACTOR ) )
{
if( g_deconTime.integer > 0 &&
level.time - level.startTime < g_deconTime.integer * 1000 )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s can't be moved until %d:%02d into the game\n\"",
BG_FindHumanNameForBuildable( traceEnt->s.modelindex ),
g_deconTime.integer / 60, g_deconTime.integer % 60 ) );
return;
}
if( g_deconTime.integer < 0 &&
level.time - level.startTime < 60 * 1000 && level.numConnectedClients )
{
int numTeammates;
if( ent->client->pers.teamSelection == PTE_HUMANS )
numTeammates = level.numHumanClients;
else
numTeammates = level.numAlienClients;
if( numTeammates * 100 / level.numConnectedClients < 33 )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s can't be moved until more players join, or after 1:00\n\"",
BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) );
return;
}
}
}
// Prevent destruction of the last spawn
if( g_markDeconstruct.integer != 1 )
@@ -2812,6 +3061,39 @@ void Cmd_Mark_f( gentity_t *ent )
return;
}
// Prevent marking of critical buildables (per g_deconTime)
if( g_deconTime.integer &&
( traceEnt->s.modelindex == BA_A_OVERMIND || traceEnt->s.modelindex == BA_H_REACTOR ) )
{
if( g_deconTime.integer > 0 &&
level.time - level.startTime < g_deconTime.integer * 1000 )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s can't be moved until %d:%02d into the game\n\"",
BG_FindHumanNameForBuildable( traceEnt->s.modelindex ),
g_deconTime.integer / 60, g_deconTime.integer % 60 ) );
return;
}
if( g_deconTime.integer < 0 &&
level.time - level.startTime < 60 * 1000 && level.numConnectedClients )
{
int numTeammates;
if( ent->client->pers.teamSelection == PTE_HUMANS )
numTeammates = level.numHumanClients;
else
numTeammates = level.numAlienClients;
if( numTeammates * 100 / level.numConnectedClients < 33 )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s can't be moved until more players join, or after 1:00\n\"",
BG_FindHumanNameForBuildable( traceEnt->s.modelindex ) ) );
return;
}
}
}
// Don't allow marking of buildables that cannot be rebuilt
if(g_suddenDeath.integer && traceEnt->health > 0 &&
( ( g_suddenDeathMode.integer == SDMODE_SELECTIVE &&
@@ -4366,6 +4648,20 @@ commands_t cmds[ ] = {
{ "me", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
{ "me_team", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Say_f },
// channel chat
{ "join", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Join_f },
{ "part", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Part_f },
{ "0", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "1", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "2", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "3", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "4", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "5", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "6", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "7", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "8", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "9", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Channel_f },
{ "score", CMD_INTERMISSION, ScoreboardMessage },
{ "mystats", CMD_TEAM|CMD_INTERMISSION, Cmd_MyStats_f },
+63 -2
View File
@@ -140,6 +140,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
float percentDamage = 0.0f;
gentity_t *player;
qboolean tk = qfalse;
int spreeRate = 0;
if( self->client->ps.pm_type == PM_DEAD )
@@ -207,6 +208,16 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
//TA: deactivate all upgrades
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
BG_DeactivateUpgrade( i, self->client->ps.stats );
// killing spree over
if( self->client->pers.statscounters.spreekills == -1 )
{
spreeRate = 2;
trap_SendServerCommand( -1,
va( "print \"%s^7's killing spree has come to an end\n\"",
self->client->pers.netname ) );
}
self->client->pers.statscounters.spreekills = 0;
if( meansOfDeath == MOD_SLAP )
{
@@ -314,6 +325,19 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
{
level.humanStatsCounters.kills++;
}
if( g_killingSpree.integer > 2 )
{
if( attacker->client->pers.statscounters.spreekills >= 0 )
attacker->client->pers.statscounters.spreekills += 60;
if( attacker->client->pers.statscounters.spreekills > ( g_killingSpree.integer - 1 ) * 60 )
{
attacker->client->pers.statscounters.spreekills = -1;
trap_SendServerCommand( -1,
va( "print \"%s^3 is on a killing spree! killer gets a double reward bonus\n\"",
attacker->client->pers.netname ) );
}
}
}
if( attacker == self )
@@ -456,6 +480,13 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
{
self->client->pers.statscounters.feeds++;
level.humanStatsCounters.feeds++;
if( g_feedingSpree.integer &&
level.reactorPresent &&
!G_BuildableRange( self->client->ps.origin, 900, BA_H_REACTOR ) )
{
self->client->pers.statscounters.spreefeeds += 60;
}
}
}
else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
@@ -465,6 +496,13 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
{
self->client->pers.statscounters.feeds++;
level.alienStatsCounters.feeds++;
if( g_feedingSpree.integer &&
level.overmindPresent &&
!G_BuildableRange( self->client->ps.origin, 900, BA_A_OVERMIND ) )
{
self->client->pers.statscounters.spreefeeds += 60;
}
}
}
}
@@ -497,6 +535,9 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
}
if( spreeRate && player == attacker )
percentDamage *= (float)spreeRate;
//add credit
G_AddCreditToClient( player->client,
(int)( classValue * percentDamage ), qtrue );
@@ -539,7 +580,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
if( frags > 0 )
{
//add kills
G_AddCreditToClient( player->client, frags, qtrue );
if( spreeRate && player == attacker )
G_AddCreditToClient( player->client, frags * spreeRate, qtrue );
else
G_AddCreditToClient( player->client, frags, qtrue );
//can't revist this account later
self->credits[ i ] = 0;
@@ -580,7 +624,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
player = g_entities + topClient;
//add kills
G_AddCreditToClient( player->client, 1, qtrue );
if( spreeRate && player == attacker )
G_AddCreditToClient( player->client, spreeRate, qtrue );
else
G_AddCreditToClient( player->client, 1, qtrue );
//can't revist this account again
self->credits[ topClient ] = 0;
@@ -633,6 +680,20 @@ finish_dying:
// g_forcerespawn may force spawning at some later time
self->client->respawnTime = level.time + 1700;
if( g_feedingSpree.integer > 2 )
{
int maxfeed;
maxfeed = (g_feedingSpree.integer - 1) * 60;
if( self->client->pers.statscounters.spreefeeds > maxfeed )
{
self->client->respawnTime += 100 * (self->client->pers.statscounters.spreefeeds - maxfeed );
trap_SendServerCommand( self->client->ps.clientNum,
va( "print \"You are on a feeding spree! respawn delayed %d seconds\n\"",
(self->client->respawnTime - level.time) / 1000 ) );
}
}
// remove powerups
memset( self->client->ps.powerups, 0, sizeof( self->client->ps.powerups ) );
+9
View File
@@ -337,6 +337,8 @@ typedef struct
int headshots;
int hits;
int hitslocational;
int spreekills;
int spreefeeds;
int teamkills;
int dretchbasytime;
int jetpackusewallwalkusetime;
@@ -394,6 +396,7 @@ typedef struct
statsCounters_t statscounters;
qboolean cusgrav;
int cusgravlvl;
char chat[ CHAT_MAXCHAN ][ CHAT_MAXPASS ];
qboolean ignoreAdminWarnings;
qboolean firstConnect;
@@ -1337,6 +1340,7 @@ extern vmCvar_t g_adminRegisterAdminPass;
extern vmCvar_t g_adminRegisterAdminLevel;
extern vmCvar_t g_minLevelToJoinTeam;
extern vmCvar_t g_minLevelToSpecMM1;
extern vmCvar_t g_chat;
extern vmCvar_t g_KillerHP;
@@ -1348,6 +1352,9 @@ extern vmCvar_t g_publicSayadmins;
extern vmCvar_t g_myStats;
extern vmCvar_t g_antiSpawnBlock;
extern vmCvar_t g_killingSpree;
extern vmCvar_t g_feedingSpree;
extern vmCvar_t g_sayAreaLocations;
extern vmCvar_t g_dretchPunt;
@@ -1377,6 +1384,8 @@ extern vmCvar_t g_banNotice;
extern vmCvar_t g_voteMinTime;
extern vmCvar_t g_mapvoteMaxTime;
extern vmCvar_t g_deconTime;
extern vmCvar_t g_specAspec;
extern vmCvar_t g_modBuildableHealth; // Buildable health
+15 -2
View File
@@ -159,6 +159,7 @@ vmCvar_t g_adminRegisterLevel;
vmCvar_t g_adminRegisterAdminPass;
vmCvar_t g_adminRegisterAdminLevel;
vmCvar_t g_minLevelToJoinTeam;
vmCvar_t g_chat;
vmCvar_t g_privateMessages;
vmCvar_t g_buildLogMaxLength;
@@ -167,6 +168,9 @@ vmCvar_t g_publicSayadmins;
vmCvar_t g_myStats;
vmCvar_t g_antiSpawnBlock;
vmCvar_t g_killingSpree;
vmCvar_t g_feedingSpree;
vmCvar_t g_KillerHP;
vmCvar_t g_decolorLogfiles;
@@ -206,6 +210,8 @@ vmCvar_t g_banNotice;
vmCvar_t g_voteMinTime;
vmCvar_t g_mapvoteMaxTime;
vmCvar_t g_deconTime;
vmCvar_t g_specAspec;
vmCvar_t g_modBuildableHealth;
@@ -386,19 +392,24 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_adminRegisterAdminPass, "g_adminRegisterAdminPass", "", CVAR_ARCHIVE, 0, qfalse },
{ &g_adminRegisterAdminLevel, "g_adminRegisterAdminLevel", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_privateMessages, "g_privateMessages", "1", CVAR_ARCHIVE, 0, qfalse },
{ &g_chat, "g_chat", "chat.dat", CVAR_ARCHIVE, 0, qfalse },
{ &g_radiationDamage, "g_radiationDamage", "1", CVAR_ARCHIVE, 0, qfalse },
{ &g_radiationTime, "g_radiationTime", "60", CVAR_ARCHIVE, 0, qfalse },
{ &g_radiationCredits, "g_radiationCredits", "1000", CVAR_ARCHIVE, 0, qfalse },
{ &g_radiationCreditsCount, "g_radiationCreditsCount", "2", CVAR_ARCHIVE, 0, qfalse },
{ &g_deconTime, "g_deconTime", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_buildLogMaxLength, "g_buildLogMaxLength", "25", CVAR_ARCHIVE, 0, qfalse },
{ &g_myStats, "g_myStats", "1", CVAR_ARCHIVE, 0, qfalse },
{ &g_publicSayadmins, "g_publicSayadmins", "1", CVAR_ARCHIVE, 0, qfalse },
{ &g_minLevelToSpecMM1, "g_minLevelToSpecMM1", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_antiSpawnBlock, "g_antiSpawnBlock", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_killingSpree, "g_killingSpree", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_feedingSpree, "g_feedingSpree", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_KillerHP, "g_KillerHP", "0", CVAR_ARCHIVE, 0, qtrue },
@@ -885,6 +896,8 @@ void G_ShutdownGame( int restart )
// write all the client session data so we can get it back
G_WriteSessionData( );
G_admin_chat_writeconfig();
G_admin_cleanup( );
G_admin_namelog_cleanup( );
G_admin_adminlog_cleanup( );