23.12.2014, 16:47
(
Последний раз редактировалось michalmonday; 27.01.2015 в 14:53.
Причина: Added instructions
)
__________________________________________________ ________________________________
Health-hack (bulletproof) detector - ******* video
Estimated reliability:

Calibration:
1. Increase delayer time in case if there are false detections
2. Evaluate if there are false detections by spectating each detected player
3. Repeat step 1 until there is no false detections
Individual script modification needed:
-afk check has to be added
-number of hits without losing health needed to take action(after calibration)
-final action (after calibration)
No-spread detector - ******* video
It's not effective if the player is waving the gun around.
Health-hack (bulletproof) detector - ******* video
Код:
#define FILTERSCRIPT
#include <a_samp>
new Float:previousHealthValue[MAX_PLAYERS],
hits[MAX_PLAYERS],
noDamageCount[MAX_PLAYERS], //count how many times the player didn't lose health after being hit
bool:delayer[MAX_PLAYERS], // delayer is neccessary because damage is not updated quickly enough and gives false detections
bool:afterSpawnCover[MAX_PLAYERS], //to avoid false detections straight after spawn which happened to me while testing it (it's set to 3 seconds right now)
bool:isDead[MAX_PLAYERS]; // hp check to see if the player is dead didn't work(the value of hp stayed the same as before last shot)
////////////////////////////////
//SETTINGS
#define DELAY_TIME 500 // 500ms delay works well on my syrver with 2 players online, I'm not sure what's it's going to be like on a server with over 100 players online
#define AFTER_SPAWN_COVER_TIME 3000
#define NO_DAMAGE_COUNT_LIMIT 0 // number of times the script detected someone taking no damage after shot needed to: send info to admins/kick/ban
//SETTINGS
////////////////////////////////
public OnFilterScriptInit()
{
print("\n--------------------------------------");
print("Health-hack detector by monday");
print("--------------------------------------\n");
return 1;
}
public OnPlayerConnect(playerid)
{
previousHealthValue[playerid] = 0.0;
hits[playerid] = 0;
noDamageCount[playerid] = 0;
delayer[playerid] = false;
return 1;
}
public OnPlayerDeath(playerid, killerid, reason)
{
isDead[playerid] = true;
return 1;
}
public OnPlayerSpawn(playerid)
{
previousHealthValue[playerid] = 0.0;
hits[playerid] = 0;
delayer[playerid] = false;
afterSpawnCover[playerid] = true;
SetTimerEx("RemoveSpawnCover", AFTER_SPAWN_COVER_TIME, false, "i", playerid);
isDead[playerid] = false;
return 1;
}
forward SwitchDelay(playerid);
public SwitchDelay(playerid)
{
delayer[playerid] = true;
return 1;
}
forward RemoveSpawnCover(playerid);
public RemoveSpawnCover(playerid)
{
afterSpawnCover[playerid] = false;
return 1;
}
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
if(hittype == BULLET_HIT_TYPE_PLAYER)
{
new Float:h, Float:a, Float:newHealthValue, message[128], cheaterName[MAX_PLAYER_NAME];
if(hits[hitid] == 0)
{
GetPlayerHealth(hitid, h);
GetPlayerArmour(hitid, a);
previousHealthValue[hitid] = h + a;
if(isDead[hitid] == true || afterSpawnCover[hitid] == true) // + here must be a check for AFK to avoid false detections
{
hits[hitid] = 0;
}
else
{
SetTimerEx("SwitchDelay", DELAY_TIME, false, "i", hitid);
}
}
else if(delayer[hitid] == true)
{
delayer[hitid] = false;
GetPlayerHealth(hitid, h);
GetPlayerArmour(hitid, a);
newHealthValue = h + a;
if(newHealthValue == previousHealthValue[hitid] && isDead[hitid] != true && afterSpawnCover[hitid] != true)
{
noDamageCount[hitid]++;
if(noDamageCount[hitid] > NO_DAMAGE_COUNT_LIMIT)
{
//send message to admins, kick, ban
GetPlayerName(hitid, cheaterName, sizeof(cheaterName));
format(message,sizeof(message),"%s didn't lose health %d times after being shot since his last login.",cheaterName, noDamageCount[hitid]);
SendClientMessageToAll(0xED6755AA,message);
}
}
else
{
previousHealthValue[hitid] = newHealthValue; //update health value if it decreased like it should
}
SetTimerEx("SwitchDelay", DELAY_TIME, false, "i", hitid); // new delay before next check
}
hits[hitid]++;
}
return 1;
}

Calibration:
1. Increase delayer time in case if there are false detections
2. Evaluate if there are false detections by spectating each detected player
3. Repeat step 1 until there is no false detections
Individual script modification needed:
-afk check has to be added
-number of hits without losing health needed to take action(after calibration)
-final action (after calibration)
No-spread detector - ******* video
It's not effective if the player is waving the gun around.
Код:
#define FILTERSCRIPT
#include <a_samp>
new hitsInaRow[MAX_PLAYERS];
new Float:lastMiddle_X[MAX_PLAYERS];
new Float:lastMiddle_Y[MAX_PLAYERS];
new Float:lastMiddle_Z[MAX_PLAYERS];
new Float:lastHit_X[MAX_PLAYERS];
new Float:lastHit_Y[MAX_PLAYERS];
new Float:lastHit_Z[MAX_PLAYERS];
new weaponUsed[MAX_PLAYERS];
new Float:averageSpread[MAX_PLAYERS];
public OnFilterScriptInit()
{
print("\n--------------------------------------");
print("No-spread detector by monday");
print("--------------------------------------\n");
return 1;
}
stock Float:GetPositiveNumber(Float:number)
{
if(0.0 > number)
{
number *= -1.0;
}
return number;
}
stock Float:GetDistanceBetweenPoints(Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2)
{
return VectorSize(x1-x2, y1-y2, z1-z2);
}
public OnPlayerConnect(playerid)
{
hitsInaRow[playerid]=0;
lastMiddle_X[playerid]=0.0;
lastMiddle_Y[playerid]=0.0;
lastMiddle_Z[playerid]=0.0;
lastHit_X[playerid]=0.0;
lastHit_Y[playerid]=0.0;
lastHit_Z[playerid]=0.0;
averageSpread[playerid]=0.0;
weaponUsed[playerid] = 0;
return 1;
}
forward SpreadCheckReset(playerid);
public SpreadCheckReset(playerid)
{
hitsInaRow[playerid]=0;
lastMiddle_X[playerid]=0.0;
lastMiddle_Y[playerid]=0.0;
lastMiddle_Z[playerid]=0.0;
lastHit_X[playerid]=0.0;
lastHit_Y[playerid]=0.0;
lastHit_Z[playerid]=0.0;
averageSpread[playerid]=0.0;
weaponUsed[playerid] = 0;
return 1;
}
forward OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ);
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
new
Float:fOriginX, Float:fOriginY, Float:fOriginZ,
Float:fVX, Float:fVY, Float:fVZ,
Float:fHitPosX, Float:fHitPosY, Float:fHitPosZ,
Float:middle_x, Float:middle_y, Float:middle_z,
Float:compareMiddle_x, Float:compareMiddle_y, Float:compareMiddle_z,
Float:compareHit_x, Float:compareHit_y, Float:compareHit_z,
Float:compareBoth_x, Float:compareBoth_y, Float:compareBoth_z,
Float:distance,
Float:spreadValue,
Float:spreadLimit,
cheaterName[MAX_PLAYER_NAME],
hitsNeeded,
weaponTime,
currentWeapon,
finalMessage[128],
gunName[32],
spread[128];
currentWeapon = GetPlayerWeapon(playerid);
GetPlayerLastShotVectors(playerid, fOriginX, fOriginY, fOriginZ, fHitPosX, fHitPosY, fHitPosZ);
distance = GetDistanceBetweenPoints(fOriginX, fOriginY, fOriginZ, fHitPosX, fHitPosY, fHitPosZ);
GetPlayerCameraFrontVector(playerid, fVX, fVY, fVZ);
middle_x = fOriginX + floatmul(fVX, distance);
middle_y = fOriginY + floatmul(fVY, distance);
middle_z = fOriginZ + floatmul(fVZ, distance);
// middle_x, middle_y, middle_z = middle of the screen
// fHitPosX, fHitPosY, fHitPosZ = shooting point
//compare with the last shot
compareMiddle_x = GetPositiveNumber(middle_x - lastMiddle_X[playerid]);
compareMiddle_y = GetPositiveNumber(middle_y - lastMiddle_Y[playerid]);
compareMiddle_z = GetPositiveNumber(middle_z - lastMiddle_Z[playerid]);
compareHit_x = GetPositiveNumber(fHitPosX - lastHit_X[playerid]);
compareHit_y = GetPositiveNumber(fHitPosY - lastHit_Y[playerid]);
compareHit_z = GetPositiveNumber(fHitPosZ - lastHit_Z[playerid]);
compareBoth_x = GetPositiveNumber(compareMiddle_x - compareHit_x);
compareBoth_y = GetPositiveNumber(compareMiddle_y - compareHit_y);
compareBoth_z = GetPositiveNumber(compareMiddle_z - compareHit_z);
spreadValue = GetPositiveNumber(compareBoth_x + compareBoth_y + compareBoth_z);
//replace last shot data with new one
lastMiddle_X[playerid] = middle_x;
lastMiddle_Y[playerid] = middle_y;
lastMiddle_Z[playerid] = middle_z;
lastHit_X[playerid] = fHitPosX;
lastHit_Y[playerid] = fHitPosY;
lastHit_Z[playerid] = fHitPosZ;
if (weaponUsed[playerid] != currentWeapon)
{
weaponUsed[playerid] = currentWeapon;
SpreadCheckReset(playerid);
return 1;
}
if (currentWeapon == 31 || currentWeapon == 30 ||currentWeapon == 28 || currentWeapon == 32 ||currentWeapon == 29) //m4, ak47, tec, uzi, mp5 - all of them are set to m4's limit which is the most accurate weapon. Mp5 has a bit faster shooting rate than other weapons included but its spread is also higher so it's not an issue, I tested it and it's not even close to get false detection
{
hitsNeeded = 3; //
weaponTime = 500; //time after which the stored hits will be reset(to make sure that there is no breaks between single shots)
weaponUsed[playerid] = currentWeapon;
}
else
{
if (currentWeapon == 24)//deagle
{
hitsNeeded = 2;
weaponTime = 1600;
weaponUsed[playerid] = currentWeapon;
}
else
{
return 1;
}
}
if( GetPlayerSpecialAction(playerid) == SPECIAL_ACTION_DUCK )
{
spreadLimit = 0.00075 * distance; //decreased limit if the player is crouching
}
else
{
spreadLimit = 0.00140 * distance;
}
format(spread, sizeof(spread), "Spread: %f Limit: %f",spreadValue, spreadLimit);
//SendClientMessage(playerid, -1, spread);
if(spreadValue < spreadLimit && 200.0 > distance > 3.0)
{
hitsInaRow[playerid]++;
averageSpread[playerid] = averageSpread[playerid] + spreadValue;
}
if (hitsInaRow[playerid] == 1)
{
SetTimerEx("SpreadCheckReset", weaponTime, 0, "i", playerid);
}
if (hitsInaRow[playerid] == hitsNeeded || hitsInaRow[playerid] > hitsNeeded)
{
//send message to admins, kick, ban
GetWeaponName(currentWeapon, gunName, sizeof(gunName));
GetPlayerName(playerid, cheaterName, MAX_PLAYER_NAME);
averageSpread[playerid] /= float(hitsInaRow[playerid]);
format(finalMessage, sizeof(finalMessage), "%s is shooting under spread limit using %s. Average spread=%f Limit=%f", cheaterName, gunName, averageSpread[playerid], spreadLimit);
SendClientMessageToAll(0xED6755AA,finalMessage);
SpreadCheckReset(playerid);
}
return 1;
}


. .