summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/g_admin.c122
-rw-r--r--src/game/g_admin.h8
-rw-r--r--src/game/g_cmds.c19
-rw-r--r--src/game/g_combat.c3
-rw-r--r--src/game/g_local.h6
-rw-r--r--src/game/g_main.c6
-rw-r--r--src/game/g_team.c44
7 files changed, 184 insertions, 24 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c
index 430650d..2ffb647 100644
--- a/src/game/g_admin.c
+++ b/src/game/g_admin.c
@@ -220,6 +220,11 @@ g_admin_cmd_t g_admin_cmds[ ] =
"[^7id^7]"
},
+ {"score_info", G_admin_score_info, qtrue, "score_info",
+ "display information about player's accumulated score",
+ "(^7name|slot#^7)"
+ },
+
{"setlevel", G_admin_setlevel, qfalse, "setlevel",
"sets the admin level of a player",
"[^7name|slot#|admin#^7] [^7level^7]"
@@ -387,6 +392,18 @@ g_admin_level_t *G_admin_level( const int l )
return NULL;
}
+g_admin_level_t *G_admin_level_next( g_admin_level_t *level )
+{
+ g_admin_level_t *n;
+ if ( !level || ( level->score == -1 ) ) return NULL;
+ for( n = g_admin_levels; n; n = n->next )
+ {
+ if ( n->score == -1 ) continue;
+ if ( n->next && n->next == level ) return n;
+ }
+ return NULL;
+}
+
g_admin_admin_t *G_admin_admin( const char *guid )
{
g_admin_admin_t *admin;
@@ -592,6 +609,8 @@ static void admin_writeconfig( void )
admin_writeconfig_string( l->name, f );
trap_FS_Write( "flags = ", 10, f );
admin_writeconfig_string( l->flags, f );
+ trap_FS_Write( "score = ", 10, f );
+ admin_writeconfig_int( l->score, f );
trap_FS_Write( "\n", 1, f );
}
for( a = g_admin_admins; a; a = a->next )
@@ -609,6 +628,8 @@ static void admin_writeconfig( void )
admin_writeconfig_int( a->level, f );
trap_FS_Write( "flags = ", 10, f );
admin_writeconfig_string( a->flags, f );
+ trap_FS_Write( "score = ", 10, f );
+ admin_writeconfig_int( a->score, f );
trap_FS_Write( "\n", 1, f );
}
for( b = g_admin_bans; b; b = b->next )
@@ -1363,6 +1384,10 @@ qboolean G_admin_readconfig( gentity_t *ent )
{
admin_readconfig_string( &cnf, l->flags, sizeof( l->flags ) );
}
+ else if( !Q_stricmp( t, "score" ) )
+ {
+ admin_readconfig_int( &cnf, &l->score );
+ }
else
{
COM_ParseError( "[level] unrecognized token \"%s\"", t );
@@ -1386,6 +1411,10 @@ qboolean G_admin_readconfig( gentity_t *ent )
{
admin_readconfig_string( &cnf, a->flags, sizeof( a->flags ) );
}
+ else if( !Q_stricmp( t, "score" ) )
+ {
+ admin_readconfig_int( &cnf, &a->score );
+ }
else
{
COM_ParseError( "[admin] unrecognized token \"%s\"", t );
@@ -3383,6 +3412,37 @@ qboolean G_admin_namelog( gentity_t *ent )
return qtrue;
}
+qboolean G_admin_score_info( gentity_t *ent )
+{
+ char reason[ 64 ];
+ int pid;
+ char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
+ gentity_t *vic;
+
+ if( trap_Argc() < 2 )
+ {
+ ADMP( va( "^3score: ^7usage: score [name|slot#]\n" ) );
+ return qfalse;
+ }
+ trap_Argv( 1, name, sizeof( name ) );
+ if( ( pid = G_ClientNumberFromString( name, err, sizeof( err ) ) ) == -1 )
+ {
+ ADMP( va( "^3score: ^7%s\n", err ) );
+ return qfalse;
+ }
+ vic = &g_entities[ pid ];
+ if( vic->client->pers.admin )
+ {
+ ADMP( va( "score: ^7%s^7 level: %d score: %d\n\"",
+ vic->client->pers.netname,
+ vic->client->pers.admin->level,
+ vic->client->pers.admin->score ) );
+ } else {
+ ADMP( va( "score: ^7%s^7 does not have an admin record.\n" ) );
+ }
+ return qtrue;
+}
+
/*
==================
G_NamelogFromString
@@ -3751,6 +3811,64 @@ qboolean G_admin_spawn( gentity_t *ent )
return qtrue;
}
+g_admin_level_t *G_admin_find_level_for_score( int score ) {
+ // NOTE: Assuming that levels are ordered in descending order
+ g_admin_level_t *level,*next;
+ for( level = g_admin_levels; level; level = next )
+ {
+ next = level->next;
+ if( next == NULL && level->score > 0) return level;
+ if( next->score < 0 ) continue;
+ if( /*level->score > score && */next->score <= score ) return next;
+ }
+ return NULL;
+}
+
+void G_admin_add_score( gentity_t *ent, int score ) {
+ g_admin_level_t *n;
+ g_admin_admin_t *a;
+ if( ent->client->pers.admin && level.numAlienClients >= g_AutoLevelMinTeamSize.integer && level.numHumanClients >= g_AutoLevelMinTeamSize.integer ) {
+ ent->client->pers.admin->score += score;
+ if (ent->client->pers.admin->level == -1) return;
+ n = G_admin_find_level_for_score( ent->client->pers.admin->score );
+ if( ( n != NULL ) && ( n->level > ent->client->pers.admin->level ) )
+ {
+ //trap_SendConsoleCommand( EXEC_APPEND,
+ // va( "setlevel %d %d;", ent - g_entities, n->level ) );
+
+ a = ent->client->pers.admin;
+ a->level = n->level;
+ admin_log( va( "^7%d (%s^7) \"%s" S_COLOR_WHITE "\"", a->level, a->guid, a->name ) );
+ AP( va("print \"^3setlevel: ^7%s^7 was given level %d admin rights (^7%s^7) through score gained\n\"",
+ a->name, a->level, n->name ) );
+ admin_writeconfig();
+ }
+ }
+}
+
+void G_admin_reset_score( gentity_t *ent ) {
+ g_admin_level_t *l;
+ g_admin_admin_t *a;
+ if( g_RageQuitScorePenalty.integer == 0 ) return;
+ if( ent->client->pers.admin && level.numAlienClients >= g_AutoLevelMinTeamSize.integer && level.numHumanClients >= g_AutoLevelMinTeamSize.integer ) {
+ a = ent->client->pers.admin;
+ l = G_admin_find_level_for_score( a->score );
+ if( g_RageQuitScorePenalty.integer < 0 ) {
+ a->score = l->score;
+ admin_log( va( "score reset: %d (%s) \"%s" S_COLOR_WHITE "\"", a->level, a->guid, a->name ) );
+ AP( va("print \"^3score: ^7%s^7 score advance towards next level reset due to rage quit.\n\"",
+ a->name ) );
+ } else {
+ a->score -= g_RageQuitScorePenalty.integer;
+ if( a->score < l->score ) a->score = l->score;
+ admin_log( va( "score penalty: %d (%s) \"%s" S_COLOR_WHITE "\"", a->level, a->guid, a->name ) );
+ AP( va("print \"^3score: ^7%s^7 score penalty of %d total score due to rage quit.\n\"",
+ a->name, g_RageQuitScorePenalty.integer ) );
+ }
+ admin_writeconfig();
+ }
+}
+
qboolean G_admin_buildlog( gentity_t *ent )
{
char search[ MAX_NAME_LENGTH ] = {""};
@@ -4273,7 +4391,6 @@ void G_admin_buffer_print( gentity_t *ent, char *m )
Q_strcat( g_bfb, sizeof( g_bfb ), m );
}
-
void G_admin_cleanup( void )
{
g_admin_level_t *l;
@@ -4282,6 +4399,9 @@ void G_admin_cleanup( void )
g_admin_command_t *c;
void *n;
+ // Always save current data before cleanup so we won't lose the accumulated scores.
+ if ( g_admin_levels ) admin_writeconfig( );
+
for( l = g_admin_levels; l; l = n )
{
n = l->next;
diff --git a/src/game/g_admin.h b/src/game/g_admin.h
index 04da54e..ccdb01e 100644
--- a/src/game/g_admin.h
+++ b/src/game/g_admin.h
@@ -95,6 +95,7 @@ typedef struct g_admin_level
{
struct g_admin_level *next;
int level;
+ int score; // total score required for automatically gaining this level, -1 for disabled
char name[ MAX_NAME_LENGTH ];
char flags[ MAX_ADMIN_FLAGS ];
}
@@ -104,6 +105,7 @@ typedef struct g_admin_admin
{
struct g_admin_admin *next;
int level;
+ int score; // total score the player currently has
char guid[ 33 ];
char name[ MAX_NAME_LENGTH ];
char flags[ MAX_ADMIN_FLAGS ];
@@ -190,11 +192,15 @@ qboolean G_admin_admintest( gentity_t *ent );
qboolean G_admin_allready( gentity_t *ent );
qboolean G_admin_endvote( gentity_t *ent );
qboolean G_admin_spawn( gentity_t *ent );
+g_admin_level_t *G_admin_find_level_for_score( int score );
+void G_admin_add_score( gentity_t *ent, int score );
+void G_admin_reset_score( gentity_t *ent );
qboolean G_admin_spec999( gentity_t *ent );
qboolean G_admin_rename( gentity_t *ent );
qboolean G_admin_restart( gentity_t *ent );
qboolean G_admin_nextmap( gentity_t *ent );
qboolean G_admin_namelog( gentity_t *ent );
+qboolean G_admin_score_info( gentity_t *ent );
qboolean G_admin_lock( gentity_t *ent );
qboolean G_admin_pause( gentity_t *ent );
qboolean G_admin_builder( gentity_t *ent );
@@ -204,6 +210,8 @@ qboolean G_admin_flaglist( gentity_t *ent );
qboolean G_admin_flag( gentity_t *ent );
qboolean G_admin_slap( gentity_t *ent );
+g_admin_level_t *G_admin_level( const int l );
+g_admin_level_t *G_admin_level_next( g_admin_level_t *level );
void G_admin_print( gentity_t *ent, char *m );
void G_admin_buffer_print( gentity_t *ent, char *m );
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index f865d93..fa6b6c9 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -3637,6 +3637,7 @@ commands_t cmds[ ] = {
{ "m", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
{ "maplog", CMD_MESSAGE|CMD_INTERMISSION, Cmd_MapLog_f },
{ "mt", CMD_MESSAGE|CMD_INTERMISSION, Cmd_PrivateMessage_f },
+ { "myscore", 0, Cmd_MyScore_f },
{ "noclip", CMD_CHEAT_TEAM, Cmd_Noclip_f },
{ "notarget", CMD_CHEAT|CMD_TEAM|CMD_LIVING, Cmd_Notarget_f },
{ "reload", CMD_HUMAN|CMD_LIVING, Cmd_Reload_f },
@@ -3812,6 +3813,24 @@ void G_UnEscapeString( char *in, char *out, int len )
*out = '\0';
}
+void Cmd_MyScore_f( gentity_t *ent )
+{
+ g_admin_level_t *n;
+ if ( !ent || !ent->client->pers.admin ) {
+ ADMP( "This command is only available for registered players.\n" );
+ return;
+ }
+ if ( n = G_admin_level_next( G_admin_level( ent->client->pers.admin->level ) ) ) {
+ ADMP( va( "^7Level %d (%s^7) total score earned: %d next level: %d\n",
+ ent->client->pers.admin->level, G_admin_level( ent->client->pers.admin->level )->name,
+ ent->client->pers.admin->score, n->score ) );
+ } else {
+ ADMP( va( "^7Level %d (%s^7) total score earned: %d (max level)\n",
+ ent->client->pers.admin->level, G_admin_level( ent->client->pers.admin->level )->name,
+ ent->client->pers.admin->score ) );
+ }
+}
+
void Cmd_PrivateMessage_f( gentity_t *ent )
{
int pids[ MAX_CLIENTS ];
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index ada2f9c..87a6bd6 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -55,6 +55,9 @@ void AddScore( gentity_t *ent, int score )
score = rint( ((float)score) / 50.0f );
ent->client->ps.persistant[ PERS_SCORE ] += score;
+
+ G_admin_add_score( ent, score );
+
CalculateRanks( );
}
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 5ee2623..2163df4 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -353,6 +353,9 @@ typedef struct
addr_t ip;
char voice[ MAX_VOICE_NAME_LEN ];
qboolean useUnlagged;
+
+ // team change tracking
+ team_t newTeam;
// keep track of other players' info for tinfo
char cinfo[ MAX_CLIENTS ][ 16 ];
} clientPersistant_t;
@@ -760,6 +763,7 @@ void G_Say( gentity_t *ent, saymode_t mode, const char *chatText );
void G_DecolorString( char *in, char *out, int len );
void G_UnEscapeString( char *in, char *out, int len );
void G_SanitiseString( char *in, char *out, int len );
+void Cmd_MyScore_f( gentity_t *ent );
void Cmd_PrivateMessage_f( gentity_t *ent );
void Cmd_ListMaps_f( gentity_t *ent );
void Cmd_ListEmoticons_f( gentity_t *ent );
@@ -1288,6 +1292,8 @@ extern vmCvar_t g_ConstantRewardFactor;
extern vmCvar_t g_TeamRewardFactor;
extern vmCvar_t g_PlayerRewardFactor;
extern vmCvar_t g_ForceRandomTeams;
+extern vmCvar_t g_AutoLevelMinTeamSize;
+extern vmCvar_t g_RageQuitScorePenalty;
void trap_Print( const char *fmt );
void trap_Error( const char *fmt );
diff --git a/src/game/g_main.c b/src/game/g_main.c
index afbd986..965fdc0 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -195,6 +195,8 @@ vmCvar_t g_PlayerRewardFactor;
vmCvar_t g_TimerPeriod;
vmCvar_t g_TimerCommand;
vmCvar_t g_ForceRandomTeams;
+vmCvar_t g_AutoLevelMinTeamSize;
+vmCvar_t g_RageQuitScorePenalty;
// copy cvars that can be set in worldspawn so they can be restored later
static char cv_gravity[ MAX_CVAR_VALUE_STRING ];
@@ -359,7 +361,9 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_PlayerRewardFactor, "g_PlayerRewardFactor", "0.25", CVAR_ARCHIVE, 0, qfalse },
{ &g_TimerPeriod, "g_TimerPeriod", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_TimerCommand, "g_TimerCommand", "", CVAR_ARCHIVE, 0, qfalse },
- { &g_ForceRandomTeams, "g_ForceRandomTeams", "0", CVAR_ARCHIVE, 0, qfalse }
+ { &g_ForceRandomTeams, "g_ForceRandomTeams", "0", CVAR_ARCHIVE, 0, qfalse },
+ { &g_AutoLevelMinTeamSize, "g_AutoLevelMinTeamSize", "3", CVAR_ARCHIVE, 0, qfalse },
+ { &g_RageQuitScorePenalty, "g_RageQuitScorePenalty", "2000", CVAR_ARCHIVE, 0, qfalse }
};
static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] );
void G_InitGame( int levelTime, int randomSeed, int restart );
diff --git a/src/game/g_team.c b/src/game/g_team.c
index e8a79db..6ffac38 100644
--- a/src/game/g_team.c
+++ b/src/game/g_team.c
@@ -172,12 +172,17 @@ void G_LeaveTeam( gentity_t *self )
gentity_t *ent;
int i;
- if( team == TEAM_ALIENS )
+ if( team == TEAM_ALIENS ) {
G_RemoveFromSpawnQueue( &level.alienSpawnQueue, self->client->ps.clientNum );
- else if( team == TEAM_HUMANS )
+ if ( ( self->client->pers.newTeam == TEAM_NONE ) && !level.intermissiontime ) {
+ G_admin_reset_score( self );
+ }
+ } else if( team == TEAM_HUMANS ) {
G_RemoveFromSpawnQueue( &level.humanSpawnQueue, self->client->ps.clientNum );
- else
- {
+ if ( ( self->client->pers.newTeam == TEAM_NONE ) && !level.intermissiontime ) {
+ G_admin_reset_score( self );
+ }
+ } else {
if( self->client->sess.spectatorState == SPECTATOR_FOLLOW )
G_StopFollowing( self );
return;
@@ -189,10 +194,6 @@ void G_LeaveTeam( gentity_t *self )
G_Vote( self, team, qfalse );
self->suicideTime = 0;
-
-
-
-
for( i = 0; i < level.num_entities; i++ )
{
ent = &g_entities[ i ];
@@ -213,21 +214,17 @@ void G_LeaveTeam( gentity_t *self )
// cut all relevant zap beams
G_ClearPlayerZapEffects( self );
- // cure infection
- if( ent->client->ps.stats[ STAT_STATE ] & SS_INFECTED &&
- ent->client->lastInfectionClient == self )
- ent->client->ps.stats[ STAT_STATE ] &= ~SS_INFECTED;
-
- else if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number )
- G_FreeEntity( ent );
+ // cure infection
+ if( ent->client->ps.stats[ STAT_STATE ] & SS_INFECTED &&
+ ent->client->lastInfectionClient == self )
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_INFECTED;
-
-
-
-
-
- G_namelog_update_score( self->client );
+ else if( ent->s.eType == ET_MISSILE && ent->r.ownerNum == self->s.number )
+ G_FreeEntity( ent );
+ G_namelog_update_score( self->client );
+
+ ent->client->pers.newTeam = TEAM_NONE;
}
/*
@@ -242,12 +239,15 @@ void G_ChangeTeam( gentity_t *ent, team_t newTeam )
if( oldTeam == newTeam )
return;
+ ent->client->pers.newTeam = newTeam;
G_LeaveTeam( ent );
+ ent->client->pers.newTeam = TEAM_NONE;
+
ent->client->pers.teamChangeTime = level.time;
ent->client->pers.teamSelection = newTeam;
ent->client->pers.classSelection = PCL_NONE;
ClientSpawn( ent, NULL, NULL, NULL );
-
+
if( oldTeam == TEAM_HUMANS && newTeam == TEAM_ALIENS )
{
// Convert from human to alien credits