Untitled diff

Created Diff never expires
/**
/**
* L4D2_skill_detect
* L4D2_skill_detect
*
*
* Plugin to detect and forward reports about 'skill'-actions,
* Plugin to detect and forward reports about 'skill'-actions,
* such as skeets, crowns, levels, dp's.
* such as skeets, crowns, levels, dp's.
* Works in campaign and versus modes.
* Works in campaign and versus modes.
*
*
* m_isAttemptingToPounce can only be trusted for
* m_isAttemptingToPounce can only be trusted for
* AI hunters -- for human hunters this gets cleared
* AI hunters -- for human hunters this gets cleared
* instantly on taking killing damage
* instantly on taking killing damage
*
*
* Shotgun skeets and teamskeets are only counted if the
* Shotgun skeets and teamskeets are only counted if the
* added up damage to pounce_interrupt is done by shotguns
* added up damage to pounce_interrupt is done by shotguns
* only. 'Skeeting' chipped hunters shouldn't count, IMO.
* only. 'Skeeting' chipped hunters shouldn't count, IMO.
*
*
* This performs global forward calls to:
* This performs global forward calls to:
* OnSkeet( survivor, hunter )
* OnSkeet( survivor, hunter )
* OnSkeetMelee( survivor, hunter )
* OnSkeetMelee( survivor, hunter )
* OnSkeetGL( survivor, hunter )
* OnSkeetGL( survivor, hunter )
* OnSkeetSniper( survivor, hunter )
* OnSkeetSniper( survivor, hunter )
* OnSkeetHurt( survivor, hunter, damage, isOverkill )
* OnSkeetHurt( survivor, hunter, damage, isOverkill )
* OnSkeetMeleeHurt( survivor, hunter, damage, isOverkill )
* OnSkeetMeleeHurt( survivor, hunter, damage, isOverkill )
* OnSkeetSniperHurt( survivor, hunter, damage, isOverkill )
* OnSkeetSniperHurt( survivor, hunter, damage, isOverkill )
* OnHunterDeadstop( survivor, hunter )
* OnHunterDeadstop( survivor, hunter )
* OnBoomerPop( survivor, boomer, shoveCount, Float:timeAlive )
* OnBoomerPop( survivor, boomer, shoveCount, Float:timeAlive )
* OnChargerLevel( survivor, charger )
* OnChargerLevel( survivor, charger )
* OnChargerLevelHurt( survivor, charger, damage )
* OnChargerLevelHurt( survivor, charger, damage )
* OnWitchCrown( survivor, damage )
* OnWitchCrown( survivor, damage )
* OnWitchCrownHurt( survivor, damage, chipdamage )
* OnWitchCrownHurt( survivor, damage, chipdamage )
* OnTongueCut( survivor, smoker )
* OnTongueCut( survivor, smoker )
* OnSmokerSelfClear( survivor, smoker, withShove )
* OnSmokerSelfClear( survivor, smoker, withShove )
* OnTankRockSkeeted( survivor, tank )
* OnTankRockSkeeted( survivor, tank )
* OnTankRockEaten( tank, survivor )
* OnTankRockEaten( tank, survivor )
* OnHunterHighPounce( hunter, victim, actualDamage, Float:calculatedDamage, Float:height, bool:bReportedHigh, bool:bPlayerIncapped )
* OnHunterHighPounce( hunter, victim, actualDamage, Float:calculatedDamage, Float:height, bool:bReportedHigh, bool:bPlayerIncapped )
* OnJockeyHighPounce( jockey, victim, Float:height, bool:bReportedHigh )
* OnJockeyHighPounce( jockey, victim, Float:height, bool:bReportedHigh )
* OnDeathCharge( charger, victim, Float: height, Float: distance, wasCarried )
* OnDeathCharge( charger, victim, Float: height, Float: distance, wasCarried )
* OnSpecialShoved( survivor, infected, zombieClass )
* OnSpecialShoved( survivor, infected, zombieClass )
* OnSpecialClear( clearer, pinner, pinvictim, zombieClass, Float:timeA, Float:timeB, withShove )
* OnSpecialClear( clearer, pinner, pinvictim, zombieClass, Float:timeA, Float:timeB, withShove )
* OnBoomerVomitLanded( boomer, amount )
* OnBoomerVomitLanded( boomer, amount )
* OnBunnyHopStreak( survivor, streak, Float:maxVelocity )
* OnBunnyHopStreak( survivor, streak, Float:maxVelocity )
* OnCarAlarmTriggered( survivor, infected, reason )
* OnCarAlarmTriggered( survivor, infected, reason )
*
*
* OnDeathChargeAssist( assister, charger, victim ) [ not done yet ]
* OnDeathChargeAssist( assister, charger, victim ) [ not done yet ]
* OnBHop( player, isInfected, speed, streak ) [ not done yet ]
* OnBHop( player, isInfected, speed, streak ) [ not done yet ]
*
*
* Where survivor == -2 if it was a team effort, -1 or 0 if unknown or invalid client.
* Where survivor == -2 if it was a team effort, -1 or 0 if unknown or invalid client.
* damage is the amount of damage done (that didn't add up to skeeting damage),
* damage is the amount of damage done (that didn't add up to skeeting damage),
* and isOverkill indicates whether the shot would've been a skeet if the hunter
* and isOverkill indicates whether the shot would've been a skeet if the hunter
* had not been chipped.
* had not been chipped.
*
*
* @author Tabun
* @author Tabun
* @libraryname skill_detect
* @libraryname skill_detect
*/
*/


#pragma semicolon 1
#pragma semicolon 1


#include <sourcemod>
#include <sourcemod>
#include <sdkhooks>
#include <sdkhooks>
#include <sdktools>
#include <sdktools>
#include <l4d2_direct>
#include <l4d2_direct>


#define PLUGIN_VERSION "0.9.19"
#define PLUGIN_VERSION "0.9.19"


#define IS_VALID_CLIENT(%1) (%1 > 0 && %1 <= MaxClients)
#define IS_VALID_CLIENT(%1) (%1 > 0 && %1 <= MaxClients)
#define IS_SURVIVOR(%1) (GetClientTeam(%1) == 2)
#define IS_SURVIVOR(%1) (GetClientTeam(%1) == 2)
#define IS_INFECTED(%1) (GetClientTeam(%1) == 3)
#define IS_INFECTED(%1) (GetClientTeam(%1) == 3)
#define IS_VALID_INGAME(%1) (IS_VALID_CLIENT(%1) && IsClientInGame(%1))
#define IS_VALID_INGAME(%1) (IS_VALID_CLIENT(%1) && IsClientInGame(%1))
#define IS_VALID_SURVIVOR(%1) (IS_VALID_INGAME(%1) && IS_SURVIVOR(%1))
#define IS_VALID_SURVIVOR(%1) (IS_VALID_INGAME(%1) && IS_SURVIVOR(%1))
#define IS_VALID_INFECTED(%1) (IS_VALID_INGAME(%1) && IS_INFECTED(%1))
#define IS_VALID_INFECTED(%1) (IS_VALID_INGAME(%1) && IS_INFECTED(%1))
#define IS_SURVIVOR_ALIVE(%1) (IS_VALID_SURVIVOR(%1) && IsPlayerAlive(%1))
#define IS_SURVIVOR_ALIVE(%1) (IS_VALID_SURVIVOR(%1) && IsPlayerAlive(%1))
#define IS_INFECTED_ALIVE(%1) (IS_VALID_INFECTED(%1) && IsPlayerAlive(%1))
#define IS_INFECTED_ALIVE(%1) (IS_VALID_INFECTED(%1) && IsPlayerAlive(%1))
#define QUOTES(%1) (%1)
#define QUOTES(%1) (%1)


#define SHOTGUN_BLAST_TIME 0.1
#define SHOTGUN_BLAST_TIME 0.1
#define POUNCE_CHECK_TIME 0.1
#define POUNCE_CHECK_TIME 0.1
#define HOP_CHECK_TIME 0.1
#define HOP_CHECK_TIME 0.1
#define HOPEND_CHECK_TIME 0.1 // after streak end (potentially) detected, to check for realz?
#define HOPEND_CHECK_TIME 0.1 // after streak end (potentially) detected, to check for realz?
#define SHOVE_TIME 0.05
#define SHOVE_TIME 0.05
#define MAX_CHARGE_TIME 12.0 // maximum time to pass before charge checking ends
#define MAX_CHARGE_TIME 12.0 // maximum time to pass before charge checking ends
#define CHARGE_CHECK_TIME 0.25 // check interval for survivors flying from impacts
#define CHARGE_CHECK_TIME 0.25 // check interval for survivors flying from impacts
#define CHARGE_END_CHECK 2.5 // after client hits ground after getting impact-charged: when to check whether it was a death
#define CHARGE_END_CHECK 2.5 // after client hits ground after getting impact-charged: when to check whether it was a death
#define CHARGE_END_RECHECK 3.0 // safeguard wait to recheck on someone getting incapped out of bounds
#define CHARGE_END_RECHECK 3.0 // safeguard wait to recheck on someone getting incapped out of bounds
#define VOMIT_DURATION_TIME 2.25 // how long the boomer vomit stream lasts -- when to check for boom count
#define VOMIT_DURATION_TIME 2.25 // how long the boomer vomit stream lasts -- when to check for boom count
#define ROCK_CHECK_TIME 0.34 // how long to wait after rock entity is destroyed before checking for skeet/eat (high to avoid lag issues)
#define ROCK_CHECK_TIME 0.34 // how long to wait after rock entity is destroyed before checking for skeet/eat (high to avoid lag issues)
#define CARALARM_MIN_TIME 0.11 // maximum time after touch/shot => alarm to connect the two events (test this for LAG)
#define CARALARM_MIN_TIME 0.11 // maximum time after touch/shot => alarm to connect the two events (test this for LAG)


#define WITCH_CHECK_TIME 0.1 // time to wait before checking for witch crown after shoots fired
#define WITCH_CHECK_TIME 0.1 // time to wait before checking for witch crown after shoots fired
#define WITCH_DELETE_TIME 0.15 // time to wait before deleting entry from witch trie after entity is destroyed
#define WITCH_DELETE_TIME 0.15 // time to wait before deleting entry from witch trie after entity is destroyed


#define MIN_DC_TRIGGER_DMG 300 // minimum amount a 'trigger' / drown must do before counted as a death action
#define MIN_DC_TRIGGER_DMG 300 // minimum amount a 'trigger' / drown must do before counted as a death action
#define MIN_DC_FALL_DMG 175 // minimum amount of fall damage counts as death-falling for a deathcharge
#define MIN_DC_FALL_DMG 175 // minimum amount of fall damage counts as death-falling for a deathcharge
#define WEIRD_FLOW_THRESH 900.0 // -9999 seems to be break flow.. but meh
#define WEIRD_FLOW_THRESH 900.0 // -9999 seems to be break flow.. but meh
#define MIN_FLOWDROPHEIGHT 350.0 // minimum height a survivor has to have dropped before a WEIRD_FLOW value is treated as a DC spot
#define MIN_FLOWDROPHEIGHT 350.0 // minimum height a survivor has to have dropped before a WEIRD_FLOW value is treated as a DC spot
#define MIN_DC_RECHECK_DMG 100 // minimum damage from map to have taken on first check, to warrant recheck
#define MIN_DC_RECHECK_DMG 100 // minimum damage from map to have taken on first check, to warrant recheck


#define HOP_ACCEL_THRESH 0.01 // bhop speed increase must be higher than this for it to count as part of a hop streak
#define HOP_ACCEL_THRESH 0.01 // bhop speed increase must be higher than this for it to count as part of a hop streak


#define ZC_SMOKER 1
#define ZC_SMOKER 1
#define ZC_BOOMER 2
#define ZC_BOOMER 2
#define ZC_HUNTER 3
#define ZC_HUNTER 3
#define ZC_JOCKEY 5
#define ZC_JOCKEY 5
#define ZC_CHARGER 6
#define ZC_CHARGER 6
#define ZC_TANK 8
#define ZC_TANK 8
#define HITGROUP_HEAD 1
#define HITGROUP_HEAD 1


#define DMG_CRUSH (1 << 0) // crushed by falling or moving object.
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object.
#define DMG_BULLET (1 << 1) // shot
#define DMG_BULLET (1 << 1) // shot
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_BUCKSHOT (1 << 29) // not quite a bullet. Little, rounder, different.
#define DMG_BUCKSHOT (1 << 29) // not quite a bullet. Little, rounder, different.


#define DMGARRAYEXT 7 // MAXPLAYERS+# -- extra indices in witch_dmg_array + 1
#define DMGARRAYEXT 7 // MAXPLAYERS+# -- extra indices in witch_dmg_array + 1


#define CUT_SHOVED 1 // smoker got shoved
#define CUT_SHOVED 1 // smoker got shoved
#define CUT_SHOVEDSURV 2 // survivor got shoved
#define CUT_SHOVEDSURV 2 // survivor got shoved
#define CUT_KILL 3 // reason for tongue break (release_type)
#define CUT_KILL 3 // reason for tongue break (release_type)
#define CUT_SLASH 4 // this is used for others shoving a survivor free too, don't trust .. it involves tongue damage?
#define CUT_SLASH 4 // this is used for others shoving a survivor free too, don't trust .. it involves tongue damage?


#define VICFLG_CARRIED (1 << 0) // was the one that the charger carried (not impacted)
#define VICFLG_CARRIED (1 << 0) // was the one that the charger carried (not impacted)
#define VICFLG_FALL (1 << 1) // flags stored per charge victim, to check for deathchargeroony -- fallen
#define VICFLG_FALL (1 << 1) // flags stored per charge victim, to check for deathchargeroony -- fallen
#define VICFLG_DROWN (1 << 2) // drowned
#define VICFLG_DROWN (1 << 2) // drowned
#define VICFLG_HURTLOTS (1 << 3) // whether the victim was hurt by 400 dmg+ at once
#define VICFLG_HURTLOTS (1 << 3) // whether the victim was hurt by 400 dmg+ at once
#define VICFLG_TRIGGER (1 << 4) // killed by trigger_hurt
#define VICFLG_TRIGGER (1 << 4) // killed by trigger_hurt
#define VICFLG_AIRDEATH (1 << 5) // died before they hit the ground (impact check)
#define VICFLG_AIRDEATH (1 << 5) // died before they hit the ground (impact check)
#define VICFLG_KILLEDBYOTHER (1 << 6) // if the survivor was killed by an SI other than the charger
#define VICFLG_KILLEDBYOTHER (1 << 6) // if the survivor was killed by an SI other than the charger
#define VICFLG_WEIRDFLOW (1 << 7) // when survivors get out of the map and such
#define VICFLG_WEIRDFLOW (1 << 7) // when survivors get out of the map and such
#define VICFLG_WEIRDFLOWDONE (1 << 8) // checked, don't recheck for this
#define VICFLG_WEIRDFLOWDONE (1 << 8) // checked, don't recheck for this


#define REP_SKEET (1 << 0)
#define REP_SKEET (1 << 0)
#define REP_HURTSKEET (1 << 1)
#define REP_HURTSKEET (1 << 1)
#define REP_LEVEL (1 << 2)
#define REP_LEVEL (1 << 2)
#define REP_HURTLEVEL (1 << 3)
#define REP_HURTLEVEL (1 << 3)
#define REP_CROWN (1 << 4)
#define REP_CROWN (1 << 4)
#define REP_DRAWCROWN (1 << 5)
#define REP_DRAWCROWN (1 << 5)
#define REP_TONGUECUT (1 << 6)
#define REP_TONGUECUT (1 << 6)
#define REP_SELFCLEAR (1 << 7)
#define REP_SELFCLEAR (1 << 7)
#define REP_SELFCLEARSHOVE (1 << 8)
#define REP_SELFCLEARSHOVE (1 << 8)
#define REP_ROCKSKEET (1 << 9)
#define REP_ROCKSKEET (1 << 9)
#define REP_DEADSTOP (1 << 10)
#define REP_DEADSTOP (1 << 10)
#define REP_POP (1 << 11)
#define REP_POP (1 << 11)
#define REP_SHOVE (1 << 12)
#define REP_SHOVE (1 << 12)
#define REP_HUNTERDP (1 << 13)
#define REP_HUNTERDP (1 << 13)
#define REP_JOCKEYDP (1 << 14)
#define REP_JOCKEYDP (1 << 14)
#define REP_DEATHCHARGE (1 << 15)
#define REP_DEATHCHARGE (1 << 15)
#define REP_DC_ASSIST (1 << 16)
#define REP_DC_ASSIST (1 << 16)
#define REP_INSTACLEAR (1 << 17) // 131072
#define REP_INSTACLEAR (1 << 17) // 131072
#define REP_BHOPSTREAK (1 << 18) // 262144
#define REP_BHOPSTREAK (1 << 18) // 262144
#define REP_CARALARM (1 << 19) // 524288
#define REP_CARALARM (1 << 19) // 524288


#define REP_DEFAULT "581685" // (REP_SKEET | REP_LEVEL | REP_CROWN | REP_DRAWCROWN | REP_HUNTERDP | REP_JOCKEYDP | REP_DEATHCHARGE | REP_CARALARM)
#define REP_DEFAULT "581685" // (REP_SKEET | REP_LEVEL | REP_CROWN | REP_DRAWCROWN | REP_HUNTERDP | REP_JOCKEYDP | REP_DEATHCHARGE | REP_CARALARM)
// 1 4 16 32 8192 16384 32768 65536 (122933 with ASSIST, 57397 without); 131072 for instaclears + 524288 for car alarm
// 1 4 16 32 8192 16384 32768 65536 (122933 with ASSIST, 57397 without); 131072 for instaclears + 524288 for car alarm




// trie values: weapon type
// trie values: weapon type
enum strWeaponType
enum strWeaponType
{
{
WPTYPE_SNIPER,
WPTYPE_SNIPER,
WPTYPE_MAGNUM,
WPTYPE_MAGNUM,
WPTYPE_GL
WPTYPE_GL
};
};


// trie values: OnEntityCreated classname
// trie values: OnEntityCreated classname
enum strOEC
enum strOEC
{
{
OEC_WITCH,
OEC_WITCH,
OEC_TANKROCK,
OEC_TANKROCK,
OEC_TRIGGER,
OEC_TRIGGER,
OEC_CARALARM,
OEC_CARALARM,
OEC_CARGLASS
OEC_CARGLASS
};
};


// trie values: special abilities
// trie values: special abilities
enum strAbility
enum strAbility
{
{
ABL_HUNTERLUNGE,
ABL_HUNTERLUNGE,
ABL_ROCKTHROW
ABL_ROCKTHROW
};
};


enum _:strRockData
enum strRockData
{
{
rckDamage,
rckDamage,
rckTank,
rckTank,
rckSkeeter
rckSkeeter
};
};


// witch array entries (maxplayers+index)
// witch array entries (maxplayers+index)
enum _:strWitchArray
enum strWitchArray
{
{
WTCH_NONE,
WTCH_NONE,
WTCH_HEALTH,
WTCH_HEALTH,
WTCH_GOTSLASH,
WTCH_GOTSLASH,
WTCH_STARTLED,
WTCH_STARTLED,
WTCH_CROWNER,
WTCH_CROWNER,
WTCH_CROWNSHOT,
WTCH_CROWNSHOT,
WTCH_CROWNTYPE
WTCH_CROWNTYPE
};
};


enum _:enAlarmReasons
enum enAlarmReasons
{
{
CALARM_UNKNOWN,
CALARM_UNKNOWN,
CALARM_HIT,
CALARM_HIT,
CALARM_TOUCHED,
CALARM_TOUCHED,
CALARM_EXPLOSION,
CALARM_EXPLOSION,
CALARM_BOOMER
CALARM_BOOMER
};
};


new const String: g_csSIClassName[][] =
new const String: g_csSIClassName[][] =
{
{
"",
"",
"smoker",
"smoker",
"boomer",
"boomer",
"hunter",
"hunter",
"spitter",
"spitter",
"jockey",
"jockey",
"charger",
"charger",
"witch",
"witch",
"tank"
"tank"
};
};


new bool: g_bLateLoad = false;
new bool: g_bLateLoad = false;


new Handle: g_hForwardSkeet = INVALID_HANDLE;
new Handle: g_hForwardSkeet = INVALID_HANDLE;
new Handle: g_hForwardSkeetHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetMelee = INVALID_HANDLE;
new Handle: g_hForwardSkeetMelee = INVALID_HANDLE;
new Handle: g_hForwardSkeetMeleeHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetMeleeHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetSniper = INVALID_HANDLE;
new Handle: g_hForwardSkeetSniper = INVALID_HANDLE;
new Handle: g_hForwardSkeetSniperHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetSniperHurt = INVALID_HANDLE;
new Handle: g_hForwardSkeetGL = INVALID_HANDLE;
new Handle: g_hForwardSkeetGL = INVALID_HANDLE;
new Handle: g_hForwardHunterDeadstop = INVALID_HANDLE;
new Handle: g_hForwardHunterDeadstop = INVALID_HANDLE;
new Handle: g_hForwardSIShove = INVALID_HANDLE;
new Handle: g_hForwardSIShove = INVALID_HANDLE;
new Handle: g_hForwardBoomerPop = INVALID_HANDLE;
new Handle: g_hForwardBoomerPop = INVALID_HANDLE;
new Handle: g_hForwardLevel = INVALID_HANDLE;
new Handle: g_hForwardLevel = INVALID_HANDLE;
new Handle: g_hForwardLevelHurt = INVALID_HANDLE;
new Handle: g_hForwardLevelHurt = INVALID_HANDLE;
new Handle: g_hForwardCrown = INVALID_HANDLE;
new Handle: g_hForwardCrown = INVALID_HANDLE;
new Handle: g_hForwardDrawCrown = INVALID_HANDLE;
new Handle: g_hForwardDrawCrown = INVALID_HANDLE;
new Handle: g_hForwardTongueCut = INVALID_HANDLE;
new Handle: g_hForwardTongueCut = INVALID_HANDLE;
new Handle: g_hForwardSmokerSelfClear = INVALID_HANDLE;
new Handle: g_hForwardSmokerSelfClear = INVALID_HANDLE;
new Handle: g_hForwardRockSkeeted = INVALID_HANDLE;
new Handle: g_hForwardRockSkeeted = INVALID_HANDLE;
new Handle: g_hForwardRockEaten = INVALID_HANDLE;
new Handle: g_hForwardRockEaten = INVALID_HANDLE;
new Handle: g_hForwardHunterDP = INVALID_HANDLE;
new Handle: g_hForwardHunterDP = INVALID_HANDLE;
new Handle: g_hForwardJockeyDP = INVALID_HANDLE;
new Handle: g_hForwardJockeyDP = INVALID_HANDLE;
new Handle: g_hForwardDeathCharge = INVALID_HANDLE;
new Handle: g_hForwardDeathCharge = INVALID_HANDLE;
new Handle: g_hForwardClear = INVALID_HANDLE;
new Handle: g_hForwardClear = INVALID_HANDLE;
new Handle: g_hForwardVomitLanded = INVALID_HANDLE;
new Handle: g_hForwardVomitLanded = INVALID_HANDLE;
new Handle: g_hForwardBHopStreak = INVALID_HANDLE;
new Handle: g_hForwardBHopStreak = INVALID_HANDLE;
new Handle: g_hForwardAlarmTriggered = INVALID_HANDLE;
new Handle: g_hForwardAlarmTriggered = INVALID_HANDLE;


new Handle: g_hTrieWeapons = INVALID_HANDLE; // weapon check
new Handle: g_hTrieWeapons = INVALID_HANDLE; // weapon check
new Handle: g_hTrieEntityCreated = INVALID_HANDLE; // getting classname of entity created
new Handle: g_hTrieEntityCreated = INVALID_HANDLE; // getting classname of entity created
new Handle: g_hTrieAbility = INVALID_HANDLE; // ability check
new Handle: g_hTrieAbility = INVALID_HANDLE; // ability check
new Handle: g_hWitchTrie = INVALID_HANDLE; // witch tracking (Crox)
new Handle: g_hWitchTrie = INVALID_HANDLE; // witch tracking (Crox)
new Handle: g_hRockTrie = INVALID_HANDLE; // tank rock tracking
new Handle: g_hRockTrie = INVALID_HANDLE; // tank rock tracking
new Handle: g_hCarTrie = INVALID_HANDLE; // car alarm tracking
new Handle: g_hCarTrie = INVALID_HANDLE; // car alarm tracking


// all SI / pinners
// all SI / pinners
new Float: g_fSpawnTime [MAXPLAYERS + 1]; // time the SI spawned up
new Float: g_fSpawnTime [MAXPLAYERS + 1]; // time the SI spawned up
new Float: g_fPinTime [MAXPLAYERS + 1][2]; // time the SI pinned a target: 0 = start of pin (tongue pull, charger carry); 1 = carry end / tongue reigned in
new Float: g_fPinTime [MAXPLAYERS + 1][2]; // time the SI pinned a target: 0 = start of pin (tongue pull, charger carry); 1 = carry end / tongue reigned in
new g_iSpecialVictim [MAXPLAYERS + 1]; // current victim (set in traceattack, so we can check on death)
new g_iSpecialVictim [MAXPLAYERS + 1]; // current victim (set in traceattack, so we can check on death)


// hunters: skeets/pounces
// hunters: skeets/pounces
new g_iHunterShotDmgTeam [MAXPLAYERS + 1]; // counting shotgun blast damage for hunter, counting entire survivor team's damage
new g_iHunterShotDmgTeam [MAXPLAYERS + 1]; // counting shotgun blast damage for hunter, counting entire survivor team's damage
new g_iHunterShotDmg [MAXPLAYERS + 1][MAXPLAYERS + 1]; // counting shotgun blast damage for hunter / skeeter combo
new g_iHunterShotDmg [MAXPLAYERS + 1][MAXPLAYERS + 1]; // counting shotgun blast damage for hunter / skeeter combo
new Float: g_fHunterShotStart [MAXPLAYERS + 1][MAXPLAYERS + 1]; // when the last shotgun blast on hunter started (if at any time) by an attacker
new Float: g_fHunterShotStart [MAXPLAYERS + 1][MAXPLAYERS + 1]; // when the last shotgun blast on hunter started (if at any time) by an attacker
new Float: g_fHunterTracePouncing [MAXPLAYERS + 1]; // time when the hunter was still pouncing (in traceattack) -- used to detect pouncing status
new Float: g_fHunterTracePouncing [MAXPLAYERS + 1]; // time when the hunter was still pouncing (in traceattack) -- used to detect pouncing status
new Float: g_fHunterLastShot [MAXPLAYERS + 1]; // when the last shotgun damage was done (by anyone) on a hunter
new Float: g_fHunterLastShot [MAXPLAYERS + 1]; // when the last shotgun damage was done (by anyone) on a hunter
new g_iHunterLastHealth [MAXPLAYERS + 1]; // last time hunter took any damage, how much health did it have left?
new g_iHunterLastHealth [MAXPLAYERS + 1]; // last time hunter took any damage, how much health did it have left?
new g_iHunterOverkill [MAXPLAYERS + 1]; // how much more damage a hunter would've taken if it wasn't already dead
new g_iHunterOverkill [MAXPLAYERS + 1]; // how much more damage a hunter would've taken if it wasn't already dead
new bool: g_bHunterKilledPouncing [MAXPLAYERS + 1]; // whether the hunter was killed when actually pouncing
new bool: g_bHunterKilledPouncing [MAXPLAYERS + 1]; // whether the hunter was killed when actually pouncing
new g_iPounceDamage [MAXPLAYERS + 1]; // how much damage on last 'highpounce' done
new g_iPounceDamage [MAXPLAYERS + 1]; // how much damage on last 'highpounce' done
new Float: g_fPouncePosition [MAXPLAYERS + 1][3]; // position that a hunter (jockey?) pounced from (or charger started his carry)
new Float: g_fPouncePosition [MAXPLAYERS + 1][3]; // position that a hunter (jockey?) pounced from (or charger started his carry)


// deadstops
// deadstops
new Float: g_fVictimLastShove [MAXPLAYERS + 1][MAXPLAYERS + 1]; // when was the player shoved last by attacker? (to prevent doubles)
new Float: g_fVictimLastShove [MAXPLAYERS + 1][MAXPLAYERS + 1]; // when was the player shoved last by attacker? (to prevent doubles)


// levels / charges
// levels / charges
new g_iChargerHealth [MAXPLAYERS + 1]; // how much health the charger had the last time it was seen taking damage
new g_iChargerHealth [MAXPLAYERS + 1]; // how much health the charger had the last time it was seen taking damage
new Float: g_fChargeTime [MAXPLAYERS + 1]; // time the charger's charge last started, or if victim, when impact started
new Float: g_fChargeTime [MAXPLAYERS + 1]; // time the charger's charge last started, or if victim, when impact started
new g_iChargeVictim [MAXPLAYERS + 1]; // who got charged
new g_iChargeVictim [MAXPLAYERS + 1]; // who got charged
new Float: g_fChargeVictimPos [MAXPLAYERS + 1][3]; // location of each survivor when it got hit by the charger
new Float: g_fChargeVictimPos [MAXPLAYERS + 1][3]; // location of each survivor when it got hit by the charger
new g_iVictimCharger [MAXPLAYERS + 1]; // for a victim, by whom they got charge(impacted)
new g_iVictimCharger [MAXPLAYERS + 1]; // for a victim, by whom they got charge(impacted)
new g_iVictimFlags [MAXPLAYERS + 1]; // flags stored per charge victim: VICFLAGS_
new g_iVictimFlags [MAXPLAYERS + 1]; // flags stored per charge victim: VICFLAGS_
new g_iVictimMapDmg [MAXPLAYERS + 1]; // for a victim, how much the cumulative map damage is so far (trigger hurt / drowning)
new g_iVictimMapDmg [MAXPLAYERS + 1]; // for a victim, how much the cumulative map damage is so far (trigger hurt / drowning)


// pops
// pops
new bool: g_bBoomerHitSomebody [MAXPLAYERS + 1]; // false if boomer didn't puke/exploded on anybody
new bool: g_bBoomerHitSomebody [MAXPLAYERS + 1]; // false if boomer didn't puke/exploded on anybody
new g_iBoomerGotShoved [MAXPLAYERS + 1]; // count boomer was shoved at any point
new g_iBoomerGotShoved [MAXPLAYERS + 1]; // count boomer was shoved at any point
new g_iBoomerVomitHits [MAXPLAYERS + 1]; // how many booms in one vomit so far
new g_iBoomerVomitHits [MAXPLAYERS + 1]; // how many booms in one vomit so far


// crowns
// crowns
new Float: g_fWitchShotStart [MAXPLAYERS + 1]; // when the last shotgun blast from a survivor started (on any witch)
new Float: g_fWitchShotStart [MAXPLAYERS + 1]; // when the last shotgun blast from a survivor started (on any witch)


// smoker clears
// smoker clears
new bool: g_bSmokerClearCheck [MAXPLAYERS + 1]; // [smoker] smoker dies and this is set, it's a self-clear if g_iSmokerVictim is the killer
new bool: g_bSmokerClearCheck [MAXPLAYERS + 1]; // [smoker] smoker dies and this is set, it's a self-clear if g_iSmokerVictim is the killer
new g_iSmokerVictim [MAXPLAYERS + 1]; // [smoker] the one that's being pulled
new g_iSmokerVictim [MAXPLAYERS + 1]; // [smoker] the one that's being pulled
new g_iSmokerVictimDamage [MAXPLAYERS + 1]; // [smoker] amount of damage done to a smoker by the one he pulled
new g_iSmokerVictimDamage [MAXPLAYERS + 1]; // [smoker] amount of damage done to a smoker by the one he pulled
new bool: g_bSmokerShoved [MAXPLAYERS + 1]; // [smoker] set if the victim of a pull manages to shove the smoker
new bool: g_bSmokerShoved [MAXPLAYERS + 1]; // [smoker] set if the victim of a pull manages to shove the smoker


// rocks
// rocks
new g_iTankRock [MAXPLAYERS + 1]; // rock entity per tank
new g_iTankRock [MAXPLAYERS + 1]; // rock entity per tank
new g_iRocksBeingThrown [10]; // 10 tanks max simultanously throwing rocks should be ok (this stores the tank client)
new g_iRocksBeingThrown [10]; // 10 tanks max simultanously throwing rocks should be ok (this stores the tank client)
new g_iRocksBeingThrownCount = 0; // so we can do a push/pop type check for who is throwing a created rock
new g_iRocksBeingThrownCount = 0; // so we can do a push/pop type check for who is throwing a created rock


// hops
// hops
new bool: g_bIsHopping [MAXPLAYERS + 1]; // currently in a hop streak
new bool: g_bIsHopping [MAXPLAYERS + 1]; // currently in a hop streak
new bool: g_bHopCheck [MAXPLAYERS + 1]; // flag to check whether a hopstreak has ended (if on ground for too long.. ends)
new bool: g_bHopCheck [MAXPLAYERS + 1]; // flag to check whether a hopstreak has ended (if on ground for too long.. ends)
new g_iHops [MAXPLAYERS + 1]; // amount of hops in streak
new g_iHops [MAXPLAYERS + 1]; // amount of hops in streak
new Float: g_fLastHop [MAXPLAYERS + 1][3]; // velocity vector of last jump
new Float: g_fLastHop [MAXPLAYERS + 1][3]; // velocity vector of last jump
new Float: g_fHopTopVelocity [MAXPLAYERS + 1]; // maximum velocity in hopping streak
new Float: g_fHopTopVelocity [MAXPLAYERS + 1]; // maximum velocity in hopping streak


// alarms
// alarms
new Float: g_fLastCarAlarm = 0.0; // time when last car alarm went off
new Float: g_fLastCarAlarm = 0.0; // time when last car alarm went off
new g_iLastCarAlarmReason [MAXPLAYERS + 1]; // what this survivor did to set the last alarm off
new g_iLastCarAlarmReason [MAXPLAYERS + 1]; // what this survivor did to set the last alarm off
new g_iLastCarAlarmBoomer; // if a boomer triggered an alarm, remember it
new g_iLastCarAlarmBoomer; // if a boomer triggered an alarm, remember it


// cvars
// cvars
new Handle: g_hCvarReport = INVALID_HANDLE; // cvar whether to report at all
new Handle: g_hCvarReport = INVALID_HANDLE; // cvar whether to report at all
new Handle: g_hCvarReportFlags = INVALID_HANDLE; // cvar what to report
new Handle: g_hCvarReportFlags = INVALID_HANDLE; // cvar what to report


new Handle: g_hCvarAllowMelee = INVALID_HANDLE; // cvar whether to count melee skeets
new Handle: g_hCvarAllowMelee = INVALID_HANDLE; // cvar whether to count melee skeets
new Handle: g_hCvarAllowSniper = INVALID_HANDLE; // cvar whether to count sniper headshot skeets
new Handle: g_hCvarAllowSniper = INVALID_HANDLE; // cvar whether to count sniper headshot skeets
new Handle: g_hCvarAllowGLSkeet = INVALID_HANDLE; // cvar whether to count direct hit GL skeets
new Handle: g_hCvarAllowGLSkeet = INVALID_HANDLE; // cvar whether to count direct hit GL skeets
new Handle: g_hCvarDrawCrownThresh = INVALID_HANDLE; // cvar damage in final shot for drawcrown-req.
new Handle: g_hCvarDrawCrownThresh = INVALID_HANDLE; // cvar damage in final shot for drawcrown-req.
new Handle: g_hCvarSelfClearThresh = INVALID_HANDLE; // cvar damage while self-clearing from smokers
new Handle: g_hCvarSelfClearThresh = INVALID_HANDLE; // cvar damage while self-clearing from smokers
new Handle: g_hCvarHunterDPThresh = INVALID_HANDLE; // cvar damage for hunter highpounce
new Handle: g_hCvarHunterDPThresh = INVALID_HANDLE; // cvar damage for hunter highpounce
new Handle: g_hCvarJockeyDPThresh = INVALID_HANDLE; // cvar distance for jockey highpounce
new Handle: g_hCvarJockeyDPThresh = INVALID_HANDLE; // cvar distance for jockey highpounce
new Handle: g_hCvarHideFakeDamage = INVALID_HANDLE; // cvar damage while self-clearing from smokers
new Handle: g_hCvarHideFakeDamage = INVALID_HANDLE; // cvar damage while self-clearing from smokers
new Handle: g_hCvarDeathChargeHeight = INVALID_HANDLE; // cvar how high a charger must have come in order for a DC to count
new Handle: g_hCvarDeathChargeHeight = INVALID_HANDLE; // cvar how high a charger must have come in order for a DC to count
new Handle: g_hCvarInstaTime = INVALID_HANDLE; // cvar clear within this time or lower for instaclear
new Handle: g_hCvarInstaTime = INVALID_HANDLE; // cvar clear within this time or lower for instaclear
new Handle: g_hCvarBHopMinStreak = INVALID_HANDLE; // cvar this many hops in a row+ = streak
new Handle: g_hCvarBHopMinStreak = INVALID_HANDLE; // cvar this many hops in a row+ = streak
new Handle: g_hCvarBHopMinInitSpeed = INVALID_HANDLE; // cvar lower than this and the first jump won't be seen as the start of a streak
new Handle: g_hCvarBHopMinInitSpeed = INVALID_HANDLE; // cvar lower than this and the first jump won't be seen as the start of a streak
new Handle: g_hCvarBHopContSpeed = INVALID_HANDLE; // cvar
new Handle: g_hCvarBHopContSpeed = INVALID_HANDLE; // cvar


new Handle: g_hCvarPounceInterrupt = INVALID_HANDLE; // z_pounce_damage_interrupt
new Handle: g_hCvarPounceInterrupt = INVALID_HANDLE; // z_pounce_damage_interrupt
new g_iPounceInterrupt = 150;
new g_iPounceInterrupt = 150;
new Handle: g_hCvarChargerHealth = INVALID_HANDLE; // z_charger_health
new Handle: g_hCvarChargerHealth = INVALID_HANDLE; // z_charger_health
new Handle: g_hCvarWitchHealth = INVALID_HANDLE; // z_witch_health
new Handle: g_hCvarWitchHealth = INVALID_HANDLE; // z_witch_health
new Handle: g_hCvarMaxPounceDistance = INVALID_HANDLE; // z_pounce_damage_range_max
new Handle: g_hCvarMaxPounceDistance = INVALID_HANDLE; // z_pounce_damage_range_max
new Handle: g_hCvarMinPounceDistance = INVALID_HANDLE; // z_pounce_damage_range_min
new Handle: g_hCvarMinPounceDistance = INVALID_HANDLE; // z_pounce_damage_range_min
new Handle: g_hCvarMaxPounceDamage = INVALID_HANDLE; // z_hunter_max_pounce_bonus_damage;
new Handle: g_hCvarMaxPounceDamage = INVALID_HANDLE; // z_hunter_max_pounce_bonus_damage;




/*
/*
Reports:
Reports:
--------
--------
Damage shown is damage done in the last shot/slash. So for crowns, this means
Damage shown is damage done in the last shot/slash. So for crowns, this means
that the 'damage' value is one shotgun blast
that the 'damage' value is one shotgun blast


Quirks:
Quirks:
-------
-------
Does not report people cutting smoker tongues that target players other
Does not report people cutting smoker tongues that target players other
than themselves. Could be done, but would require (too much) tracking.
than themselves. Could be done, but would require (too much) tracking.
Actual damage done, on Hunter DPs, is low when the survivor gets incapped
Actual damage done, on Hunter DPs, is low when the survivor gets incapped
by (a fraction of) the total pounce damage.
by (a fraction of) the total pounce damage.
Fake Damage
Fake Damage
-----------
-----------
Hiding of fake damage has the following consequences:
Hiding of fake damage has the following consequences:
- Drawcrowns are less likely to be registered: if a witch takes too
- Drawcrowns are less likely to be registered: if a witch takes too
much chip before the crowning shot, the final shot will be considered
much chip before the crowning shot, the final shot will be considered
as doing too little damage for a crown (even if it would have been a crown
as doing too little damage for a crown (even if it would have been a crown
had the witch had more health).
had the witch had more health).
- Charger levels are harder to get on chipped chargers. Any charger that
- Charger levels are harder to get on chipped chargers. Any charger that
has taken (600 - 390 =) 210 damage or more cannot be leveled (even if
has taken (600 - 390 =) 210 damage or more cannot be leveled (even if
the melee swing would've killed the charger (1559 damage) if it'd have
the melee swing would've killed the charger (1559 damage) if it'd have
had full health).
had full health).
I strongly recommend leaving fakedamage visible: it will offer more feedback on
I strongly recommend leaving fakedamage visible: it will offer more feedback on
the survivor's action and reward survivors doing (what would be) full crowns and
the survivor's action and reward survivors doing (what would be) full crowns and
levels on chipped targets.
levels on chipped targets.
To Do
To Do
-----
-----
- fix: tank rock owner is not reliable for the RockEaten forward
- fix: tank rock owner is not reliable for the RockEaten forward
- fix: tank rock skeets still unreliable detection (often triggers a 'skeet' when actually landed on someone)
- fix: tank rock skeets still unreliable detection (often triggers a 'skeet' when actually landed on someone)
- fix: apparently some HR4 cars generate car alarm messages when shot, even when no alarm goes off
- fix: apparently some HR4 cars generate car alarm messages when shot, even when no alarm goes off
(combination with car equalize plugin?)
(combination with car equalize plugin?)
- see below: the single hook might also fix this.. -- if not, hook for sound
- see below: the single hook might also fix this.. -- if not, hook for sound
- do a hookoutput on prop_car_alarm's and use that to track the actual alarm
- do a hookoutput on prop_car_alarm's and use that to track the actual alarm
going off (might help in the case 2 alarms go off exactly at the same time?)
going off (might help in the case 2 alarms go off exactly at the same time?)
- fix: double prints on car alarms (sometimes? epi + m60)
- fix: double prints on car alarms (sometimes? epi + m60)


- fix: sometimes instaclear reports double for single clear (0.16s / 0.19s) epi saw this, was for hunter
- fix: sometimes instaclear reports double for single clear (0.16s / 0.19s) epi saw this, was for hunter
- fix: deadstops and m2s don't always register .. no idea why..
- fix: deadstops and m2s don't always register .. no idea why..
- fix: sometimes a (first?) round doesn't work for skeet detection.. no hurt/full skeets are reported or counted
- fix: sometimes a (first?) round doesn't work for skeet detection.. no hurt/full skeets are reported or counted


- make forwards fire for every potential action,
- make forwards fire for every potential action,
- include the relevant values, so other plugins can decide for themselves what to consider it
- include the relevant values, so other plugins can decide for themselves what to consider it
- test chargers getting dislodged with boomer pops?
- test chargers getting dislodged with boomer pops?
- add commonhop check
- add commonhop check
- add deathcharge assist check
- add deathcharge assist check
- smoker
- smoker
- jockey
- jockey
- add deathcharge coordinates for some areas
- add deathcharge coordinates for some areas
- DT4 next to saferoom
- DT4 next to saferoom
- DA1 near the lower roof, on sidewalk next to fence (no hurttrigger there)
- DA1 near the lower roof, on sidewalk next to fence (no hurttrigger there)
- DA2 next to crane roof to the right of window
- DA2 next to crane roof to the right of window
DA2 charge down into start area, after everyone's jumped the fence
DA2 charge down into start area, after everyone's jumped the fence
- count rock hits even if they do no damage [epi request]
- count rock hits even if they do no damage [epi request]
- sir
- sir
- make separate teamskeet forward, with (for now, up to) 4 skeeters + the damage each did
- make separate teamskeet forward, with (for now, up to) 4 skeeters + the damage each did
- xan
- xan
- add detection/display of unsuccesful witch crowns (witch death + info)
- add detection/display of unsuccesful witch crowns (witch death + info)