AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
|
03-30-2021
, 21:52
Re: Efficiency & Accuracy Modification
|
#14
|
This will disconnect players at round end when accuracy and/or efficiency is outside of the acceptable value. You may want to rethink this a bit and add more conditions. If a player decides to spray for the fun of it, there's a possibility he will be disconnected at round end due to his accuracy, depending on how much time he's spent on the server. You want to motivate people to play on your server, not punish them for choosing your server. What type of activity are you aiming to eliminate from your server?
cvars:
sm_maxefficiency - Max efficiency before getting kicked - default: 50
sm_minaccuracy - Min accuracy before getting kicked - default: 20
sm_minrounds - Minimum rounds before plugin may kick/reset you - default: 5
sm_minshots - Minimum shots fired before plugin may kick/reset you - default: 100
sm_minkillsdeaths = Minimum kills+deaths before plugin may kick/reset you - default: 5
PHP Code:
#include <amxmodx> #include <fakemeta> #include <hamsandwich> #include <cstrike> #include <nvault_util> #include <nvault_array> #include <csx>
new const Version[] = "0.3";
#if AMXX_VERSION_NUM >= 190 #define client_disconnect client_disconnected #endif
//#define TESTING
#define MAX_PLAYERS 32
new const VaultName[] = "stats_moderator"; const MaxRanked = 1000;
#if AMXX_VERSION_NUM <= 181 new g_fwid , g_max_clients , g_guns_eventids_bitsum;
new const g_guns_events[][] = { "events/awp.sc", "events/g3sg1.sc", "events/ak47.sc", "events/scout.sc", "events/m249.sc", "events/m4a1.sc", "events/sg552.sc", "events/aug.sc", "events/sg550.sc", "events/m3.sc", "events/xm1014.sc", "events/usp.sc", "events/mac10.sc", "events/ump45.sc", "events/fiveseven.sc", "events/p90.sc", "events/deagle.sc", "events/p228.sc", "events/glock18.sc", "events/mp5n.sc", "events/tmp.sc", "events/elite_left.sc", "events/elite_right.sc", "events/galil.sc", "events/famas.sc" }; #endif
enum PlayerStats { Stats_Kills = 0, Stats_Deaths, Stats_Headshots, Stats_TeamKills, Stats_Shots, Stats_Hits, Stats_Damage, Stats_RoundsPlayed }
enum BodyHits { Hit_Generic = 0, Hit_Head, Hit_Chest, Hit_Stomach, Hit_LeftArm, Hit_RightArm, Hit_LeftLeg, Hit_RightLeg }
enum StatsData { sdName[ 33 ], sdAuthID[ 35 ], sdStats[ PlayerStats ], sdHits[ BodyHits ] }
new g_sdData[ MAX_PLAYERS + 1 ][ StatsData ]; new g_Vault new g_pMaxEfficiency , g_pMinAccuracy , g_pMinRounds , g_pMinShots , g_pMinKillsDeaths;
public plugin_init() { register_plugin( "Stats Moderator" , Version , "bugsy" ); register_clcmd( "say rank" , "ShowRank" ); register_clcmd( "say topten" , "ShowTopTen" ); register_concmd( "resetstats" , "ResetStats" ); g_pMaxEfficiency = register_cvar( "sm_maxefficiency" , "50" ); g_pMinAccuracy = register_cvar( "sm_minaccuracy" , "20" ); g_pMinRounds = register_cvar( "sm_minrounds" , "5" ); g_pMinShots = register_cvar( "sm_minshots" , "100" ); g_pMinKillsDeaths = register_cvar( "sm_minkillsdeaths" , "5" ); register_event( "DeathMsg" , "DeathMsg" , "a" ); register_logevent( "RoundEnd" , 2 , "1=Round_End" ); RegisterHam( Ham_TakeDamage , "player" , "PlayerTakeDamage" ); if ( ( g_Vault = nvault_open( VaultName ) ) == INVALID_HANDLE ) { set_fail_state( "Failed to open vault" ); } #if AMXX_VERSION_NUM > 181 for ( new szWeapon[ 20 ], iWeaponID = CSW_P228 ; iWeaponID <= CSW_P90 ; iWeaponID++ ) { if ( get_weaponname( iWeaponID , szWeapon , charsmax( szWeapon ) ) ) { RegisterHam( Ham_Weapon_PrimaryAttack , szWeapon , "WeaponPrimaryAttack" , true ); } } #else unregister_forward(FM_PrecacheEvent, g_fwid, 1); register_forward(FM_PlaybackEvent, "fwPlaybackEvent"); g_max_clients = global_get(glb_maxClients); #endif }
#if AMXX_VERSION_NUM <= 181 public plugin_precache() { g_fwid = register_forward(FM_PrecacheEvent, "fwPrecacheEvent", 1) } #endif
public plugin_end() { nvault_close( g_Vault ); }
public client_authorized( id ) { if ( !is_user_bot( id ) ) { get_user_authid( id , g_sdData[ id ][ sdAuthID ] , charsmax( g_sdData[][ sdAuthID ] ) ); nvault_get_array( g_Vault , g_sdData[ id ][ sdAuthID ] , g_sdData[ id ][ StatsData:0 ] , sizeof( g_sdData[] ) ); get_user_name( id , g_sdData[ id ][ sdName ] , charsmax( g_sdData[][ sdName ] ) ); if ( !g_sdData[ id ][ sdAuthID ][ 0 ] ) get_user_authid( id , g_sdData[ id ][ sdAuthID ] , charsmax( g_sdData[][ sdAuthID ] ) ); } }
public client_disconnect( id ) { if ( !is_user_bot( id ) ) { nvault_set_array( g_Vault , g_sdData[ id ][ sdAuthID ] , g_sdData[ id ][ StatsData:0 ] , sizeof( g_sdData[] ) ); } }
public DeathMsg() { new iKiller = read_data( 1 ); new iVictim = read_data( 2 ); g_sdData[ iKiller ][ sdStats ][ Stats_Kills ]++; g_sdData[ iVictim ][ sdStats ][ Stats_Deaths ]++; g_sdData[ iKiller ][ sdStats ][ Stats_Headshots ] += read_data( 3 ); g_sdData[ iKiller ][ sdStats ][ Stats_TeamKills ] += _:( cs_get_user_team( iKiller ) == cs_get_user_team( iVictim ) ); #if defined TESTING server_print( "Kills=%d Deaths=%d HS=%d TK=%d" , g_sdData[ iKiller ][ sdStats ][ Stats_Kills ] , g_sdData[ iKiller ][ sdStats ][ Stats_Deaths ] , g_sdData[ iKiller ][ sdStats ][ Stats_Headshots ] , g_sdData[ iKiller ][ sdStats ][ Stats_TeamKills ] ); #endif }
public RoundEnd() { new iPlayers[ 32 ] , iNum; get_players( iPlayers , iNum , "ch" ); for ( new i = 0 , id ; i < iNum ; i++ ) { id = iPlayers[ i ]; g_sdData[ id ][ sdStats ][ Stats_RoundsPlayed ]++; CheckPlayer( id ); } }
public WeaponPrimaryAttack( iEntity ) { static const m_iClientClip = 52; static const XO_WEAPON = 4; if ( pev_valid( iEntity ) && ( cs_get_weapon_ammo( iEntity ) != get_pdata_int( iEntity , m_iClientClip , XO_WEAPON ) ) ) { g_sdData[ pev( iEntity , pev_owner ) ][ sdStats ][ Stats_Shots ]++; #if defined TESTING server_print( "Shots=%d" , g_sdData[ pev( iEntity , pev_owner ) ][ sdStats ][ Stats_Shots ] ); #endif } }
public PlayerTakeDamage( iVictim , iInflictor , iAttacker , Float:fDamage , DamageBits ) { static const m_LastHitGroup = 75; if ( iAttacker ) { g_sdData[ iAttacker ][ sdStats ][ Stats_Hits ]++; g_sdData[ iAttacker ][ sdStats ][ Stats_Damage ] += floatround( fDamage ); g_sdData[ iAttacker ][ sdHits ][ BodyHits:get_pdata_int( iVictim , m_LastHitGroup ) ]++; #if defined TESTING server_print( "Hits=%d Damage=%d Hits=%d %d %d %d %d %d %d %d" , g_sdData[ iAttacker ][ sdStats ][ Stats_Hits ] , g_sdData[ iAttacker ][ sdStats ][ Stats_Damage ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:0 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:1 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:2 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:3 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:4 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:5 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:6 ] , g_sdData[ iAttacker ][ sdHits ][ BodyHits:7 ] ); #endif } }
#if AMXX_VERSION_NUM <= 181 public fwPrecacheEvent(type, const name[]) { for (new i = 0; i < sizeof g_guns_events; ++i) { if (equal(g_guns_events[i], name)) { g_guns_eventids_bitsum |= (1<<get_orig_retval()) return FMRES_HANDLED } } return FMRES_IGNORED }
public fwPlaybackEvent( flags , invoker , eventid ) { if ( !( g_guns_eventids_bitsum & ( 1 << eventid ) ) || !( 1 <= invoker <= g_max_clients ) ) return FMRES_IGNORED; g_sdData[ invoker ][ sdStats ][ Stats_Shots ]++; #if defined TESTING server_print( "Shots=%d" , g_sdData[ pev( iEntity , pev_owner ) ][ sdStats ][ Stats_Shots ] ); #endif return FMRES_HANDLED } #endif
public ShowTopTen( id ) { enum _:Top10Data { nVault_Offset, Rank_Value } static szTop10[ 1536 ]; static iRankData[ MaxRanked ][ Top10Data ]; new sdData[ StatsData ] , iCurrentOffset , iNextOffset; new iVault , iCount , iPos , iAvailablePlayers; SaveConnectedPlayerData(); nvault_close( g_Vault ); if ( ( g_Vault = nvault_open( VaultName ) ) == INVALID_HANDLE ) set_fail_state( "Error opening vault." ); iVault = nvault_util_open( VaultName ); iCount = nvault_util_count( iVault ); if ( !iCount ) { client_print( id , print_chat , "* No players are ranked yet." ); return PLUGIN_HANDLED; } for ( new iRow = 0 ; iRow < iCount && iRow < MaxRanked ; iRow++ ) { iNextOffset = nvault_util_read_array( iVault , iNextOffset , "" , 0 , sdData[ StatsData:0 ] , sizeof( sdData ) ); iRankData[ iRow ][ nVault_Offset ] = iCurrentOffset; iRankData[ iRow ][ Rank_Value ] = ( sdData[ sdStats ][ Stats_Kills ] - sdData[ sdStats ][ Stats_Deaths ] );
iCurrentOffset = iNextOffset; } SortCustom2D( iRankData , min( iCount , MaxRanked ) , "SortCompare" ); iPos += copy( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "<html><style>body { background-color:#000000; }.tabel { color:#FFB000; }.header { background-color:#3d3c23; color:#FFB000;}</style><body>"); iPos += copy( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "<br><br><table align=center border=1 width=90% class=tabel>"); iPos += copy( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "<tr><td class=header width=5% align=center>#</td><td class=header width=20%>Name</td><td class=header width=10%>Kills</td>" ); iPos += copy( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "<td class=header width=10%>Deaths</td><td class=header width=10%>HeadShots</td><td class=header width=10%>Efficiency</td><td class=header width=10%>Accuracy</td></tr>"); iAvailablePlayers = min( iCount , 10 );
for ( new i = 0 ; i < iAvailablePlayers ; i++ ) { nvault_util_read_array( iVault , iRankData[ i ][ nVault_Offset ] , "" , 0 , sdData[ StatsData:0 ] , sizeof( sdData ) ); iPos += formatex( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "<tr><td>%d</td><td>%s</td><td>%d</td><td>%d</td><td>%d</td><td>%0.2f</td><td>%0.2f</td></tr>" , i+1 , sdData[ sdName ] , sdData[ sdStats ][ Stats_Kills ] , sdData[ sdStats ][ Stats_Deaths ] , sdData[ sdStats ][ Stats_Headshots ] , GetEfficiency( sdData ) , GetAccuracy( sdData ) ); } iPos += copy( szTop10[ iPos ] , charsmax( szTop10 ) - iPos , "</table></body></html>" ); nvault_util_close( iVault );
show_motd( id , szTop10 , "Top Ten" ); return PLUGIN_HANDLED; }
public ShowRank( id ) { enum _:RankData { AuthID[ 34 ], Rank_Value } static iRankData[ MaxRanked ][ RankData ]; new sdData[ StatsData ] , iOffset; new iVault , iCount , iRow , iRank; SaveConnectedPlayerData(); nvault_close( g_Vault ); if ( ( g_Vault = nvault_open( VaultName ) ) == INVALID_HANDLE ) set_fail_state( "Error opening vault." ); iVault = nvault_util_open( VaultName ); iCount = nvault_util_count( iVault ); if ( !iCount ) { client_print( id , print_chat , "* No players are ranked yet." ); return PLUGIN_HANDLED; } for ( iRow = 0 ; iRow < iCount && iRow < MaxRanked ; iRow++ ) { iOffset = nvault_util_read_array( iVault , iOffset , "" , 0 , sdData[ StatsData:0 ] , sizeof( sdData ) ); copy( iRankData[ iRow ][ AuthID ] , charsmax( iRankData[][ sdAuthID ] ) , sdData[ sdAuthID ] ); iRankData[ iRow ][ Rank_Value ] = ( sdData[ sdStats ][ Stats_Kills ] - sdData[ sdStats ][ Stats_Deaths ] ); } nvault_util_close( iVault ); SortCustom2D( _:iRankData , min( iCount , MaxRanked ) , "SortCompare" ); for ( iRow = 0 ; iRow < iCount && iRow < MaxRanked ; iRow++ ) { if ( equal( iRankData[ iRow ][ AuthID ] , g_sdData[ id ][ sdAuthID ] ) ) { iRank = ( iRow + 1 ); break; } } if ( iRank == 0 ) { client_print( id , print_chat , "* You are not yet ranked." ); } else { nvault_get_array( g_Vault , iRankData[ iRow ][ AuthID ] , sdData[ StatsData:0 ] , sizeof( sdData ) ); client_print( id , print_chat , "* %s, your rank is %d, with %d kills, %d deaths, and %d headshots" , sdData[ sdName ] , iRank , sdData[ sdStats ][ Stats_Kills ] , sdData[ sdStats ][ Stats_Deaths ] , sdData[ sdStats ][ Stats_Headshots ] ); client_print( id , print_chat , "* Efficiency: %0.2f - Accuracy: %0.2f - %d Shots - %d Hits" , GetEfficiency( sdData ) , GetAccuracy( sdData ) , sdData[ sdStats ][ Stats_Shots ] , sdData[ sdStats ][ Stats_Hits ] ); } return PLUGIN_HANDLED; }
public SortCompare( elem1[] , elem2[] ) { if ( elem1[ 1 ] > elem2[ 1 ] ) return -1; else if(elem1[ 1 ] < elem2[ 1 ] ) return 1; else return 0; }
public ResetStats( id , level , cid ) { if ( cmd_access( id , level , cid , 0 ) ) { nvault_prune( g_Vault , 0 , get_systime() ); for ( new i = 1 ; i <= MAX_PLAYERS ; i++ ) { arrayset( g_sdData[ id ][ sdStats ] , 0 , sizeof( g_sdData[][ sdStats ] ) ); arrayset( g_sdData[ id ][ sdHits ] , 0 , sizeof( g_sdData[][ sdHits ] ) ); } } }
CheckPlayer( id ) { new Float:fMinAccuracy = get_pcvar_float( g_pMinAccuracy ); new Float:fMaxEfficiency = get_pcvar_float( g_pMaxEfficiency ); new szMsg[ 128 ]; if ( MeetsMinThresholds( id ) && ( ( GetEfficiency( g_sdData[ id ] ) >= fMaxEfficiency ) || ( GetAccuracy( g_sdData[ id ] ) <= fMinAccuracy ) ) ) { nvault_remove( g_Vault , g_sdData[ id ][ sdAuthID ] ); arrayset( g_sdData[ id ][ sdStats ] , 0 , sizeof( g_sdData[][ sdStats ] ) ); arrayset( g_sdData[ id ][ sdHits ] , 0 , sizeof( g_sdData[][ sdHits ] ) ); formatex( szMsg , charsmax( szMsg ) , "Stats are outside of thresholds:^n Accuracy must be higher than %0.2f^n Efficiency must be less than %0.2f" , fMinAccuracy , fMaxEfficiency ); message_begin( MSG_ONE_UNRELIABLE , SVC_DISCONNECT , _, id ); write_string( szMsg ); message_end(); } }
SaveConnectedPlayerData() { new iPlayers[ 32 ] , iNum; get_players( iPlayers , iNum , "ch" ); for ( new i = 0 , id ; i < iNum ; i++ ) { id = iPlayers[ i ]; nvault_set_array( g_Vault , g_sdData[ id ][ sdAuthID ] , g_sdData[ id ][ StatsData:0 ] , sizeof( g_sdData[] ) ); } }
bool:MeetsMinThresholds( id ) { return bool:( ( g_sdData[ id ][ sdStats ][ Stats_RoundsPlayed ] >= get_pcvar_num( g_pMinRounds ) ) && ( g_sdData[ id ][ sdStats ][ Stats_Shots ] >= get_pcvar_num( g_pMinShots ) ) && ( ( g_sdData[ id ][ sdStats ][ Stats_Kills ] + g_sdData[ id ][ sdStats ][ Stats_Deaths ] ) >= get_pcvar_num( g_pMinKillsDeaths ) ) ); }
Float:GetAccuracy( sdData[ StatsData ] ) { return sdData[ sdStats ][ Stats_Shots ] ? ( 100.0 * float( sdData[ sdStats ][ Stats_Hits ] ) / float(sdData[ sdStats ][ Stats_Shots ] ) ) : ( 0.0 ); }
Float:GetEfficiency( sdData[ StatsData ] ) { return sdData[ sdStats ][ Stats_Kills ] ? ( 100.0 * float( sdData[ sdStats ][ Stats_Kills ] ) / float( sdData[ sdStats ][ Stats_Kills ] + sdData[ sdStats ][ Stats_Deaths ] ) ) : ( 0.0 ); }
__________________
Last edited by Bugsy; 04-03-2021 at 10:39.
|
|