diff options
| -rw-r--r-- | src/game/g_admin.c | 395 | ||||
| -rw-r--r-- | src/game/g_admin.h | 19 | ||||
| -rw-r--r-- | src/game/g_local.h | 2 | ||||
| -rw-r--r-- | src/game/g_main.c | 4 | 
4 files changed, 419 insertions, 1 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 422b3c1..a4006ea 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -404,6 +404,23 @@ g_admin_cmd_t g_admin_cmds[ ] =      {"setrotation", G_admin_setrotation, "setrotation",        "sets the map rotation",        "[^3rotation^7]" +    }, + +    {"versions", G_admin_versions, "namelog", +     "Check what versions of Tremulous players are running.", +     "" +    }, + +    {"showff", G_admin_showff, "showff", +      "shows how much friendly damage a player has done this game" +      "\nno arguments will list all connected players", +      "(^3name|slot^7)" +      "\n ^3Example:^7 ^120% ^7means 1/5th of the damage dealt this game was dealt to the team" +    }, + +    {"tklog", G_admin_tklog, "tklog", +      "list recent teamkill activity", +      "(^5start id#|name|-skip#^7) (^5search skip#^7)"      }    }; @@ -454,6 +471,9 @@ static qboolean admin_permission( char *flags, const char *flag, qboolean *perm  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 ]; +  // 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 ) @@ -7789,3 +7809,378 @@ qboolean G_admin_setrotation(gentity_t *ent, int skiparg)    }    return qfalse;  } + +qboolean G_admin_versions(gentity_t *ent, int skiparg) +{ +	int i; + +	ADMBP_begin(); + +	for (i = 0; i < level.maxclients; i++) { +		gclient_t *client = level.clients + i; +		char userinfo[ MAX_INFO_STRING ], *p; + +		if (client->pers.connected == CON_DISCONNECTED) +			continue; + +		ADMBP(va("%02i ", i)); + +		trap_GetUserinfo(i, userinfo, sizeof(userinfo)); +		p = Info_ValueForKey(userinfo, "version"); + +		if (p[0]) +			ADMBP(va("'%s'\n", p)); +		else { +			p = Info_ValueForKey(userinfo, "cl_voip"); + +			if (p[0]) +				ADMBP("probably GPP or newer\n"); +			else +				ADMBP("probably stock 1.1\n"); +		} +	} + +	ADMBP_end(); +	return qtrue; +} + +static int calc_ff_pct(statsCounters_t *sc) { +	if (sc->dmgdone + sc->structdmgdone <= 0) { +		if (sc->ffdmgdone <= 0) +			return 0; +		else +			return 100; +	} // else { +		// return round((float)sc->ffdmgdone / (sc->ffdmgdone + sc->dmgdone + sc->structdmgdone) * 100); +	// } +} + +qboolean G_admin_showff(gentity_t *ent, int skiparg) +{ +	char arg_name_raw[MAX_NAME_LENGTH]; +	char arg_name[MAX_NAME_LENGTH]; +	int target_id, ffpct; +	gentity_t *target; +	statsCounters_t *sc; + +	if (G_SayArgc() == 1 + skiparg) { +		int i; +		char team[4]; +		gclient_t *client; + +		ADMBP_begin(); +		ADMBP("^3!showff:^7 friendly fire damage percentage for all connected players\n"); + +		for (i = 0; i < level.maxclients; i++) {  +			client = &level.clients[i]; + +			if (client->pers.connected != CON_CONNECTED) +				continue; + +			if (client->pers.teamSelection == PTE_HUMANS) +				Com_sprintf( team, sizeof( team ), "^4H", team); +			else if (client->pers.teamSelection == PTE_ALIENS) +				Com_sprintf( team, sizeof( team ), "^1A", team); +			else +				Com_sprintf( team, sizeof( team ), "^3S", team); + +			ffpct = calc_ff_pct(&client->pers.statscounters); +			ADMBP(va("%2d %s ^1%3d%% ^7%s^7\n", i, team, ffpct, client->pers.netname)); +		} + +		ADMBP("^7for detailed information, use ^3!showff player|slot^7\n"); +		ADMBP_end(); +		return qtrue; +	} + +	G_SayArgv(1 + skiparg, arg_name_raw, sizeof(arg_name_raw)); +	G_SanitiseString(arg_name_raw, arg_name, sizeof(arg_name)); + +	if (is_numeric(arg_name)) { +		target_id = atoi(arg_name); + +		if (target_id < 0 || target_id >= MAX_CLIENTS) { +			ADMP(va("^3!showff: ^7invalid client number\n")); +			return qfalse; +		} +	} else { +		int pids[MAX_CLIENTS]; + +		if (G_ClientNumbersFromString(arg_name, pids) != 1) { +			char error[MAX_STRING_CHARS]; + +			G_MatchOnePlayer(pids, error, sizeof(error)); +			ADMP(va("^3!showff: ^7%s\n", error)); +			return qfalse; +		} + +		target_id = pids[0]; +	} + +	target = g_entities + target_id; +	sc     = &target->client->pers.statscounters; +	ffpct  = calc_ff_pct(sc); + +	ADMP(va("^3!showff: ^7detailed FF information for %s^7:\n", +	        target->client->pers.netname)); +	ADMP(va("^7damage to: Enemies: ^1%d^7, structures: ^1%d^7, friendlies: ^1%d\n", +	        sc->dmgdone, sc->structdmgdone, sc->ffdmgdone)); +	ADMP(va("dealt ^1%d%%^7 of their total damage to the team\n", ffpct)); + +	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 + (int)( 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; +} diff --git a/src/game/g_admin.h b/src/game/g_admin.h index 24a256e..177d7e3 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  #define MAX_ADMIN_CMD_LEN 20  #define MAX_ADMIN_BAN_REASON 50  #define MAX_ADMIN_BANSUSPEND_DAYS 14 +#define MAX_ADMIN_TKLOGS 64  /*   * IMMUNITY - cannot be vote kicked, vote muted @@ -190,6 +191,19 @@ typedef struct g_admin_adminlog  }  g_admin_adminlog_t; +typedef struct g_admin_tklog +{ +  char      name[ MAX_NAME_LENGTH ]; +  char      victim[ MAX_NAME_LENGTH ]; +  int       id; +  int       time; +  int       damage; +  int       value; +  int       team; +  int       weapon; +} +g_admin_tklog_t; +  qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen );  qboolean G_admin_cmd_check( gentity_t *ent, qboolean say );  qboolean G_admin_readconfig( gentity_t *ent, int skiparg ); @@ -270,6 +284,11 @@ qboolean G_admin_bubble( gentity_t *ent, int skiparg );  qboolean G_admin_scrim( gentity_t *ent, int skiparg );  qboolean G_admin_give( gentity_t *ent, int skiparg );  qboolean G_admin_setrotation( gentity_t *ent, int skiparg ); +qboolean G_admin_versions( gentity_t *ent, int skiparg ); +qboolean G_admin_showff(gentity_t *ent, int skiparg); +qboolean G_admin_tklog( gentity_t *ent, int skiparg ); +void G_admin_tklog_cleanup( void ); +void G_admin_tklog_log( gentity_t *attacker, gentity_t *victim, int meansOfDeath );  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_local.h b/src/game/g_local.h index c6352cd..61cc3bf 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -361,6 +361,7 @@ typedef struct    int jetpackusewallwalkusetime;    int timeLastViewed;    int AllstatstimeLastViewed; +  int spreebleeds;  } statsCounters_t;  typedef struct @@ -1486,6 +1487,7 @@ extern  vmCvar_t  g_aimbotAdvertBanReason;  extern  vmCvar_t  g_Bubbles;  extern  vmCvar_t  g_scrimMode;  extern  vmCvar_t  g_gradualFreeFunds; +extern  vmCvar_t  g_bleedingSpree;  void      trap_Printf( const char *fmt );  void      trap_Error( const char *fmt ); diff --git a/src/game/g_main.c b/src/game/g_main.c index 19d98ad..856d0d2 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -238,6 +238,7 @@ vmCvar_t  g_aimbotAdvertBanReason;  vmCvar_t  g_Bubbles;  vmCvar_t  g_scrimMode;  vmCvar_t  g_gradualFreeFunds; +vmCvar_t  g_bleedingSpree;  static cvarTable_t   gameCvarTable[ ] =  { @@ -453,7 +454,8 @@ static cvarTable_t   gameCvarTable[ ] =    { &g_Bubbles, "g_Bubbles", "1", CVAR_ARCHIVE, 0, qfalse  },    { &g_scrimMode, "g_scrimMode", "0", CVAR_ARCHIVE, 0, qfalse }, -  { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue  } +  { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue  }, +  { &g_bleedingSpree, "g_bleedingSpree", "0", CVAR_ARCHIVE, 0, qfalse  }  };  static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] );  | 
