2016-12-20 15:27:43 +00:00
/*
PROJECT <> SA : MP Anticheat Plug - in
LICENSE <> See LICENSE in the top level directory .
AUTHOR ( S ) <> Lorenc_ ( zeelorenc @ hotmail . com )
PURPOSE <> Providing datastructures for the internal SA : MP Server .
Copyright ( C ) 2014 SA : MP Anticheat Plug - in .
The Project is available on https :// github . com / myudev / SAMPAC
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , see < http :// www . gnu . org / licenses />.
*/
2018-05-12 16:26:14 +00:00
/* ** Includes ** */
#include < YSI\y_hooks >
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
/* ** Variables ** */
static stock
Float : p_PlayerHealth [ MAX_PLAYERS ] [ E_PLAYER_HITPOINTS ],
Float : p_PlayerArmour [ MAX_PLAYERS ] [ E_PLAYER_HITPOINTS ],
Float : p_LastDamageIssued [ MAX_PLAYERS ],
p_LastTookDamage [ MAX_PLAYERS ],
p_LastDamageIssuer [ MAX_PLAYERS ] = { INVALID_PLAYER_ID , ... },
p_LastWeaponIssuer [ MAX_PLAYERS ]
;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
/* ** Forwards ** */
forward OnPlayerDamagePlayer ( playerid , damagedid , Float : amount , weaponid , bodypart );
forward OnPlayerTakePlayerDamage ( playerid , issuerid , & Float : amount , weaponid , bodypart );
forward OnPlayerDeathEx ( playerid , killerid , reason , Float : damage , bodypart );
2017-10-08 02:40:03 +00:00
2018-05-12 16:26:14 +00:00
// Function (AC_UpdateKillerData)
2017-10-08 02:40:03 +00:00
2018-05-12 16:26:14 +00:00
stock AC_UpdateDamageInformation ( playerid , attackerid , weaponid )
{
p_LastTookDamage [ playerid ] = GetTickCount ( );
p_LastDamageIssuer [ playerid ] = attackerid ;
p_LastWeaponIssuer [ playerid ] = weaponid ;
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Function (AC_GetPlayerHealth)
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
stock Float : AC_GetPlayerHealth ( playerid )
return p_PlayerHealth [ playerid ] [ E_POINTS ];
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Function (AddPlayerHealth)
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
stock AC_AddPlayerHealth ( playerid , Float : amount )
{
p_PlayerHealth [ playerid ] [ E_POINTS ] += amount ;
p_PlayerHealth [ playerid ] [ E_SYNCED ] = false ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
return SetPlayerHealth ( playerid , p_PlayerHealth [ playerid ] [ E_POINTS ] );
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Function Hook (SetPlayerHealth)
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
stock AC_SetPlayerHealth ( playerid , Float : amount )
{
p_PlayerHealth [ playerid ] [ E_POINTS ] = amount ;
p_PlayerHealth [ playerid ] [ E_SYNCED ] = false ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( amount <= 0.0 && p_acSpawned { playerid } )
{
if ( ( GetTickCount ( ) - p_LastTookDamage [ playerid ] ) > 2500 ) {
p_LastDamageIssuer [ playerid ] = INVALID_PLAYER_ID , p_LastWeaponIssuer [ playerid ] = 47 ;
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
p_acSpawned { playerid } = false ; // They're dead!
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , playerid , p_LastDamageIssuer [ playerid ], p_LastWeaponIssuer [ playerid ], 3.3 , 3 );
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
return SetPlayerHealth ( playerid , amount );
}
#if defined _ALS_SetPlayerHealth
#undef SetPlayerHealth
#else
#define _ALS_SetPlayerHealth
#endif
#define SetPlayerHealth AC_SetPlayerHealth
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Function Hook (SetPlayerArmour)
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
stock AC_SetPlayerArmour ( playerid , Float : amount )
{
p_PlayerArmour [ playerid ] [ E_POINTS ] = amount ;
p_PlayerArmour [ playerid ] [ E_SYNCED ] = false ;
return SetPlayerArmour ( playerid , amount );
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
#if defined _ALS_SetPlayerArmour
#undef SetPlayerArmour
#else
#define _ALS_SetPlayerArmour
#endif
#define SetPlayerArmour AC_SetPlayerArmour
// Function Hook (SetPlayerTeam)
stock AC_SetPlayerTeam ( playerid , teamid )
{
if ( teamid != AC_DEFAULT_TEAM ) {
printf ( " [ACWarning] You cannot use SetPlayerTeam as you have hitpoint hack detection enabled (teamid %d, default %d). " , teamid , AC_DEFAULT_TEAM );
}
return SetPlayerTeam ( playerid , AC_DEFAULT_TEAM );
}
#if defined _ALS_SetPlayerTeam
#undef SetPlayerTeam
#else
#define _ALS_SetPlayerArmour
#endif
#define SetPlayerTeam AC_SetPlayerTeam
/* ** Callback Hooks ** */
hook OnPlayerConnect ( playerid )
{
if ( 0 <= playerid < MAX_PLAYERS )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
p_PlayerHealth [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
p_PlayerArmour [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
return 1 ;
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
hook OnPlayerSpawn ( playerid )
{
// Health/Armour Hack
p_PlayerHealth [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
p_PlayerHealth [ playerid ] [ E_POINTS ] = 100.0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
p_PlayerArmour [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
p_PlayerArmour [ playerid ] [ E_POINTS ] = 0.0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
SetPlayerTeam ( playerid , AC_DEFAULT_TEAM ); // Set everyone the same team
return 1 ;
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
hook OnPlayerTakeDamage ( playerid , issuerid , Float : amount , weaponid , bodypart )
{
new
is_npc = IsPlayerNPC ( issuerid );
p_LastTookDamage [ playerid ] = GetTickCount ( );
p_LastDamageIssuer [ playerid ] = issuerid ;
p_LastWeaponIssuer [ playerid ] = weaponid ;
p_LastDamageIssued [ playerid ] = amount ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
//if( !( issuerid != INVALID_PLAYER_ID && IsPlayerInAnyVehicle( issuerid ) && GetPlayerVehicleSeat( issuerid ) == 0 && ( weaponid == WEAPON_M4 || weaponid == WEAPON_MINIGUN ) ) )
// return 0;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Allow hunter damage/sparrow
if ( ! ( issuerid != INVALID_PLAYER_ID && IsPlayerInAnyVehicle ( issuerid ) && GetPlayerVehicleSeat ( issuerid ) == 0 && ( weaponid == WEAPON_M4 || weaponid == WEAPON_MINIGUN ) ) && ! is_npc )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
// Ignore unreliable and invalid damage
if ( weaponid < 0 || weaponid >= sizeof ( s_ValidDamageGiven ) || s_ValidDamageGiven [ weaponid ] )
return 0 ;
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( ac_IsPlayerSpawned ( playerid ) )
{
if ( issuerid != INVALID_PLAYER_ID && ! is_npc )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
if ( OnPlayerTakePlayerDamage ( playerid , issuerid , amount , weaponid , bodypart ) )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
new Float : tmp , Float : tmp_amount = amount ;
if ( p_PlayerArmour [ playerid ] [ E_POINTS ] )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
if ( ( tmp = p_PlayerArmour [ playerid ] [ E_POINTS ] - tmp_amount ) < 0.0 ) {
tmp_amount -= p_PlayerArmour [ playerid ] [ E_POINTS ];
p_PlayerArmour [ playerid ] [ E_POINTS ] = 0.0 ;
} else {
p_PlayerArmour [ playerid ] [ E_POINTS ] = tmp ;
tmp_amount = 0.0 ;
2016-12-20 15:27:43 +00:00
}
}
2018-05-12 16:26:14 +00:00
if ( ( p_PlayerHealth [ playerid ] [ E_POINTS ] -= tmp_amount ) < 0.0 ) {
p_acSpawned { playerid } = false ; // They're dead!
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , playerid , issuerid , weaponid , amount , bodypart );
}
SetPlayerArmour ( playerid , p_PlayerArmour [ playerid ] [ E_POINTS ] );
SetPlayerHealth ( playerid , p_PlayerHealth [ playerid ] [ E_POINTS ] );
CallRemoteFunction ( " OnPlayerDamagePlayer " , " ddfdd " , issuerid , playerid , amount , weaponid , bodypart );
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
}
else
{
new Float : tmp , Float : tmp_amount = amount ;
if ( ! ( weaponid == 53 || weaponid == 54 || weaponid == 50 ) && p_PlayerArmour [ playerid ] [ E_POINTS ] )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
if ( ( tmp = p_PlayerArmour [ playerid ] [ E_POINTS ] - tmp_amount ) < 0.0 ) {
tmp_amount -= p_PlayerArmour [ playerid ] [ E_POINTS ];
p_PlayerArmour [ playerid ] [ E_POINTS ] = 0.0 ;
} else {
p_PlayerArmour [ playerid ] [ E_POINTS ] = tmp ;
tmp_amount = 0.0 ;
}
}
// printf("OnPlayerTakeDamage( %d, %d, %f, %d, %d ) %f", playerid, issuerid, amount, weaponid, bodypart, p_PlayerHealth[ playerid ] [ E_POINTS ] );
if ( ( p_PlayerHealth [ playerid ] [ E_POINTS ] -= tmp_amount ) <= ( weaponid == 37 ? 0.99999 : 0.0 ) ) {
// find any possible killers prior
if ( ( GetTickCount ( ) - p_LastTookDamage [ playerid ] ) > 2500 ) {
p_LastDamageIssuer [ playerid ] = issuerid , p_LastWeaponIssuer [ playerid ] = weaponid ;
}
p_acSpawned { playerid } = false ; // They're dead!
if ( weaponid == 37 || weaponid == 51 ) SetPlayerHealth ( playerid , - 1 ); // Death bug fix
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , playerid , p_LastDamageIssuer [ playerid ], p_LastWeaponIssuer [ playerid ], amount , bodypart );
}
}
}
return 1 ;
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
hook OnPlayerGiveDamage ( playerid , damagedid , Float : amount , weaponid , bodypart )
{
// Ignore unreliable and invalid damage
if ( weaponid < 0 || weaponid >= sizeof ( s_ValidDamageGiven ) || ! s_ValidDamageGiven [ weaponid ] )
return 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( weaponid < 0 || weaponid >= sizeof ( s_ValidMaxDamage ) || amount > s_ValidMaxDamage [ weaponid ] + 2.0 ) // 2.0 safety margin
return 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( damagedid == INVALID_PLAYER_ID )
return 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( IsPlayerInAnyVehicle ( playerid ) && GetPlayerVehicleSeat ( playerid ) == 0 && ( weaponid == WEAPON_M4 || weaponid == WEAPON_MINIGUN ) )
return 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( ! IsPlayerNPC ( damagedid ) )
{
if ( ! ac_IsPlayerSpawned ( damagedid ) )
return 0 ;
if ( ( ! IsPlayerStreamedIn ( playerid , damagedid ) && ! ( GetTickCount ( ) - p_acUpdateTime [ damagedid ] >= 2595 ) ) || ! IsPlayerStreamedIn ( damagedid , playerid ) )
return 0 ;
//printf("OnPlayerGiveDamage( %d, %d, %f, %d, %d )", playerid, damagedid, amount, weaponid, bodypart );
//p_LastTookDamage[ damagedid ] = GetTickCount( );
//p_LastDamageIssuer[ damagedid ] = playerid;
//p_LastWeaponIssuer[ damagedid ] = weaponid;
//p_LastDamageIssued[ damagedid ] = amount;
if ( OnPlayerTakePlayerDamage ( damagedid , playerid , amount , weaponid , bodypart ) )
{
new
Float : tmp ,
Float : distance = ac_GetDistanceBetweenPlayers ( playerid , damagedid ), // Calc distance between players
Float : tmp_amount = amount // this amount is extremely unreliable
;
//printf("Proposed dmg %f kinda %f (min: %f, max: %f, rng: %f)", amount, tmp_amount, GetWeaponMinRange( weaponid ), GetWeaponMaxRange( weaponid ), distance );
if ( distance > s_WeaponRange [ weaponid ] + 2.0 )
return 0 ; //printf(" INVALID RANGE %f (MAX %f)", distance, GetWeaponMaxRange( weaponid ) ), 0;
if ( p_PlayerArmour [ damagedid ] [ E_POINTS ] )
{
if ( ( tmp = p_PlayerArmour [ damagedid ] [ E_POINTS ] - tmp_amount ) < 0.0 ) {
tmp_amount -= p_PlayerArmour [ damagedid ] [ E_POINTS ];
p_PlayerArmour [ damagedid ] [ E_POINTS ] = 0.0 ;
} else {
p_PlayerArmour [ damagedid ] [ E_POINTS ] = tmp ;
tmp_amount = 0.0 ;
}
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
if ( ( p_PlayerHealth [ damagedid ] [ E_POINTS ] -= tmp_amount ) < 0.0 ) {
p_acSpawned { damagedid } = false ; // They're dead!
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , damagedid , playerid , weaponid , amount , bodypart );
}
SetPlayerArmour ( damagedid , p_PlayerArmour [ damagedid ] [ E_POINTS ] );
SetPlayerHealth ( damagedid , p_PlayerHealth [ damagedid ] [ E_POINTS ] );
CallRemoteFunction ( " OnPlayerDamagePlayer " , " ddfdd " , playerid , damagedid , amount , weaponid , bodypart );
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
}
return 1 ;
}
// Functions (Player)
stock vCheckForHealthHacks ( playerid , iTicks )
{
new
Float : currentHealth ,
Float : currentArmour
;
GetPlayerHealth ( playerid , currentHealth );
GetPlayerArmour ( playerid , currentArmour );
// Lag Calculations
new
Float : fHitDamage = p_LastDamageIssued [ playerid ],
Float : fArmourDamage ,
Float : fHealthDamage
;
if ( fHitDamage > currentArmour ) {
fArmourDamage = currentArmour ;
fHealthDamage = fHitDamage - currentArmour ;
}
else fArmourDamage = fHitDamage ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
// Begin Health Hack Detection
if ( iTicks > p_PlayerHealth [ playerid ] [ E_UPDATE_TIME ] )
{
new currentHealthInt = floatround ( currentHealth , floatround_floor );
new healthShouldBeInt = floatround ( p_PlayerHealth [ playerid ] [ E_POINTS ], floatround_floor );
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( currentHealthInt == healthShouldBeInt )
p_PlayerHealth [ playerid ] [ E_SYNCED ] = true ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( ! p_PlayerHealth [ playerid ] [ E_SYNCED ] )
{
if ( currentHealthInt > healthShouldBeInt )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
switch ( p_PlayerHealth [ playerid ] [ E_UPDATE_FAIL ] ++ )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
case 0 .. 9 : SetPlayerHealth ( playerid , p_PlayerHealth [ playerid ] [ E_POINTS ] );
case 10 : SendClientMessage ( playerid , 0xa9c4e4ff , " You have been kicked as you are desynced from the server. Please relog! " ), KickPlayerTimed ( playerid ), printf ( " [health] Player %d was desynced thus kicked. " , playerid );
2016-12-20 15:27:43 +00:00
}
}
2018-05-12 16:26:14 +00:00
}
else
{
p_PlayerHealth [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( healthShouldBeInt > currentHealthInt )
p_PlayerHealth [ playerid ] [ E_POINTS ] = currentHealth ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( currentHealthInt > healthShouldBeInt && currentHealthInt <= 255 && currentHealthInt > 0 )
SetPlayerHealth ( playerid , p_PlayerHealth [ playerid ] [ E_POINTS ] );
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
currentHealthInt = floatround ( currentHealth , floatround_floor );
healthShouldBeInt = floatround ( p_PlayerHealth [ playerid ] [ E_POINTS ], floatround_floor );
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
new dmgOne = floatround ( currentHealthInt - fHealthDamage , floatround_floor );
new dmgTwo = floatround ( currentHealthInt - fHealthDamage , floatround_ceil );
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( ! ( currentHealthInt == healthShouldBeInt || dmgOne == healthShouldBeInt || dmgTwo == healthShouldBeInt ) )
{
SetPlayerHealth ( playerid , p_PlayerHealth [ playerid ] [ E_POINTS ] );
//printf("[health][%d] %d seems to health hack (server health: %d and client health: %d, health dmg: %f, armour dmg: %f).", playerid, playerid, healthShouldBeInt, currentHealthInt, fHealthDamage, fArmourDamage );
}
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
p_PlayerHealth [ playerid ] [ E_UPDATE_TIME ] = iTicks + 1000 ;
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
// Begin Armour Hack Detection
if ( iTicks > p_PlayerArmour [ playerid ] [ E_UPDATE_TIME ] )
2016-12-20 15:27:43 +00:00
{
2018-05-12 16:26:14 +00:00
new currentArmourInt = floatround ( currentArmour , floatround_floor );
new ArmourShouldBeInt = floatround ( p_PlayerArmour [ playerid ] [ E_POINTS ], floatround_floor );
if ( currentArmourInt == ArmourShouldBeInt )
p_PlayerArmour [ playerid ] [ E_SYNCED ] = true ;
if ( ! p_PlayerArmour [ playerid ] [ E_SYNCED ] )
{
if ( currentArmourInt > ArmourShouldBeInt )
{
switch ( p_PlayerArmour [ playerid ] [ E_UPDATE_FAIL ] ++ )
{
case 0 .. 9 : SetPlayerArmour ( playerid , p_PlayerArmour [ playerid ] [ E_POINTS ] );
case 10 : SendClientMessage ( playerid , 0xa9c4e4ff , " You have been kicked as you are desynced from the server. Please relog! " ), KickPlayerTimed ( playerid ), printf ( " [armour] Player %d was desynced thus kicked. " , playerid );
}
}
}
else
{
p_PlayerArmour [ playerid ] [ E_UPDATE_FAIL ] = 0 ;
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
if ( ArmourShouldBeInt > currentArmourInt )
p_PlayerArmour [ playerid ] [ E_POINTS ] = currentArmour ;
if ( currentArmourInt > ArmourShouldBeInt && currentArmourInt <= 255 && currentArmourInt > 0 )
SetPlayerArmour ( playerid , p_PlayerArmour [ playerid ] [ E_POINTS ] );
currentArmourInt = floatround ( currentArmour , floatround_floor );
ArmourShouldBeInt = floatround ( p_PlayerArmour [ playerid ] [ E_POINTS ], floatround_floor );
new dmgOne = floatround ( currentArmourInt - fArmourDamage , floatround_floor );
new dmgTwo = floatround ( currentArmourInt - fArmourDamage , floatround_ceil );
if ( ! ( currentArmourInt == ArmourShouldBeInt || dmgOne == ArmourShouldBeInt || dmgTwo == ArmourShouldBeInt ) )
{
SetPlayerArmour ( playerid , p_PlayerArmour [ playerid ] [ E_POINTS ] );
//printf("[armour] %d seems to armour hack (server armour: %d and client armour: %d, health dmg: %f, armour dmg: %f).", playerid, ArmourShouldBeInt, currentArmourInt, fHealthDamage, fArmourDamage );
}
}
p_PlayerArmour [ playerid ] [ E_UPDATE_TIME ] = iTicks + 1000 ;
2016-12-20 15:27:43 +00:00
}
2018-05-12 16:26:14 +00:00
}
2016-12-20 15:27:43 +00:00
2018-05-12 16:26:14 +00:00
hook OnPlayerDeath ( playerid , killerid , reason )
{
if ( ! IsPlayerNPC ( playerid ) )
{
// Health/Armour Hack
if ( GetPVarInt ( playerid , " CustomKill " ) )
{
new
customKiller = GetPVarInt ( playerid , " KillerID " );
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , playerid , customKiller != playerid ? customKiller : INVALID_PLAYER_ID , GetPVarInt ( playerid , " WeaponID " ), 3.3 , 3 );
DeletePVar ( playerid , " KillerID " );
DeletePVar ( playerid , " WeaponID " );
DeletePVar ( playerid , " CustomKill " );
}
// Died in Vehicle
else if ( GetPlayerVehicleID ( playerid ) && ac_IsPlayerSpawned ( playerid ) )
{
if ( ( GetTickCount ( ) - p_LastTookDamage [ playerid ] ) > 2500 )
p_LastDamageIssuer [ playerid ] = INVALID_PLAYER_ID , p_LastWeaponIssuer [ playerid ] = 51 ;
p_acSpawned { playerid } = false ; // They're dead!
CallRemoteFunction ( " OnPlayerDeathEx " , " ddfd " , playerid , p_LastDamageIssuer [ playerid ], p_LastWeaponIssuer [ playerid ], 3.3 , 3 );
}
// General
p_acSpawned { playerid } = false ;
// Airbrake
p_abLastTick [ playerid ] = GetTickCount ( ) + 3000 ;
}
return 1 ;
}
/* ** Functions ** */
stock ForcePlayerKill ( playerid , killerid , weaponid )
{
SetPVarInt ( playerid , " KillerID " , killerid );
SetPVarInt ( playerid , " WeaponID " , weaponid );
SetPVarInt ( playerid , " CustomKill " , 1 );
SetPlayerHealth ( playerid , - 1 );
}