mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-26 06:45:37 +03:00
4ab6b083c1
Fixed Condition-Zero support. Replaced Stats with StatsX.
1872 lines
63 KiB
Plaintext
Executable File
1872 lines
63 KiB
Plaintext
Executable File
/************************************************************
|
|
AMX mod X script. Copyright (C) 2002-2004, XAD.
|
|
$Id: statsx.sma, v 0.9.8 2004-Mar-29
|
|
************************************************************/
|
|
|
|
/*************************************************************
|
|
|
|
StatsX AMX-plugin v0.9.8.
|
|
Based on "stats.sma" original written by OLO.
|
|
|
|
This file is provided as is (no warranties).
|
|
|
|
=============================================================
|
|
|
|
Description:
|
|
------------
|
|
This AMX-plugin will display game stats as HUD and chat messages.
|
|
|
|
Example of stats are: killing stats, most damage, best score,
|
|
accuracy, efficiency, attackers list, victims list, team scores.
|
|
|
|
All effeciency stats are calculated per game, not per round.
|
|
The accuracy stats are calculated per round, except for "/score"
|
|
which is per game.
|
|
|
|
Plugin support players switching teams and awarded players
|
|
disconnecting from server before round end. It also supports
|
|
game restart, ie all stats are resetted.
|
|
|
|
Plugin also support players switching of the stats announcements
|
|
on the HUD. The setting is a client parameter and therefore
|
|
saved between playing sessions.
|
|
|
|
|
|
Server Config:
|
|
--------------
|
|
|
|
Duration of HUD-statistics. (Default 12 sec.)
|
|
amx_statsx_duration < time in seconds >
|
|
|
|
HUD-statistics display limit relative round freeze end.
|
|
Negative time will clear the HUD-statstics before the
|
|
round freeze time has ended. (Default -2 sec.)
|
|
amx_statsx_freeze < time in seconds >
|
|
|
|
When activating this plugin the Stats Settings Plugin,
|
|
"statscfg", should also be activated.
|
|
Activating the Stats Settings Plugin allows configuration
|
|
to be done either with client GUI menus or in server
|
|
configuration files.
|
|
amx_statscfg < "on" or "off" > < option >
|
|
|
|
StatsX options:
|
|
"KillerChat" - show killer stats in the chat section
|
|
"ShowAttackers" - show attackers on HUD (deactivated)
|
|
"ShowVictims" - show victims on HUD (deactivated)
|
|
"ShowKiller" - show killer on HUD
|
|
"ShowTeamScore" - shows team score at round end (deactivated)
|
|
"ShowTotalStats" - shows round total stats (deactivated)
|
|
"ShowBestScore" - shows rounds best scored player
|
|
"ShowMostDisruptive"
|
|
- shows rounds most disruptive player
|
|
"EndPlayer" - display player stats MOTD at map end
|
|
"EndTop15" - display top15 MOTD at the end of map
|
|
"SayHP" - allow for say /hp
|
|
"SayStatsMe" - allow for say /statsme
|
|
"SayRankStats" - allow for say /rankstats
|
|
"SayMe" - allow for say /me
|
|
"SayRank" - allow for say /rank
|
|
"SayReport" - allow for say /report
|
|
"SayScore" - allow for say /score
|
|
"SayTop15" - allow for say /top15
|
|
"SayStatsAll" - allow for say /stats
|
|
"SayMiscFunc" - allow for say /timeleft, /thetime,
|
|
/currentmap, /ff
|
|
"ShowStats" - client HUD-stats switched on by default
|
|
"ShowDistHS" - show distance and HS in attackers and
|
|
victims HUD lists
|
|
"SpecRankInfo" - displays rank info when spectating
|
|
|
|
Stats plugin options (flags) to define what to display to
|
|
the clients.
|
|
NOTE! To deactivate all options set flags to " "
|
|
(one quoted space).
|
|
amx_statsx_mode < flags >
|
|
"a" - delay (0.01s) HUD stats on HUD reset
|
|
|
|
|
|
Client Commands:
|
|
----------------
|
|
|
|
Display info about your killer in the chat section.
|
|
say /hp
|
|
|
|
Display info about your stats, on the current map,
|
|
in a MOTD window.
|
|
say /statsme
|
|
|
|
Display your rank stats, in a MOTD window.
|
|
say /rankstats
|
|
|
|
Display your current round hit-stats in the chat section.
|
|
say /me
|
|
|
|
Display your rank in the chat section.
|
|
say /rank
|
|
|
|
Display the game score and stats in the chat section.
|
|
say /score
|
|
|
|
Display players current weapon status, as a say team command.
|
|
say /report
|
|
|
|
Display the 15 highest ranked players in a MOTD window.
|
|
say /top15
|
|
|
|
Display all players stats and rank in a MOTD window. The
|
|
displayed player is selection from a menu.
|
|
say /stats
|
|
|
|
Display time left on the map, as a say command.
|
|
say /timeleft
|
|
|
|
Display the current time, as a say command.
|
|
say /thetime
|
|
|
|
Display the current map, as a say command.
|
|
say /currentmap
|
|
|
|
Display the current status on friendly fire flag,
|
|
as a say command.
|
|
say /ff
|
|
|
|
Switch on or off all HUD-stats announcements ("_amxstatsx").
|
|
say /switch
|
|
|
|
|
|
=============================================================
|
|
|
|
Requirements/Limitations:
|
|
-------------------------
|
|
- AMX Mod X v0.16: Tested.
|
|
- Replaces "stats.amx" by OLO.
|
|
- Requires the AMX module "csstats_amx".
|
|
- You are recommended to not run any other death or
|
|
end-round plugins.
|
|
- If HUD-statistics are activated it is recommended that
|
|
other HUD-messages are deactivated as these otherwise
|
|
will disrupt HUD-statistics, such as PTB's. This is a
|
|
HalfLife-engine limitation.
|
|
- It is not recommended to use "mp_freezetime" less than
|
|
1.0 sec.
|
|
|
|
|
|
Installation:
|
|
-------------
|
|
- Copy the StatsX file "statsx.amx" to the AMX plugins
|
|
folder.
|
|
- In the AMX Mod X plugin configuration file ("plugins.ini"),
|
|
replace the line "stats.amx" with "statsx.amx".
|
|
- Add StatsX cvar to the server or AMX Mod X configuration file.
|
|
If menu configuration will not be used then also add
|
|
the "amx_statscfg" commands to one of the configuration
|
|
files.
|
|
- Restart server. Normally changing map is sufficient but
|
|
restarting the server is the "safe" procedure.
|
|
- If menu configuration is used then reconfigure the
|
|
stats settings using the "amx_statscfgmenu" command.
|
|
|
|
|
|
Tips:
|
|
-----
|
|
NOTE! All statistics collection is done by the module
|
|
"csstats_amx" and questions or issues should be directed
|
|
to the module author.
|
|
|
|
- To reset the player statistics in AMX Mod X 0.16, enter
|
|
"csstats_reset 1" in the server consol. At the next
|
|
mapchange the stats will be reset and the cvar
|
|
"csstats_reset" will be set back to "0". If you put
|
|
this command in the server.cfg the stats will be reset
|
|
at every mapchange.
|
|
- In AMX Mod X 0.16 statistics are by default only saved if the
|
|
difference between kills and deaths are greater than 0.
|
|
|
|
|
|
Comments:
|
|
---------
|
|
This code is based on/parts taken from OLO's stats v0.8.
|
|
- Added "endround" and some other functionality from
|
|
StatsMe 2.7 source code and config files.
|
|
- This plugin has been updated with new functionality
|
|
added to "stats" (by OLO), v0.8 to v0.9.6.
|
|
- New functions and configuration flags have been added.
|
|
- Original "/rank" is changed to "/rankstats".
|
|
- Attackers/victims is displayed before next round end.
|
|
- Last shot and kill included in all stats.
|
|
- Changed HUD number on killer stats to "2" to make
|
|
round end stats work with PTB.
|
|
- All statistics collection is done by the module
|
|
"csstats_mm" and questions or issues should be directed
|
|
to the module author.
|
|
|
|
Money is not supported in "say /report" (requires fun-module).
|
|
|
|
=============================================================
|
|
|
|
Modlog:
|
|
-------
|
|
|
|
0.8 2002-xx-xx OLO Original "stats.sma" version 0.8.
|
|
(c) Copyright 2002, OLO
|
|
This file is provided as is (no waranties).
|
|
0.8a 2002-12-xx XAD First modified version. Added file header.
|
|
0.8c 2002-12-20 XAD First production tested version.
|
|
0.9a 2003-01-23 XAD Recompiled for AMX 0.9.0.
|
|
0.9d 2003-02-14 XAD Added player weapon stats, timeleft, thetime,
|
|
and currentmap.
|
|
0.9e 2003-02-15 XAD Fixed missed friendly fire command registration.
|
|
Fixed divide by zero in best score and most
|
|
disruptive.
|
|
0.9g 2003-02-19 XAD Changed "/rank" to "/rankstats".
|
|
Added a new "/rank" command to report rank as
|
|
chat message.
|
|
Changed "/hp" to be in the chat section instead
|
|
on HUD.
|
|
Fixed some misspellings and changed from "say"
|
|
to server chat.
|
|
Added "/me", your current round stats.
|
|
Added "/switch", client command to disable all
|
|
stats announcements.
|
|
0.9h 2003-02-26 XAD Added player-rank menu (from stats/0.9.2).
|
|
Added config menu (from stats/0.9.3).
|
|
Increased global buffer to 2048 (fix in stats/0.9.3)
|
|
Changed to set tab equal to 4 spaces (from 6).
|
|
0.9i 2003-03-11 XAD Added efficiency and accuracy to top15, stats, and
|
|
rankstats MOTD (thanks Coxton).
|
|
Removed deny message on the non-stats related
|
|
commands so these can be overriden by other scripts.
|
|
0.9i.1 2003-03-20 XAD Fixed bug in "/statsme" (thanks NiLuJe).
|
|
0.9i.2 2003-04-05 XAD Fixed bug in "/statsme" (thanks NiLuJe, doh).
|
|
0.9j 2003-06-05 XAD Support client HUD stats switched off by default,
|
|
mode flag "s" (thanks Troopa).
|
|
Added killing distance to "/me", accuracy and HS-kills
|
|
for each weapons in "/statsme", killing distance and
|
|
HS on victim and killer HUD stats (thanks versus666).
|
|
Added HS-kills to "/statsme" and "/rankstats"
|
|
(thanks Jim66).
|
|
Added team score prediction to remove 0.5 sec. task
|
|
delay on round end stats.
|
|
Changed death-stats to be triggered 0.25 sec. after
|
|
death instead of "late" hit-event, to fix problems
|
|
with 3:rd party modules (thanks server_sgz).
|
|
Added support for HUD statistics over HUD reset with
|
|
time limits relative to the round freeze end.
|
|
Added cvar for HUD time parameters.
|
|
Special thanks to server_sgz for test work.
|
|
0.9.6b 2003-09-12 XAD Adapted to AMX 0.9.6h.
|
|
Added config menu ("statscfg" for AMX 0.9.6) and
|
|
removed old ("statsset" from AMX 0.9.3).
|
|
Changed to html in MOTD (thanks ootoaoo).
|
|
Deactivated victim list, attacker list, team score,
|
|
and total HUD-stats. The killer, best score, most
|
|
disruptive HUD-stats have been reduced in size to
|
|
be within the 79 character HUD-message limit.
|
|
Thanks for debug reports: BMJ.
|
|
0.9.8a 2003-11-30 XAD Updated for CS release 2003-nov-26.
|
|
Restored all HUD-messages changed in v0.9.6b, as
|
|
HUD-message limit has increased to 480 characters.
|
|
Reactivated last-hit fix, as AMX core function
|
|
"CS_DeathMsg" doesn't always work.
|
|
0.9.8a1a 2004-01-03 XAD Removed show_roundend_hudstats from kill_stats.
|
|
Reduced HUD_MIN_DURATION from 1 sec to 0.2 sec.
|
|
0.9.8b 2004-03-29 XAD Updated for AMX Mod X 0.16.
|
|
Changed the code to support non-zero initializing
|
|
Small compilers.
|
|
Removed support for 79 char limit HUD-message.
|
|
|
|
*************************************************************/
|
|
|
|
new PLUGIN_AUTHOR[] = "XAD (OLO)";
|
|
new PLUGIN_NAME[] = "STATSX";
|
|
new STRING_VERSION[] = "0.9.8b";
|
|
|
|
//--------------------------------
|
|
|
|
#include <amxmodx>
|
|
#include <amxmisc>
|
|
#include <csstats>
|
|
|
|
//--------------------------------
|
|
|
|
// Uncomment to activate log debug messages.
|
|
//#define STATSX_DEBUG
|
|
//#define STATSX_DEBUG2
|
|
|
|
// Comment to activate new DeathMsg process (if fixed).
|
|
#define STATSX_OLD_DEATHMSG
|
|
|
|
// HUD statistics duration in seconds (minimum 1.0 seconds).
|
|
new HUD_DURATION_CVAR[] = "amx_statsx_duration";
|
|
new HUD_DURATION[] = "12.0";
|
|
|
|
// HUD statistics stop relative freeze end in seconds.
|
|
// To stop before freeze end use a negative value.
|
|
new HUD_FREEZE_LIMIT_CVAR[] = "amx_statsx_freeze";
|
|
new HUD_FREEZE_LIMIT[] = "-2.0";
|
|
|
|
// HUD statistics minimum duration, in seconds, to trigger the display logic.
|
|
#define HUD_MIN_DURATION 0.2
|
|
|
|
// Config plugin constants.
|
|
#define MODE_HUD_DELAY 0 // Make a 0.01 sec delay on HUD reset process.
|
|
|
|
// You can also manualy enable or disable these options by setting them to 1
|
|
// For example:
|
|
// public ShowAttackers = 1
|
|
// However amx_statscfg command is recommended
|
|
|
|
public KillerChat = 0; // displays killer hp&ap to victim console
|
|
// and screen
|
|
|
|
public ShowAttackers = 0; // shows attackers
|
|
public ShowVictims = 0; // shows victims
|
|
public ShowKiller = 0; // shows killer
|
|
public ShowTeamScore = 0; // shows team score at round end
|
|
public ShowTotalStats = 0; // shows round total stats
|
|
public ShowBestScore = 0; // shows rounds best scored player
|
|
public ShowMostDisruptive = 0; // shows rounds most disruptive player
|
|
|
|
public EndPlayer = 0; // displays player stats at the end of map
|
|
public EndTop15 = 0; // displays top15 at the end of map
|
|
|
|
public SayHP = 0; // displays information about user killer
|
|
public SayStatsMe = 0; // displays user's stats and rank
|
|
public SayRankStats = 0; // displays user's rank stats
|
|
public SayMe = 0; // displays user's stats
|
|
public SayRank = 0; // displays user's rank
|
|
public SayReport = 0; // report user's weapon status to team
|
|
public SayScore = 0; // displays team's map score
|
|
public SayTop15 = 0; // displays first 15 players
|
|
public SayStatsAll = 0; // displays all players stats and rank
|
|
public SayMiscFunc = 0; // displays timeleft, thetime, currentmap, ff
|
|
|
|
public ShowStats = 0; // set client HUD-stats switched off by default
|
|
public ShowDistHS = 0; // show distance and HS in attackers and
|
|
// victims HUD lists
|
|
public ShowFullStats = 0; // show full HUD stats (more than 78 chars)
|
|
|
|
public SpecRankInfo = 0; // displays rank info when spectating
|
|
|
|
// Standard Contstants.
|
|
#define MAX_TEAMS 2
|
|
#define MAX_PLAYERS 32 + 1
|
|
|
|
#define MAX_NAME_LENGTH 31
|
|
#define MAX_WEAPON_LENGTH 31
|
|
#define MAX_TEXT_LENGTH 255
|
|
#define MAX_BUFFER_LENGTH 2047
|
|
|
|
// User messages.
|
|
new g_sDisabledMsg[] = "Server has disabled that option";
|
|
|
|
// User stats parms id
|
|
#define STATS_KILLS 0
|
|
#define STATS_DEATHS 1
|
|
#define STATS_HS 2
|
|
#define STATS_TKS 3
|
|
#define STATS_SHOTS 4
|
|
#define STATS_HITS 5
|
|
#define STATS_DAMAGE 6
|
|
|
|
// Global player flags.
|
|
|
|
new BODY_PART[8][] = {
|
|
"wholebody",
|
|
"head",
|
|
"chest",
|
|
"stomach",
|
|
"leftarm",
|
|
"rightarm",
|
|
"leftleg",
|
|
"rightleg"
|
|
}
|
|
|
|
// Killer information, save killer info at the time when player is killed.
|
|
#define KILLED_KILLER_ID 0 // Killer userindex/user-ID
|
|
#define KILLED_KILLER_HEALTH 1 // Killer's health
|
|
#define KILLED_KILLER_ARMOUR 2 // Killer's armour
|
|
#define KILLED_TEAM 3 // Killer's team
|
|
#define KILLED_KILLER_STATSFIX 4 // Fix to register the last hit/kill
|
|
|
|
new g_izKilled[MAX_PLAYERS][5];
|
|
|
|
// Menu variables and configuration
|
|
#define MAX_PPL_MENU_ACTIONS 2 // Number of player menu actions
|
|
#define PPL_MENU_OPTIONS 7 // Number of player options per displayed menu
|
|
|
|
new g_iPluginMode = 0;
|
|
|
|
new g_izUserMenuPosition[MAX_PLAYERS] = { 0, ... };
|
|
new g_izUserMenuAction[MAX_PLAYERS] = { 0, ... };
|
|
new g_izUserMenuPlayers[MAX_PLAYERS][32];
|
|
|
|
new g_izSpecMode[MAX_PLAYERS] = { 0, ... };
|
|
|
|
new g_izShowStatsFlags[MAX_PLAYERS] = { 0, ... };
|
|
new g_izStatsSwitch[MAX_PLAYERS] = { 0, ... };
|
|
new Float:g_fzShowUserStatsTime[MAX_PLAYERS] = { 0.0, ... };
|
|
new Float:g_fShowStatsTime = 0.0;
|
|
new Float:g_fFreezeTime = 0.0;
|
|
new Float:g_fFreezeLimitTime = 0.0;
|
|
new Float:g_fHUDDuration = 0.0;
|
|
|
|
new g_iRoundEndTriggered = 0;
|
|
new g_iRoundEndProcessed = 0;
|
|
|
|
new Float:g_fStartGame = 0.0;
|
|
new g_izTeamScore[MAX_TEAMS] = { 0, ... };
|
|
new g_izTeamEventScore[MAX_TEAMS] = { 0, ... };
|
|
new g_izTeamRndStats[MAX_TEAMS][8];
|
|
new g_izTeamGameStats[MAX_TEAMS][8];
|
|
new g_izUserUserID[MAX_PLAYERS] = { 0, ... };
|
|
new g_izUserAttackerDistance[MAX_PLAYERS] = { 0, ... };
|
|
new g_izUserVictimDistance[MAX_PLAYERS][MAX_PLAYERS];
|
|
new g_izUserRndName[MAX_PLAYERS][MAX_NAME_LENGTH];
|
|
new g_izUserRndStats[MAX_PLAYERS][8];
|
|
new g_izUserGameStats[MAX_PLAYERS][8];
|
|
|
|
// Common buffer to improve performance, as Small always zero-initializes all vars
|
|
new g_sBuffer[MAX_BUFFER_LENGTH+1] = "";
|
|
new g_sScore[MAX_TEXT_LENGTH+1] = "";
|
|
new g_sAwardAndScore[MAX_BUFFER_LENGTH+1] = "";
|
|
|
|
new t_sText[MAX_TEXT_LENGTH+1] = "";
|
|
new t_sName[MAX_NAME_LENGTH+1] = "";
|
|
new t_sWpn[MAX_WEAPON_LENGTH+1] = "";
|
|
|
|
//--------------------------------
|
|
// Initialize
|
|
//--------------------------------
|
|
|
|
public plugin_init() {
|
|
// Register plugin.
|
|
log_message( "[%s] %s v%s", PLUGIN_NAME, "StatsX", STRING_VERSION );
|
|
register_plugin( "StatsX", STRING_VERSION, PLUGIN_AUTHOR );
|
|
|
|
// Register events.
|
|
register_event( "TextMsg", "eventStartGame", "a",
|
|
"2=#Game_Commencing", "2=#Game_will_restart_in" );
|
|
register_event( "ResetHUD", "eventResetHud", "be" );
|
|
register_event( "RoundTime", "eventStartRound", "bc" );
|
|
|
|
#if defined STATSX_OLD_DEATHMSG
|
|
register_event( "DeathMsg", "eventDeathMsg", "a" );
|
|
register_event( "Damage", "eventDamage", "b", "2!0", "3=0", "4!0" );
|
|
#else
|
|
register_event( "CS_DeathMsg", "eventCSDeathMsg", "a" );
|
|
#endif
|
|
|
|
register_event( "SendAudio", "eventEndRound", "a",
|
|
"2=%!MRAD_terwin", "2=%!MRAD_ctwin", "2=%!MRAD_rounddraw" );
|
|
register_event( "TeamScore", "eventTeamScore", "a" );
|
|
register_event( "30", "eventIntermission", "a" );
|
|
|
|
register_event( "TextMsg", "eventSpecMode", "bd", "2&ec_Mod" );
|
|
register_event( "StatusValue", "eventShowRank", "bd", "1=2" );
|
|
|
|
// Register commands.
|
|
register_clcmd( "say /hp", "cmdHp", 0, "- display info. about your killer (chat)" );
|
|
register_clcmd( "say /statsme", "cmdStatsMe", 0, "- display your stats (MOTD)" );
|
|
register_clcmd( "say /rankstats", "cmdRankStats", 0, "- display your server stats (MOTD)" );
|
|
register_clcmd( "say /me", "cmdMe", 0, "- display current round stats (chat)" );
|
|
register_clcmd( "say /score", "cmdScore", 0, "- display last score (chat)" );
|
|
register_clcmd( "say /rank", "cmdRank", 0, "- display your rank (chat)" );
|
|
register_clcmd( "say /report", "cmdReport", 0, "- display waepon status (say_team)" );
|
|
|
|
register_clcmd( "say /top15", "cmdTop15", 0, "- display top 15 players (MOTD)" );
|
|
register_clcmd( "say /stats", "cmdStats", 0, "- display players stats (menu/MOTD)" );
|
|
|
|
register_clcmd( "say /timeleft", "cmdTimeLeft", 0, "- display time left on map (say)" );
|
|
register_clcmd( "say /thetime", "cmdTheTime", 0, "- display the time (say)" );
|
|
register_clcmd( "say /currentmap", "cmdCurrentMap", 0, "- display current map (say)" );
|
|
register_clcmd( "say /ff", "cmdFf", 0, "- display friendly fire status (say)" );
|
|
|
|
register_clcmd( "say /switch", "cmdSwitch", 0, "- switch client's stats on or off" );
|
|
|
|
// Register menus.
|
|
register_menucmd( register_menuid("Server Stats"), 1023, "actionStatsMenu" );
|
|
|
|
// Register special configuration setting and default value.
|
|
register_srvcmd( "amx_statsx_mode", "cmdPluginMode", ADMIN_CFG, "<flags> - sets plugin options" );
|
|
|
|
#if defined STATSX_DEBUG2
|
|
register_clcmd( "say /hudtest", "cmdHudTest" );
|
|
#endif
|
|
|
|
register_cvar( HUD_DURATION_CVAR, HUD_DURATION );
|
|
register_cvar( HUD_FREEZE_LIMIT_CVAR, HUD_FREEZE_LIMIT );
|
|
|
|
// Init buffers and some global vars.
|
|
g_sBuffer[0] = 0;
|
|
save_team_chatscore();
|
|
|
|
// Update local configuration vars with value in cvars.
|
|
get_config_cvars();
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
new g_addStast[] = "amx_statscfg add ^"%s^" %s"
|
|
|
|
public plugin_cfg(){
|
|
server_cmd( g_addStast, "Show killer hp&ap","KillerChat" );
|
|
|
|
server_cmd( g_addStast, "Show Attackers", "ShowAttackers" );
|
|
server_cmd( g_addStast, "Show Victims", "ShowVictims" );
|
|
server_cmd( g_addStast, "Show killer", "ShowKiller" );
|
|
server_cmd( g_addStast, "Show Team Score", "ShowTeamScore" );
|
|
server_cmd( g_addStast, "Show Total Stats", "ShowTotalStats" );
|
|
server_cmd( g_addStast, "Show Best Score", "ShowBestScore" );
|
|
server_cmd( g_addStast, "Show Most Disruptive", "ShowMostDisruptive" );
|
|
|
|
server_cmd( g_addStast, "HUD-stats default", "ShowStats" );
|
|
server_cmd( g_addStast, "Dist&HS in HUD lists", "ShowDistHS" );
|
|
|
|
server_cmd( g_addStast, "Stats at the end of map", "EndPlayer");
|
|
server_cmd( g_addStast, "Top15 at the end of map", "EndTop15" );
|
|
|
|
server_cmd( g_addStast, "Say /hp", "SayHP" );
|
|
server_cmd( g_addStast, "Say /statsme", "SayStatsMe" );
|
|
server_cmd( g_addStast, "Say /rankstats", "SayRankStats" );
|
|
server_cmd( g_addStast, "Say /me", "SayMe" );
|
|
server_cmd( g_addStast, "Say /rank", "SayRank" );
|
|
server_cmd( g_addStast, "Say /report", "SayReport" );
|
|
server_cmd( g_addStast, "Say /score", "SayScore" );
|
|
server_cmd( g_addStast, "Say /top15", "SayTop15" );
|
|
server_cmd( g_addStast, "Say /stats", "SayStatsAll" );
|
|
server_cmd( g_addStast, "Misc say commands", "SayMiscFunc" );
|
|
|
|
server_cmd( g_addStast, "Spec. Rank Info", "SpecRankInfo" );
|
|
}
|
|
|
|
// Set hudmessage format.
|
|
set_hudtype_killer( Float:fDuration )
|
|
set_hudmessage( 220, 80, 0, 0.05, 0.15, 0, 6.0, fDuration, (fDuration>=g_fHUDDuration)?1.0:0.0, 1.0, 2 );
|
|
set_hudtype_endround( Float:fDuration )
|
|
set_hudmessage( 100, 200, 0, 0.05, 0.55, 0, 0.02, fDuration, (fDuration>=g_fHUDDuration)?1.0:0.0, 1.0, 1 );
|
|
set_hudtype_attacker( Float:fDuration )
|
|
set_hudmessage( 220, 80, 0, 0.55, 0.35, 0, 6.0, fDuration, (fDuration>=g_fHUDDuration)?1.0:0.0, 1.0, 3 );
|
|
set_hudtype_victim( Float:fDuration )
|
|
set_hudmessage( 0, 80, 220, 0.55, 0.60, 0, 6.0, fDuration, (fDuration>=g_fHUDDuration)?1.0:0.0, 1.0, 4 );
|
|
set_hudtype_specmode() {
|
|
set_hudmessage( 255, 255, 255, 0.02, 0.87, 2, 0.05, 0.1, 0.01, 3.0, 1);
|
|
}
|
|
|
|
#if defined STATSX_DEBUG2
|
|
public cmdHudTest( id ) {
|
|
new i, iLen;
|
|
iLen = 0;
|
|
for( i = 1; i < 20; i++ )
|
|
iLen += format( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen, "....x....1....x....2....x....3....x....4....x....^n" );
|
|
set_hudtype_killer( 50.0 );
|
|
show_hudmessage( id, g_sBuffer );
|
|
}
|
|
#endif
|
|
|
|
// Stats formulas
|
|
Float:accuracy( izStats[8] ) {
|
|
if( !izStats[STATS_SHOTS] ) return ( 0.0 );
|
|
return ( 100.0 * float( izStats[STATS_HITS] ) / float( izStats[STATS_SHOTS] ) );
|
|
}
|
|
|
|
Float:effec( izStats[8] ) {
|
|
if( !izStats[STATS_KILLS] ) return ( 0.0 );
|
|
return ( 100.0 * float( izStats[STATS_KILLS] ) / float( izStats[STATS_KILLS] + izStats[STATS_DEATHS] ) );
|
|
}
|
|
|
|
// Distance formula (metric)
|
|
Float:distance( iDistance ) {
|
|
return float( iDistance ) * 0.0254;
|
|
}
|
|
|
|
// Get plugin config flags.
|
|
set_plugin_mode( id, sFlags[] ){
|
|
if( sFlags[0] )
|
|
g_iPluginMode = read_flags( sFlags );
|
|
get_flags( g_iPluginMode, t_sText, MAX_TEXT_LENGTH );
|
|
console_print( id, "^"amx_statsx_mode^" set to ^"%s^"", t_sText );
|
|
return g_iPluginMode;
|
|
}
|
|
|
|
// Get config parameters.
|
|
get_config_cvars() {
|
|
g_fFreezeTime = get_cvar_float("mp_freezetime");
|
|
if( g_fFreezeTime < 0.0 ) g_fFreezeTime = 0.0;
|
|
|
|
g_fHUDDuration = get_cvar_float( HUD_DURATION_CVAR );
|
|
if( g_fHUDDuration < 1.0 ) g_fHUDDuration = 1.0;
|
|
|
|
g_fFreezeLimitTime = get_cvar_float( HUD_FREEZE_LIMIT_CVAR );
|
|
|
|
return;
|
|
}
|
|
|
|
// Get and format attackers header and list.
|
|
get_attackers( id, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new izStats[8], izBody[8];
|
|
new iAttacker;
|
|
new iFound, iLen;
|
|
new iMaxPlayer = get_maxplayers();
|
|
|
|
iFound = 0;
|
|
sBuffer[0] = 0;
|
|
|
|
// Get and format header. Add killing attacker statistics if user is dead.
|
|
// Make sure shots is greater than zero or division by zero will occur.
|
|
// To print a '%', 4 of them must done in a row.
|
|
izStats[STATS_SHOTS] = 0;
|
|
iAttacker = g_izKilled[id][KILLED_KILLER_ID];
|
|
if( iAttacker )
|
|
get_user_astats( id, iAttacker, izStats, izBody );
|
|
if( izStats[STATS_SHOTS] && ShowFullStats ) {
|
|
get_user_name( iAttacker, t_sName, MAX_NAME_LENGTH );
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH, "Attackers -- %s -- %0.2f%%%% acc.:^n",
|
|
t_sName, accuracy( izStats ) );
|
|
}
|
|
else
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH, "Attackers:^n" );
|
|
|
|
// Get and format attacker list.
|
|
for( iAttacker = 1; iAttacker <= iMaxPlayer; iAttacker++ ) {
|
|
if( get_user_astats( id, iAttacker, izStats, izBody, t_sWpn, MAX_WEAPON_LENGTH ) ) {
|
|
iFound = 1;
|
|
get_user_name( iAttacker, t_sName, 32 );
|
|
if( izStats[STATS_KILLS] ) {
|
|
if( !ShowDistHS )
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn );
|
|
else if( izStats[STATS_HS] )
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s / %0.0f m / HS^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn, distance(g_izUserAttackerDistance[id]) );
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s / %0.0f m^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn, distance(g_izUserAttackerDistance[id]) );
|
|
}
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE] );
|
|
}
|
|
}
|
|
if( !iFound )
|
|
sBuffer[0] = 0;
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format victims header and list
|
|
get_victims( id, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new izStats[8], izBody[8];
|
|
new iVictim;
|
|
new iFound, iLen;
|
|
new iMaxPlayer = get_maxplayers();
|
|
|
|
iFound = 0;
|
|
sBuffer[0] = 0;
|
|
|
|
// Get and format header.
|
|
// Make sure shots is greater than zero or division by zero will occur.
|
|
// To print a '%', 4 of them must done in a row.
|
|
izStats[STATS_SHOTS] = 0;
|
|
get_user_vstats( id, 0, izStats, izBody );
|
|
if( izStats[STATS_SHOTS] )
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH, "Victims -- %0.2f%%%% acc.:^n",
|
|
accuracy( izStats ) );
|
|
else
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH, "Victims:^n" );
|
|
|
|
for( iVictim = 1; iVictim <= iMaxPlayer; iVictim++ ) {
|
|
if( get_user_vstats( id, iVictim, izStats, izBody, t_sWpn, MAX_WEAPON_LENGTH ) ) {
|
|
iFound = 1;
|
|
get_user_name( iVictim, t_sName, MAX_NAME_LENGTH );
|
|
if( izStats[STATS_DEATHS] ) {
|
|
if( !ShowDistHS )
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn );
|
|
else if( izStats[STATS_HS] )
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s / %0.0f m / HS^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn, distance(g_izUserVictimDistance[id][iVictim]) );
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg / %s / %0.0f m^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE],
|
|
t_sWpn, distance(g_izUserVictimDistance[id][iVictim]) );
|
|
}
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s -- %d hit(s) / %d dmg^n",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE] );
|
|
}
|
|
}
|
|
if( !iFound )
|
|
sBuffer[0] = 0;
|
|
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format kill info.
|
|
get_kill_info( id, iKiller, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new iFound, iLen;
|
|
|
|
iFound = 0;
|
|
sBuffer[0] = 0;
|
|
|
|
if( iKiller && iKiller != id ) {
|
|
new izAStats[8], izABody[8], izVStats[8], iaVBody[8];
|
|
|
|
iFound = 1;
|
|
get_user_name( iKiller, t_sName, MAX_NAME_LENGTH );
|
|
|
|
izAStats[STATS_HITS] = 0;
|
|
izAStats[STATS_DAMAGE] = 0;
|
|
t_sWpn[0] = 0;
|
|
get_user_astats( id, iKiller, izAStats, izABody, t_sWpn, MAX_WEAPON_LENGTH );
|
|
|
|
izVStats[STATS_HITS] = 0;
|
|
izVStats[STATS_DAMAGE] = 0;
|
|
get_user_vstats( id, iKiller, izVStats, iaVBody );
|
|
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"%s killed you with %s^nfrom distance of %0.2f meters.^n",
|
|
t_sName, t_sWpn, distance(g_izUserAttackerDistance[id]) );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"He did %d damage to you with %d hit(s)^nand still has %dhp and %dap.^n",
|
|
izAStats[STATS_DAMAGE], izAStats[STATS_HITS],
|
|
g_izKilled[id][KILLED_KILLER_HEALTH], g_izKilled[id][KILLED_KILLER_ARMOUR] );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"You did %d damage to him with %d hit(s).^n",
|
|
izVStats[STATS_DAMAGE], izVStats[STATS_HITS] );
|
|
}
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format most disruptive.
|
|
add_most_disruptive( sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new id, iMaxDamageId, iMaxDamage, iMaxHeadShots;
|
|
|
|
iMaxDamageId = 0;
|
|
iMaxDamage = 0;
|
|
iMaxHeadShots = 0;
|
|
|
|
// Find player.
|
|
for( id = 1; id < MAX_PLAYERS; id++ ) {
|
|
if( g_izUserRndStats[id][STATS_DAMAGE] >= iMaxDamage &&
|
|
( g_izUserRndStats[id][STATS_DAMAGE] > iMaxDamage || g_izUserRndStats[id][STATS_HS] > iMaxHeadShots ) ) {
|
|
iMaxDamageId = id;
|
|
iMaxDamage = g_izUserRndStats[id][STATS_DAMAGE];
|
|
iMaxHeadShots = g_izUserRndStats[id][STATS_HS];
|
|
}
|
|
}
|
|
|
|
// Format statistics.
|
|
if( iMaxDamageId ) {
|
|
id = iMaxDamageId;
|
|
new Float:fGameEff = effec( g_izUserGameStats[id] );
|
|
new Float:fRndAcc = accuracy( g_izUserRndStats[id] );
|
|
format( t_sText, MAX_TEXT_LENGTH,
|
|
"Most damage done by: %s^n%d hit(s) / %d dmg -- %0.2f%%%% eff. / %0.2f%%%% acc.^n",
|
|
g_izUserRndName[id], g_izUserRndStats[id][STATS_HITS],
|
|
iMaxDamage, fGameEff, fRndAcc );
|
|
add( sBuffer, MAX_BUFFER_LENGTH, t_sText );
|
|
}
|
|
return iMaxDamageId;
|
|
}
|
|
|
|
// Get and format best score.
|
|
add_best_score( sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new id, iMaxKillsId, iMaxKills, iMaxHeadShots;
|
|
|
|
iMaxKillsId = 0;
|
|
iMaxKills = 0;
|
|
iMaxHeadShots = 0;
|
|
|
|
// Find player
|
|
for( id = 1; id < MAX_PLAYERS; id++ ) {
|
|
if( g_izUserRndStats[id][STATS_KILLS] >= iMaxKills &&
|
|
( g_izUserRndStats[id][STATS_KILLS] > iMaxKills || g_izUserRndStats[id][STATS_HS] > iMaxHeadShots ) ) {
|
|
iMaxKillsId = id;
|
|
iMaxKills = g_izUserRndStats[id][STATS_KILLS];
|
|
iMaxHeadShots = g_izUserRndStats[id][STATS_HS];
|
|
}
|
|
}
|
|
|
|
// Format statistics.
|
|
if( iMaxKillsId ) {
|
|
id = iMaxKillsId;
|
|
new Float:fGameEff = effec( g_izUserGameStats[id] );
|
|
new Float:fRndAcc = accuracy( g_izUserRndStats[id] );
|
|
format( t_sText, MAX_TEXT_LENGTH,
|
|
"Best score: %s^n%d kill(s) / %d hs -- %0.2f%%%% eff. / %0.2f%%%% acc.^n",
|
|
g_izUserRndName[id], iMaxKills, iMaxHeadShots, fGameEff, fRndAcc );
|
|
add( sBuffer, MAX_BUFFER_LENGTH, t_sText );
|
|
}
|
|
return iMaxKillsId;
|
|
}
|
|
|
|
|
|
// Get and format team score.
|
|
add_team_score( sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new Float:fzMapEff[MAX_TEAMS], Float:fzMapAcc[MAX_TEAMS], Float:fzRndAcc[MAX_TEAMS];
|
|
|
|
// Calculate team stats
|
|
for( new iTeam = 0; iTeam < MAX_TEAMS; iTeam++ ) {
|
|
fzMapEff[iTeam] = effec( g_izTeamGameStats[iTeam] );
|
|
fzMapAcc[iTeam] = accuracy( g_izTeamGameStats[iTeam] );
|
|
fzRndAcc[iTeam] = accuracy( g_izTeamRndStats[iTeam] );
|
|
}
|
|
|
|
// Format round team stats, MOTD
|
|
format( t_sText, MAX_TEXT_LENGTH,
|
|
"TERRORIST %i / %0.2f%%%% eff. / %0.2f%%%% acc.^nCT %i / %0.2f%%%% eff. / %0.2f%%%% acc.^n",
|
|
g_izTeamScore[0], fzMapEff[0], fzRndAcc[0], g_izTeamScore[1], fzMapEff[1], fzRndAcc[1] );
|
|
add( sBuffer, MAX_BUFFER_LENGTH, t_sText );
|
|
}
|
|
|
|
|
|
// Get and format team stats, chat version
|
|
save_team_chatscore() {
|
|
new Float:fzMapEff[MAX_TEAMS], Float:fzMapAcc[MAX_TEAMS], Float:fzRndAcc[MAX_TEAMS];
|
|
|
|
// Calculate team stats
|
|
for( new iTeam = 0; iTeam < MAX_TEAMS; iTeam++ ) {
|
|
fzMapEff[iTeam] = effec( g_izTeamGameStats[iTeam] );
|
|
fzMapAcc[iTeam] = accuracy( g_izTeamGameStats[iTeam] );
|
|
fzRndAcc[iTeam] = accuracy( g_izTeamRndStats[iTeam] );
|
|
}
|
|
|
|
// Format game team stats, chat
|
|
format( g_sScore, MAX_BUFFER_LENGTH,
|
|
"TERRORIST %i / %0.2f%%%% eff. / %0.2f%%%% acc. -- CT %i / %0.2f%%%% eff. / %0.2f%%%% acc.",
|
|
g_izTeamScore[0], fzMapEff[0], fzMapAcc[0], g_izTeamScore[1], fzMapEff[1], fzMapAcc[1] );
|
|
}
|
|
|
|
|
|
// Get and format total stats.
|
|
add_total_stats( sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
format( t_sText, MAX_TEXT_LENGTH,
|
|
"Total: %d kill(s) / %d hs -- %d hit(s) / %d shot(s)^n",
|
|
g_izUserRndStats[0][STATS_KILLS], g_izUserRndStats[0][STATS_HS],
|
|
g_izUserRndStats[0][STATS_HITS], g_izUserRndStats[0][STATS_SHOTS] );
|
|
add( sBuffer, MAX_BUFFER_LENGTH, t_sText );
|
|
}
|
|
|
|
|
|
// Get and format a user's list of body hits from an attacker.
|
|
add_attacker_hits( id, iAttacker, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new iFound = 0;
|
|
if( iAttacker && iAttacker != id ) {
|
|
new izStats[8], izBody[8], iLen;
|
|
|
|
izStats[STATS_HITS] = 0;
|
|
get_user_astats( id, iAttacker, izStats, izBody );
|
|
|
|
if( izStats[STATS_HITS] ) {
|
|
iFound = 1;
|
|
iLen = strlen( sBuffer );
|
|
get_user_name( iAttacker, t_sName, MAX_NAME_LENGTH );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s hits you in:^n", t_sName );
|
|
for( new i = 1; i < 8; i++ ) {
|
|
if( !izBody[i] ) continue;
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s: %d^n", BODY_PART[i], izBody[i] );
|
|
}
|
|
}
|
|
}
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format killed stats: killer hp, ap, hits.
|
|
format_kill_ainfo( id, iKiller, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new iFound = 0;
|
|
if( iKiller && iKiller != id ) {
|
|
new izStats[8], izBody[8];
|
|
new iLen;
|
|
iFound = 1;
|
|
get_user_name( iKiller, t_sName, MAX_NAME_LENGTH );
|
|
|
|
izStats[STATS_HITS] = 0;
|
|
get_user_astats( id, iKiller, izStats, izBody, t_sWpn, MAX_WEAPON_LENGTH );
|
|
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"Killed by %s with %s @ %0.0fm (%dhp, %dap) >>", t_sName, t_sWpn,
|
|
distance(g_izUserAttackerDistance[id]),
|
|
g_izKilled[id][KILLED_KILLER_HEALTH], g_izKilled[id][KILLED_KILLER_ARMOUR] );
|
|
|
|
if( izStats[STATS_HITS] ) {
|
|
for( new i = 1; i < 8; i++ ) {
|
|
if( !izBody[i] ) continue;
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
" %s: %d", BODY_PART[i], izBody[i] );
|
|
}
|
|
}
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
" no hits" );
|
|
}
|
|
else
|
|
copy( sBuffer, MAX_BUFFER_LENGTH, "You have no killer..." );
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format killed stats: hits, damage on killer.
|
|
format_kill_vinfo( id, iKiller, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new iFound = 0;
|
|
new izStats[8];
|
|
new izBody[8];
|
|
new iLen;
|
|
|
|
izStats[STATS_HITS] = 0;
|
|
izStats[STATS_DAMAGE] = 0;
|
|
get_user_vstats( id, iKiller, izStats, izBody );
|
|
|
|
if( iKiller && iKiller != id ) {
|
|
iFound = 1;
|
|
get_user_name( iKiller, t_sName, MAX_NAME_LENGTH );
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"You hit %s %d time(s), %d damage >>",
|
|
t_sName, izStats[STATS_HITS], izStats[STATS_DAMAGE] );
|
|
}
|
|
else
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"Last result: %d hit(s), %d damage >>",
|
|
izStats[STATS_HITS], izStats[STATS_DAMAGE] );
|
|
|
|
if( izStats[STATS_HITS] ) {
|
|
for( new i = 1; i < 8; i++ ) {
|
|
if( !izBody[i] ) continue;
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
" %s: %d", BODY_PART[i], izBody[i] );
|
|
}
|
|
}
|
|
else
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
" no hits" );
|
|
return iFound;
|
|
}
|
|
|
|
|
|
// Get and format top 15.
|
|
format_top15( sBuffer[MAX_BUFFER_LENGTH+1] ){
|
|
new iMax = get_statsnum();
|
|
new izStats[8], izBody[8];
|
|
new iLen = 0;
|
|
|
|
if( iMax > 15 )
|
|
iMax = 15;
|
|
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"<body bgcolor=#000000><font color=#FFB000><pre>" );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%2s %-22.22s %6s %6s %6s %6s %4s %4s %4s^n",
|
|
"#", "Nick", "Kills", "Deaths", "Hits", "Shots", "HS", "Eff.", "Acc." );
|
|
for( new i = 0; i < iMax && MAX_BUFFER_LENGTH - iLen > 0; i++ ) {
|
|
get_stats( i, izStats, izBody, t_sName, MAX_NAME_LENGTH );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%2d %-22.22s %6d %6d %6d %6d %4d %3.0f%% %3.0f%%^n", i+1, t_sName,
|
|
izStats[STATS_KILLS], izStats[STATS_DEATHS], izStats[STATS_HITS],
|
|
izStats[STATS_SHOTS], izStats[STATS_HS],
|
|
effec( izStats ), accuracy( izStats ) );
|
|
}
|
|
}
|
|
|
|
|
|
// Get and format rank stats.
|
|
format_rankstats( id, sBuffer[MAX_BUFFER_LENGTH+1], iMyId=0 ) {
|
|
new izStats[8] = { 0, ... };
|
|
new izBody[8];
|
|
new iRankPos, iLen;
|
|
iRankPos = get_user_stats( id, izStats, izBody );
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"<body bgcolor=#000000><font color=#FFB000><pre>" );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s rank is %d of %d^n^n",
|
|
(!iMyId||iMyId==id)?"Your":"Players", iRankPos, get_statsnum() );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%s rank is %d of %d^n^n",
|
|
(!iMyId||iMyId==id)?"Your":"Players", iRankPos, get_statsnum() );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%6s: %d (%d with hs)^n%6s: %d^n%6s: %d^n%6s: %d^n%6s: %d^n%6s: %0.2f%%^n%6s: %0.2f%%^n^n",
|
|
"Kills", izStats[STATS_KILLS], izStats[STATS_HS],
|
|
"Deaths", izStats[STATS_DEATHS], "Hits", izStats[STATS_HITS],
|
|
"Shots", izStats[STATS_SHOTS], "Damage", izStats[STATS_DAMAGE],
|
|
"Eff.", effec( izStats ), "Acc.", accuracy( izStats ) );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%10s:^n%10s: %d^n%10s: %d^n%10s: %d^n%10s: %d^n%10s: %d^n%10s: %d^n%10s: %d",
|
|
"HITS", BODY_PART[1], izBody[1], BODY_PART[2], izBody[2],
|
|
BODY_PART[3], izBody[3], BODY_PART[4], izBody[4], BODY_PART[5], izBody[5],
|
|
BODY_PART[6], izBody[6], BODY_PART[7], izBody[7]);
|
|
return;
|
|
}
|
|
|
|
|
|
// Get and format stats.
|
|
format_stats( id, sBuffer[MAX_BUFFER_LENGTH+1] ) {
|
|
new izStats[8] = { 0, ... };
|
|
new izBody[8];
|
|
new iWeapon, iLen;
|
|
get_user_wstats( id, 0, izStats, izBody );
|
|
iLen = format( sBuffer, MAX_BUFFER_LENGTH,
|
|
"<body bgcolor=#000000><font color=#FFB000><pre>" );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%6s: %d (%d with hs)^n%6s: %d^n%6s: %d^n%6s: %d^n%6s: %d^n%6s: %0.2f%%^n%6s: %0.2f%%^n^n",
|
|
"Kills", izStats[STATS_KILLS], izStats[STATS_HS],
|
|
"Deaths", izStats[STATS_DEATHS], "Hits", izStats[STATS_HITS],
|
|
"Shots", izStats[STATS_SHOTS], "Damage", izStats[STATS_DAMAGE],
|
|
"Eff.", effec( izStats ), "Acc.", accuracy( izStats ) );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%-12.12s %6s %6s %6s %6s %6s %4s^n",
|
|
"Weapon", "Kills", "Deaths", "Hits", "Shots", "Damage", "Acc." );
|
|
for( iWeapon = 1; iWeapon < 31 && MAX_BUFFER_LENGTH - iLen > 0 ; iWeapon++ ) {
|
|
if( get_user_wstats( id, iWeapon, izStats, izBody ) ) {
|
|
get_weaponname( iWeapon, t_sWpn, MAX_WEAPON_LENGTH );
|
|
iLen += format( sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%-12.12s %6d %6d %6d %6d %6d %3.0f%%^n",
|
|
t_sWpn[7], izStats[STATS_KILLS], izStats[STATS_DEATHS],
|
|
izStats[STATS_HITS], izStats[STATS_SHOTS],
|
|
izStats[STATS_DAMAGE], accuracy( izStats ) );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Show round end stats. If gametime is zero then use default duration time.
|
|
show_roundend_hudstats( id, Float:fGameTime ) {
|
|
|
|
// Bail out if there no HUD stats should be shown
|
|
// for this player or end round stats not created.
|
|
if( !g_izStatsSwitch[id] ) return;
|
|
if( !g_sAwardAndScore[0] ) return;
|
|
|
|
// If round end timer is zero clear round end stats.
|
|
if( g_fShowStatsTime == 0.0 ) {
|
|
set_hudtype_endround( 0.05 );
|
|
show_hudmessage( id, "" );
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Clear round end HUD stats for #%i", PLUGIN_NAME, id );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// Set HUD-duration to default or remaining time.
|
|
new Float:fDuration;
|
|
if( fGameTime == 0.0 )
|
|
fDuration = g_fHUDDuration;
|
|
else {
|
|
fDuration = g_fShowStatsTime + g_fHUDDuration - fGameTime;
|
|
if( fDuration > g_fFreezeTime + g_fFreezeLimitTime )
|
|
fDuration = g_fFreezeTime + g_fFreezeLimitTime;
|
|
}
|
|
// Show stats only if more time left than coded minimum.
|
|
if( fDuration >= HUD_MIN_DURATION ) {
|
|
set_hudtype_endround( fDuration );
|
|
show_hudmessage( id, g_sAwardAndScore );
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Show %1.2fs round end HUD stats for #%i", PLUGIN_NAME, fDuration, id );
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// Show round end stats.
|
|
show_user_hudstats( id, Float:fGameTime ) {
|
|
|
|
// Bail out if there no HUD stats should be shown
|
|
// for this player or user stats timer is zero.
|
|
if( !g_izStatsSwitch[id] ) return;
|
|
if( g_fzShowUserStatsTime[id] == 0.0 ) return;
|
|
|
|
// Set HUD-duration to default or remaining time.
|
|
new Float:fDuration;
|
|
if( fGameTime == 0.0 )
|
|
fDuration = g_fHUDDuration;
|
|
else {
|
|
fDuration = g_fzShowUserStatsTime[id] + g_fHUDDuration - fGameTime;
|
|
if( fDuration > g_fFreezeTime + g_fFreezeLimitTime )
|
|
fDuration = g_fFreezeTime + g_fFreezeLimitTime;
|
|
}
|
|
// Show stats only if more time left than coded minimum.
|
|
if( fDuration >= HUD_MIN_DURATION ) {
|
|
if( ShowKiller ) {
|
|
new iKiller;
|
|
iKiller = g_izKilled[id][KILLED_KILLER_ID];
|
|
get_kill_info( id, iKiller, g_sBuffer );
|
|
add_attacker_hits( id, iKiller, g_sBuffer );
|
|
set_hudtype_killer( fDuration );
|
|
show_hudmessage( id, g_sBuffer );
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Show %1.2fs %suser HUD k-stats for #%i", PLUGIN_NAME, fDuration, g_sBuffer[0]?"":"no ", id );
|
|
#endif
|
|
}
|
|
if( ShowVictims ) {
|
|
get_victims( id, g_sBuffer );
|
|
set_hudtype_victim( fDuration );
|
|
show_hudmessage( id, g_sBuffer );
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Show %1.2fs %suser HUD v-stats for #%i", PLUGIN_NAME, fDuration, g_sBuffer[0]?"":"no ", id );
|
|
#endif
|
|
}
|
|
if( ShowAttackers ) {
|
|
get_attackers( id, g_sBuffer );
|
|
set_hudtype_attacker( fDuration );
|
|
show_hudmessage( id, g_sBuffer );
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Show %1.2fs %suser HUD a-stats for #%i", PLUGIN_NAME, fDuration, g_sBuffer[0]?"":"no ", id );
|
|
#endif
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// Plugin commands
|
|
//------------------------------------------------------------
|
|
|
|
// Set or get plugin config flags.
|
|
public cmdPluginMode( id, level, cid ) {
|
|
if( !cmd_access( id, level, cid, 1 ) )
|
|
return PLUGIN_HANDLED;
|
|
if( read_argc() > 1 )
|
|
read_argv( 1, g_sBuffer, MAX_BUFFER_LENGTH );
|
|
else
|
|
g_sBuffer[0] = 0;
|
|
set_plugin_mode( id, g_sBuffer );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
|
|
// Display MOTD stats.
|
|
public cmdStatsMe( id ) {
|
|
if( !SayStatsMe ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
format_stats( id, g_sBuffer );
|
|
get_user_name( id, t_sName, MAX_NAME_LENGTH );
|
|
show_motd( id, g_sBuffer, t_sName );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display MOTD rank.
|
|
public cmdRankStats( id ) {
|
|
if( !SayRankStats ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
format_rankstats( id, g_sBuffer );
|
|
get_user_name( id, t_sName, MAX_NAME_LENGTH );
|
|
show_motd( id, g_sBuffer, t_sName );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display MOTD top15 ranked.
|
|
public cmdTop15( id ) {
|
|
if( !SayTop15 ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
format_top15( g_sBuffer );
|
|
show_motd( id, g_sBuffer, "Top 15" );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display killer information.
|
|
public cmdHp( id ) {
|
|
if( !SayHP ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
new iKiller = g_izKilled[id][KILLED_KILLER_ID];
|
|
format_kill_ainfo( id, iKiller, g_sBuffer );
|
|
client_print( id, print_chat, "* %s", g_sBuffer );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display user stats.
|
|
public cmdMe( id ) {
|
|
if( !SayMe ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
format_kill_vinfo( id, 0, g_sBuffer );
|
|
client_print( id, print_chat, "* %s", g_sBuffer );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display user rank
|
|
public cmdRank( id ) {
|
|
if( !SayRank ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
new izStats[8], izBody[8];
|
|
new iRankPos, iRankMax;
|
|
new Float:fEff, Float:fAcc;
|
|
iRankPos = get_user_stats( id, izStats, izBody );
|
|
iRankMax = get_statsnum();
|
|
fEff = effec( izStats );
|
|
fAcc = accuracy( izStats );
|
|
client_print( id, print_chat,
|
|
"* Your rank is %d of %d with %d kill(s), %d hit(s), %0.2f%%%% eff. and %0.2f%%%% acc.",
|
|
iRankPos, iRankMax, izStats[STATS_KILLS], izStats[STATS_HITS],
|
|
fEff, fAcc );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Report user weapon status to team.
|
|
public cmdReport( id ) {
|
|
if( !SayReport ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
new iWeapon, iClip, iAmmo, iHealth, iArmor;
|
|
iWeapon = get_user_weapon( id, iClip, iAmmo );
|
|
get_weaponname( iWeapon, t_sWpn, MAX_WEAPON_LENGTH );
|
|
iHealth = get_user_health( id );
|
|
iArmor = get_user_armor( id );
|
|
if( iClip >= 0 )
|
|
format( g_sBuffer, MAX_BUFFER_LENGTH,
|
|
"weapon: %s, ammo: %d/%d, health: %d, armor: %d",
|
|
t_sWpn[7], iClip, iAmmo, iHealth, iArmor );
|
|
else
|
|
format( g_sBuffer, MAX_BUFFER_LENGTH,
|
|
"weapon: %s, health: %d, armor: %d",
|
|
t_sWpn[7], iHealth, iArmor );
|
|
engclient_cmd( id, "say_team", g_sBuffer );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display team map score
|
|
public cmdScore( id ) {
|
|
if( !SayScore ) {
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
client_print( id, print_chat, "Game score: %s", g_sScore );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display time left on map
|
|
public cmdTimeLeft( id ) {
|
|
if( !SayMiscFunc )
|
|
return PLUGIN_CONTINUE;
|
|
new iTimeLeft = get_timeleft();
|
|
if( iTimeLeft )
|
|
client_print( 0, print_chat,
|
|
"Time remaining: %02d:%02d", iTimeLeft / 60, iTimeLeft % 60 );
|
|
else
|
|
client_print( 0, print_chat, "* No Time Limit *" );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display the time.
|
|
public cmdTheTime( id ) {
|
|
if( !SayMiscFunc )
|
|
return PLUGIN_CONTINUE;
|
|
get_time( "%H:%M:%S", g_sBuffer, MAX_BUFFER_LENGTH );
|
|
client_print( 0, print_chat, "The time: %s", g_sBuffer );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display current map name.
|
|
public cmdCurrentMap( id ) {
|
|
if( !SayMiscFunc )
|
|
return PLUGIN_CONTINUE;
|
|
get_mapname( g_sBuffer, MAX_BUFFER_LENGTH );
|
|
client_print( 0, print_chat, "Played map: %s", g_sBuffer );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Display friendly fire status.
|
|
public cmdFf( id ) {
|
|
if( !SayMiscFunc )
|
|
return PLUGIN_CONTINUE;
|
|
client_print( 0, print_chat, "Friendly fire: %s",
|
|
get_cvar_num( "mp_friendlyfire" ) ? "ON" : "OFF" );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Client switch to enable or disable stats announcements.
|
|
public cmdSwitch( id ) {
|
|
g_izStatsSwitch[id] = ( g_izStatsSwitch[id] ) ? 0 : -1 ;
|
|
num_to_str( g_izStatsSwitch[id], t_sText, MAX_TEXT_LENGTH );
|
|
client_cmd( id, "setinfo _amxstatsx %s", t_sText );
|
|
client_print( id, print_chat, "* You have %s stats announcements",
|
|
g_izStatsSwitch[id] ? "enabled" : "disabled" );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Player stats menu.
|
|
public cmdStats( id ) {
|
|
if ( !SayStatsAll ){
|
|
client_print( id, print_chat, g_sDisabledMsg );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
showStatsMenu( id, g_izUserMenuPosition[id]=0 );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
|
|
//--------------------------------
|
|
// Menu
|
|
//--------------------------------
|
|
|
|
public actionStatsMenu( id, key ) {
|
|
switch( key ) {
|
|
// Key '1' to '7', execute action on this option
|
|
case 0..6: {
|
|
new iOption, iIndex;
|
|
iOption = ( g_izUserMenuPosition[id] * PPL_MENU_OPTIONS ) + key;
|
|
if( iOption >= 0 && iOption < 32 ) {
|
|
iIndex = g_izUserMenuPlayers[id][iOption];
|
|
if( is_user_connected( iIndex ) ){
|
|
switch( g_izUserMenuAction[id] ) {
|
|
case 0: format_stats( iIndex, g_sBuffer );
|
|
case 1: format_rankstats( iIndex, g_sBuffer, id );
|
|
default: g_sBuffer[0] = 0;
|
|
}
|
|
if( g_sBuffer[0] ) {
|
|
get_user_name( iIndex, t_sName, MAX_NAME_LENGTH );
|
|
show_motd( id, g_sBuffer, t_sName );
|
|
}
|
|
}
|
|
}
|
|
showStatsMenu( id, g_izUserMenuPosition[id] );
|
|
}
|
|
// Key '8', change action
|
|
case 7: {
|
|
g_izUserMenuAction[id]++;
|
|
if( g_izUserMenuAction[id] >= MAX_PPL_MENU_ACTIONS )
|
|
g_izUserMenuAction[id] = 0;
|
|
showStatsMenu( id, g_izUserMenuPosition[id] );
|
|
}
|
|
// Key '9', select next page of options
|
|
case 8:
|
|
showStatsMenu( id, ++g_izUserMenuPosition[id] );
|
|
// Key '10', cancel or go back to previous menu
|
|
case 9: {
|
|
if( g_izUserMenuPosition[id] > 0 )
|
|
showStatsMenu( id, --g_izUserMenuPosition[id] );
|
|
}
|
|
}
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
|
|
new g_izUserMenuActionText[MAX_PPL_MENU_ACTIONS][] = { "Show stats", "Show rank stats" };
|
|
|
|
showStatsMenu( id, iMenuPos ) {
|
|
new iLen, iKeyMask, iPlayers;
|
|
new iUserIndex, iMenuPosMax, iMenuOption, iMenuOptionMax;
|
|
get_players( g_izUserMenuPlayers[id], iPlayers );
|
|
iMenuPosMax = (( iPlayers - 1 ) / PPL_MENU_OPTIONS ) + 1;
|
|
// If menu pos does not excist use last menu (if players has left)
|
|
if ( iMenuPos >= iMenuPosMax )
|
|
iMenuPos = iMenuPosMax - 1;
|
|
iUserIndex = iMenuPos * PPL_MENU_OPTIONS;
|
|
iLen = format( g_sBuffer, MAX_BUFFER_LENGTH, "\yServer Stats\R%d/%d^n\w^n",
|
|
iMenuPos + 1, iMenuPosMax );
|
|
iMenuOptionMax = iPlayers - iUserIndex;
|
|
if( iMenuOptionMax > PPL_MENU_OPTIONS )
|
|
iMenuOptionMax = PPL_MENU_OPTIONS;
|
|
for( iMenuOption = 0; iMenuOption < iMenuOptionMax; iMenuOption++ ) {
|
|
get_user_name( g_izUserMenuPlayers[id][iUserIndex++], t_sName, MAX_NAME_LENGTH );
|
|
iKeyMask |= (1<<iMenuOption);
|
|
iLen += format( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen,
|
|
"%d. %s^n\w", iMenuOption + 1, t_sName );
|
|
}
|
|
iKeyMask |= (1<<7)|(1<<9);
|
|
iLen += format( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen, "^n8. %s^n\w",
|
|
g_izUserMenuActionText[ g_izUserMenuAction[id] ] );
|
|
if( iPlayers > iUserIndex ) {
|
|
iLen += copy( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen, "^n9. More..." );
|
|
iKeyMask |= (1<<8);
|
|
}
|
|
if( iMenuPos > 0 )
|
|
iLen += copy( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen, "^n0. Back" );
|
|
else
|
|
iLen += copy( g_sBuffer[iLen], MAX_BUFFER_LENGTH - iLen, "^n0. Exit" );
|
|
show_menu( id, iKeyMask, g_sBuffer );
|
|
return PLUGIN_HANDLED;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// Plugin events
|
|
//------------------------------------------------------------
|
|
|
|
// Reset game stats on game start and restart.
|
|
public eventStartGame() {
|
|
read_data( 2, t_sText, MAX_TEXT_LENGTH );
|
|
if( t_sText[6] == 'w' ) {
|
|
read_data( 3, t_sText, MAX_TEXT_LENGTH );
|
|
g_fStartGame = get_gametime() + float( str_to_num( t_sText ) );
|
|
}
|
|
else
|
|
g_fStartGame = get_gametime();
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Round start
|
|
public eventStartRound() {
|
|
new iTeam, id, i;
|
|
new iRoundTime;
|
|
|
|
iRoundTime = read_data( 1 );
|
|
if ( iRoundTime >= get_cvar_float("mp_roundtime") * 60 ) {
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Reset round stats", PLUGIN_NAME );
|
|
#endif
|
|
|
|
// Reset game stats on game start and restart.
|
|
if( g_fStartGame > 0.0 && g_fStartGame <= get_gametime() ) {
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Reset game stats", PLUGIN_NAME );
|
|
#endif
|
|
|
|
g_fStartGame = 0.0;
|
|
|
|
// Clear team and game stats.
|
|
for( iTeam = 0; iTeam < MAX_TEAMS; iTeam++ ) {
|
|
g_izTeamEventScore[iTeam] = 0;
|
|
for( i = 0; i < 8; i++ )
|
|
g_izTeamGameStats[iTeam][i] = 0;
|
|
}
|
|
|
|
// Clear game stats, incl '0' that is sum of all users.
|
|
for( id = 0; id < MAX_PLAYERS; id++ ) {
|
|
for( i = 0; i < 8; i++ )
|
|
g_izUserGameStats[id][i] = 0;
|
|
}
|
|
}
|
|
|
|
// Update team score with "TeamScore" event values and
|
|
// clear team round stats.
|
|
for( iTeam = 0; iTeam < MAX_TEAMS; iTeam++ ) {
|
|
g_izTeamScore[iTeam] = g_izTeamEventScore[iTeam];
|
|
for( i = 0; i < 8; i++ )
|
|
g_izTeamRndStats[iTeam][i] = 0;
|
|
}
|
|
|
|
// Clear user round stats, incl '0' that is sum of all users.
|
|
for( id = 0; id < MAX_PLAYERS; id++ ) {
|
|
g_izUserRndName[id][0] = 0;
|
|
for( i = 0; i < 8; i++ )
|
|
g_izUserRndStats[id][i] = 0;
|
|
g_fzShowUserStatsTime[id] = 0.0;
|
|
}
|
|
|
|
// Allow end round stats and reset end round triggered indicator.
|
|
g_iRoundEndTriggered = 0;
|
|
g_iRoundEndProcessed = 0;
|
|
g_fShowStatsTime = 0.0;
|
|
|
|
// Update local configuration vars with value in cvars.
|
|
get_config_cvars();
|
|
}
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
// Reset killer info on round restart.
|
|
public eventResetHud( id ) {
|
|
new args[1];
|
|
args[0] = id;
|
|
if( g_iPluginMode & MODE_HUD_DELAY )
|
|
set_task( 0.01, "delay_resethud", 200 + id, args, 1 );
|
|
else
|
|
delay_resethud( args );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public delay_resethud( args[] ) {
|
|
new id = args[0];
|
|
new Float:fGameTime
|
|
|
|
// Show user and score round stats after HUD-reset
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Reset HUD for #%i", PLUGIN_NAME, id );
|
|
#endif
|
|
fGameTime = get_gametime();
|
|
show_user_hudstats( id, fGameTime );
|
|
show_roundend_hudstats( id, fGameTime );
|
|
|
|
// Reset round stats
|
|
g_izKilled[id][KILLED_KILLER_ID] = 0;
|
|
g_izKilled[id][KILLED_KILLER_STATSFIX] = 0;
|
|
g_izShowStatsFlags[id] = -1; // Initialize flags
|
|
g_fzShowUserStatsTime[id] = 0.0;
|
|
g_izUserAttackerDistance[id] = 0;
|
|
for( new i = 0; i < MAX_PLAYERS; i++ )
|
|
g_izUserVictimDistance[id][i] = 0;
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
#if defined STATSX_OLD_DEATHMSG
|
|
|
|
// Save killer info on death.
|
|
public eventDeathMsg() {
|
|
new iKiller = read_data( 1 );
|
|
new iVictim = read_data( 2 );
|
|
|
|
// Bail out if no killer.
|
|
if( !iKiller ) return PLUGIN_CONTINUE;
|
|
|
|
if( iKiller != iVictim ) {
|
|
new iaVOrigin[3], iaKOrigin[3];
|
|
new iDistance;
|
|
get_user_origin( iVictim, iaVOrigin );
|
|
get_user_origin( iKiller, iaKOrigin );
|
|
g_izKilled[iVictim][KILLED_KILLER_ID] = iKiller;
|
|
g_izKilled[iVictim][KILLED_KILLER_HEALTH] = get_user_health( iKiller );
|
|
g_izKilled[iVictim][KILLED_KILLER_ARMOUR] = get_user_armor( iKiller );
|
|
g_izKilled[iVictim][KILLED_KILLER_STATSFIX] = 0;
|
|
|
|
iDistance = get_distance( iaVOrigin, iaKOrigin );
|
|
g_izUserAttackerDistance[iVictim] = iDistance;
|
|
g_izUserVictimDistance[iKiller][iVictim] = iDistance;
|
|
}
|
|
g_izKilled[iVictim][KILLED_TEAM] = get_user_team( iVictim );
|
|
new args[1];
|
|
args[0] = iVictim;
|
|
set_task( 0.25, "delay_damage", 100 + iVictim, args, 1 );
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public delay_damage( args[] ) {
|
|
new id = args[0];
|
|
|
|
// Display stats to killed player if player
|
|
// has not already been processed.
|
|
if( !g_izKilled[id][KILLED_KILLER_STATSFIX] ) {
|
|
g_izKilled[id][KILLED_KILLER_STATSFIX] = 1;
|
|
|
|
// Display round end stats to all players if
|
|
// round end has already been triggered.
|
|
if( g_iRoundEndTriggered )
|
|
endround_stats();
|
|
// Display kill stats for the player if round
|
|
// end stats was not processed.
|
|
if( !g_iRoundEndProcessed )
|
|
kill_stats( id );
|
|
}
|
|
}
|
|
|
|
// Trigger death stats processing.
|
|
public eventDamage( id ) {
|
|
// Bail out if player not killed or if player
|
|
// player has already been processed.
|
|
if( !g_izKilled[id][KILLED_KILLER_ID] || g_izKilled[id][KILLED_KILLER_STATSFIX] )
|
|
return PLUGIN_CONTINUE;
|
|
|
|
// Remove task if not alreay done and process.
|
|
remove_task( 100 + id );
|
|
|
|
// Process player deaths.
|
|
new izData[1];
|
|
izData[0] = id;
|
|
delay_damage( izData );
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
#endif // if defined STATSX_OLD_DEATHMSG
|
|
|
|
|
|
#if !defined STATSX_OLD_DEATHMSG
|
|
|
|
// Save killer info on death.
|
|
public eventCSDeathMsg() {
|
|
new iKiller = read_data( 1 );
|
|
new iVictim = read_data( 2 );
|
|
|
|
// Bail out if no killer.
|
|
if( !iKiller ) return PLUGIN_CONTINUE;
|
|
|
|
if( iKiller != iVictim ) {
|
|
new iaVOrigin[3], iaKOrigin[3];
|
|
new iDistance;
|
|
get_user_origin( iVictim, iaVOrigin );
|
|
get_user_origin( iKiller, iaKOrigin );
|
|
g_izKilled[iVictim][KILLED_KILLER_ID] = iKiller;
|
|
g_izKilled[iVictim][KILLED_KILLER_HEALTH] = get_user_health( iKiller );
|
|
g_izKilled[iVictim][KILLED_KILLER_ARMOUR] = get_user_armor( iKiller );
|
|
g_izKilled[iVictim][KILLED_KILLER_STATSFIX] = 0;
|
|
|
|
iDistance = get_distance( iaVOrigin, iaKOrigin );
|
|
g_izUserAttackerDistance[iVictim] = iDistance;
|
|
g_izUserVictimDistance[iKiller][iVictim] = iDistance;
|
|
}
|
|
g_izKilled[iVictim][KILLED_TEAM] = get_user_team( iVictim );
|
|
g_izKilled[iVictim][KILLED_KILLER_STATSFIX] = 1;
|
|
|
|
// Display kill stats for the player if round
|
|
// end stats was not processed.
|
|
if( !g_iRoundEndProcessed )
|
|
kill_stats( iVictim );
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Display hudmessage stats on death.
|
|
// This will also update all round and game stats.
|
|
// Must be called at least once per round.
|
|
kill_stats( id ) {
|
|
|
|
// Bail out if user stats timer is non-zero,
|
|
// ie function already called.
|
|
if( g_fzShowUserStatsTime[id] > 0.0 ) return;
|
|
|
|
// Flag kill stats displayed for this player.
|
|
g_fzShowUserStatsTime[id] = get_gametime();
|
|
|
|
// Add user death stats to user round stats
|
|
new izStats[8], izBody[8];
|
|
new iTeam, i;
|
|
new iKiller;
|
|
|
|
iKiller = g_izKilled[id][KILLED_KILLER_ID];
|
|
|
|
// Get user's team (if dead use the saved team)
|
|
if( iKiller )
|
|
iTeam = g_izKilled[id][KILLED_TEAM] - 1;
|
|
else
|
|
iTeam = get_user_team( id ) - 1;
|
|
|
|
get_user_name( id, g_izUserRndName[id], MAX_NAME_LENGTH );
|
|
|
|
if( get_user_rstats( id, izStats, izBody ) ) {
|
|
|
|
// Update user's team round stats
|
|
if( iTeam >= 0 && iTeam < MAX_TEAMS ) {
|
|
for( i = 0; i < 8; i++ ) {
|
|
g_izTeamRndStats[iTeam][i] += izStats[i];
|
|
g_izTeamGameStats[iTeam][i] += izStats[i];
|
|
g_izUserRndStats[0][i] += izStats[i];
|
|
g_izUserGameStats[0][i] += izStats[i];
|
|
}
|
|
}
|
|
|
|
// Update user's round stats
|
|
if( g_izUserUserID[id] == get_user_userid( id ) ) {
|
|
for( i = 0; i < 8; i++ ) {
|
|
g_izUserRndStats[id][i] += izStats[i];
|
|
g_izUserGameStats[id][i] += izStats[i];
|
|
}
|
|
}
|
|
else {
|
|
g_izUserUserID[id] = get_user_userid( id );
|
|
for( i = 0; i < 8; i++ ) {
|
|
g_izUserRndStats[id][i] = izStats[i];
|
|
g_izUserGameStats[id][i] = izStats[i];
|
|
}
|
|
}
|
|
|
|
} // endif( get_user_rstats() )
|
|
|
|
// Report stats in the chat section, if player is killed.
|
|
if( KillerChat && iKiller && iKiller != id ) {
|
|
if( format_kill_ainfo( id, iKiller, g_sBuffer ) ) {
|
|
client_print( id, print_chat, "* %s", g_sBuffer );
|
|
format_kill_vinfo( id, iKiller, g_sBuffer );
|
|
}
|
|
client_print( id, print_chat, "* %s", g_sBuffer );
|
|
}
|
|
|
|
// Display player stats info.
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] Kill stats for #%i", PLUGIN_NAME, id );
|
|
#endif
|
|
show_user_hudstats( id, 0.0 )
|
|
|
|
return;
|
|
}
|
|
|
|
public eventEndRound() {
|
|
|
|
// Update local configuration vars with value in cvars.
|
|
get_config_cvars();
|
|
|
|
// If first end round event in the round, calculate team score.
|
|
if( !g_iRoundEndTriggered ) {
|
|
read_data( 2, t_sText, MAX_TEXT_LENGTH );
|
|
if( t_sText[7] == 't' ) // Terrorist wins
|
|
g_izTeamScore[0]++;
|
|
else if( t_sText[7] == 'c' ) // CT wins
|
|
g_izTeamScore[1]++;
|
|
}
|
|
|
|
// Flag round end triggered.
|
|
g_iRoundEndTriggered = 1;
|
|
|
|
// Display round end stats to all players.
|
|
endround_stats();
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
endround_stats() {
|
|
|
|
// Bail out if end round stats has already been processed
|
|
// or round end not triggered.
|
|
if( g_iRoundEndProcessed || !g_iRoundEndTriggered ) return;
|
|
|
|
new iaPlayers[32], iPlayer, iPlayers, id;
|
|
|
|
get_players( iaPlayers, iPlayers );
|
|
|
|
#if defined STATSX_OLD_DEATHMSG
|
|
// Bail out if not all killers got their damage event (ie last stats)
|
|
for( iPlayer = 0; iPlayer < iPlayers; iPlayer++ ) {
|
|
id = iaPlayers[iPlayer];
|
|
if( g_izKilled[id][KILLED_KILLER_ID] && !g_izKilled[id][KILLED_KILLER_STATSFIX] )
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Display attacker & victim list for all living players.
|
|
// This will also update all round and game stats for all players
|
|
// not killed.
|
|
#if defined STATSX_DEBUG
|
|
log_message( "[%s] End round stats", PLUGIN_NAME );
|
|
#endif
|
|
for( iPlayer = 0; iPlayer < iPlayers; iPlayer++ ) {
|
|
id = iaPlayers[iPlayer];
|
|
if( g_fzShowUserStatsTime[id] == 0.0 )
|
|
kill_stats( id );
|
|
}
|
|
|
|
g_sAwardAndScore[0] = 0;
|
|
|
|
// Create round awards.
|
|
if( ShowMostDisruptive )
|
|
add_most_disruptive( g_sAwardAndScore );
|
|
if( ShowBestScore )
|
|
add_best_score( g_sAwardAndScore );
|
|
|
|
// Create round score.
|
|
// Compensate HUD message if awards are disabled.
|
|
if( ShowTeamScore || ShowTotalStats ) {
|
|
if( ShowMostDisruptive && ShowBestScore )
|
|
add( g_sAwardAndScore, MAX_BUFFER_LENGTH, "^n^n" );
|
|
else if( ShowMostDisruptive || ShowBestScore )
|
|
add( g_sAwardAndScore, MAX_BUFFER_LENGTH, "^n^n^n^n" );
|
|
else
|
|
add( g_sAwardAndScore, MAX_BUFFER_LENGTH, "^n^n^n^n^n^n" );
|
|
if( ShowTeamScore )
|
|
add_team_score( g_sAwardAndScore );
|
|
if( ShowTotalStats )
|
|
add_total_stats( g_sAwardAndScore );
|
|
}
|
|
|
|
save_team_chatscore();
|
|
|
|
// Get and save round end stats time.
|
|
g_fShowStatsTime = get_gametime();
|
|
|
|
// Display round end stats to all players.
|
|
for( iPlayer = 0; iPlayer < iPlayers; iPlayer++ ) {
|
|
id = iaPlayers[iPlayer];
|
|
show_roundend_hudstats( id, 0.0 );
|
|
}
|
|
|
|
// Flag round end processed.
|
|
g_iRoundEndProcessed = 1;
|
|
|
|
return;
|
|
}
|
|
|
|
public eventTeamScore() {
|
|
new sTeamID[1+1], iTeamScore;
|
|
read_data( 1, sTeamID, 1 );
|
|
iTeamScore = read_data(2);
|
|
g_izTeamEventScore[ (sTeamID[0]=='C') ? 1 : 0 ] = iTeamScore;
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public eventIntermission() {
|
|
if( EndPlayer || EndTop15 )
|
|
set_task( 1.0, "end_game_stats", 900 );
|
|
}
|
|
|
|
public end_game_stats() {
|
|
new iaPlayers[32], iPlayer, iPlayers, id;
|
|
|
|
if( EndPlayer ) {
|
|
get_players( iaPlayers, iPlayers );
|
|
for( iPlayer = 0; iPlayer < iPlayers; iPlayer++ ) {
|
|
id = iaPlayers[iPlayer];
|
|
if( !g_izStatsSwitch[id] ) continue; // Do not show any stats
|
|
cmdStatsMe( iaPlayers[iPlayer] );
|
|
}
|
|
}
|
|
else if( EndTop15 ) {
|
|
get_players( iaPlayers, iPlayers );
|
|
format_top15( g_sBuffer );
|
|
for( iPlayer = 0; iPlayer < iPlayers; iPlayer++ ) {
|
|
id = iaPlayers[iPlayer];
|
|
if( !g_izStatsSwitch[id] ) continue; // Do not show any stats
|
|
show_motd( iaPlayers[iPlayer], g_sBuffer, "Top 15" );
|
|
}
|
|
}
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public eventSpecMode( id ) {
|
|
new sData[12];
|
|
read_data( 2, sData, 11 );
|
|
g_izSpecMode[id] = ( sData[10] == '2' );
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public eventShowRank( id ) {
|
|
if( SpecRankInfo && g_izSpecMode[id] ) {
|
|
new iPlayer = read_data(2);
|
|
if( is_user_connected( iPlayer ) ) {
|
|
new izStats[8], izBody[8];
|
|
new iRankPos, iRankMax;
|
|
get_user_name( iPlayer, t_sName, MAX_NAME_LENGTH );
|
|
iRankPos = get_user_stats( iPlayer, izStats, izBody );
|
|
iRankMax = get_statsnum();
|
|
set_hudtype_specmode();
|
|
show_hudmessage( id, "%s's rank is %d of %d", t_sName, iRankPos, iRankMax );
|
|
}
|
|
}
|
|
return PLUGIN_CONTINUE;
|
|
}
|
|
|
|
public client_connect( id ) {
|
|
if( ShowStats ) {
|
|
get_user_info( id, "_amxstatsx", t_sText, MAX_TEXT_LENGTH );
|
|
g_izStatsSwitch[id] = ( t_sText[0] ) ? str_to_num( t_sText ) : -1 ;
|
|
}
|
|
else
|
|
g_izStatsSwitch[id] = 0;
|
|
|
|
g_izKilled[id][KILLED_KILLER_ID] = 0;
|
|
g_izKilled[id][KILLED_KILLER_STATSFIX] = 0;
|
|
g_izShowStatsFlags[id] = 0; // Clear all flags
|
|
g_fzShowUserStatsTime[id] = 0.0;
|
|
|
|
return PLUGIN_CONTINUE;
|
|
}
|