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  | 
