diff options
author | Mikko Tiusanen <ams@daug.net> | 2014-10-15 21:16:06 +0300 |
---|---|---|
committer | Mikko Tiusanen <ams@daug.net> | 2014-10-15 21:16:06 +0300 |
commit | 8268afc55026f70cd21a7941e1228cfd9adeb0a8 (patch) | |
tree | 2439ce84a6ae39f40cf0a460db87036597a2d969 | |
parent | cb6e022bb7aadf56d4f7ebc136f652fc18fbc44e (diff) |
Added automatic levels functionality based on total score earned of each player.
-rw-r--r-- | src/game/g_admin.c | 122 | ||||
-rw-r--r-- | src/game/g_admin.h | 8 | ||||
-rw-r--r-- | src/game/g_cmds.c | 19 | ||||
-rw-r--r-- | src/game/g_combat.c | 3 | ||||
-rw-r--r-- | src/game/g_local.h | 6 | ||||
-rw-r--r-- | src/game/g_main.c | 6 | ||||
-rw-r--r-- | src/game/g_team.c | 44 |
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 |