From ec79847d3db4a3ab511535cdfda211a6b273b1b8 Mon Sep 17 00:00:00 2001 From: IronClawTrem Date: Fri, 1 Nov 2019 22:16:43 +0000 Subject: add versions, showff and tklog --- src/game/g_admin.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/game/g_admin.h | 19 +++ src/game/g_local.h | 2 + src/game/g_main.c | 4 +- 4 files changed, 419 insertions(+), 1 deletion(-) 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 ] ); -- cgit