Hey, it's already some time this script is running on NoobSpot, making gameplay bearable for newbies and detecting several hacks, including aimbot, so I'd like to share it with you guys :D
AimDetect={Enabled=true;};
function InCombat(player)
return (_time - (player.allCombatTime or (_time-1000)))<30
end
if AimDetect.Enabled then
function AimDetect:OnShoot(hit)
local wpn,player=hit.weapon,hit.shooter;
if player and wpn then
if not player.aimTable then player.aimTable={} end
if not player.aimTable[wpn.class] then player.aimTable[wpn.class]={shots = 0, hits = 0 }; end
player.aimTable[wpn.class].shots = player.aimTable[wpn.class].shots + 1;
player.aimStatsShots = (player.aimStatsShots or 0)+1;
local mode=player.actor:GetNanoSuitMode() or 0;
if mode==2 then
local diff=_time - (player.lastCloakShoot or (_time-20))
if diff<1 then
if player.cloakHackSuspects>6 then
--Chat:SendToAll(nil,"Player %s suspected from cloak hack!!! Diff: %.4f", player:GetName(), diff)
AntiCheat:DealWithPlayer(player,"cloak hack",true,"Suspects: "..player.cloakHackSuspects..", difference: "..diff)
player.cloakHackProbable = true
end
player.cloakHackSuspects = (player.cloakHackSuspects or 0)+1
else player.cloakHackSuspects = 0 end
player.lastCloakShoot=_time
end
end
end
function AimDetect:CheckPlayer(player)
if not player.skill then
player.skill = {
combatRatio = 0;
bulletRatio = 0;
avgDst = 1;
avgDstRatio = 1;
combatTime = 0;
skillQuotient = 0;
accuracy = 0;
shots = 0;
hits = 0;
timeRatio = 1;
difference = 0;
};
end
end
function AimDetect:OnHit(hit)
local wpn,player=hit.weapon,hit.shooter;
if player and wpn and hit.damage>0 then
local mtl = hit.material_type or "unknown"
if hit.target and hit.target~=player then hit.target.allCombatTime=_time end
if not player.aimTable then player.aimTable={} end
if not player.aimTable[wpn.class] then return; end
player.aimTable[wpn.class].hits = player.aimTable[wpn.class].hits + 1;
player.aimStatsHits = (player.aimStatsHits or 0)+1;
if hit.shooter and hit.target and (hit.shooter.IsOnVehicle and (not hit.shooter:IsOnVehicle())) and (hit.target.IsOnVehicle and (not hit.target:IsOnVehicle())) then
hit.target.activeCombats = hit.target.activeCombats or {}
hit.shooter.activeCombats = hit.shooter.activeCombats or {}
if hit.target.skill and hit.shooter.skill then
local diff = hit.target.skill.difference - hit.shooter.skill.difference
local odmg = hit.damage
local ratio=1
if diff>=11 then ratio=10/8.75
elseif diff>=8 then ratio=10/9
elseif diff>=5 then ratio=10/9.25
end
if ratio>1 then
hit.damage = hit.damage*ratio
--printf("raising damage against pro: %.2f to %.2f; combat: %s : %s; skdiff: %.2f, ratio: %.2f", odmg, hit.damage, hit.shooter:GetName(), hit.target:GetName(), diff, ratio)
end
end
local newCombat = false
local combat = hit.shooter.activeCombats[hit.target.id] or hit.target.activeCombats[hit.target.id]
if not combat then
combat={startTime = _time; bulletsShot = 0; lastShotTime=_time; side1=hit.shooter; side2= hit.target; side1_t = _time; side2_t=0; };
newCombat=true;
else
local t = 0;
if hit.shooter.id == combat.side1.id then
t = combat.side1_t
else t = combat.side2_t end
if (_time - t)>4 then
newCombat = true;
end --lse printf("diff: %f", _time ); end
end
if newCombat then
local skipped = { DSG1 = true, GaussRifle = true };
if not skipped[hit.weapon.class or "null"] then
hit.shooter.mtl_table = hit.shooter.mtl_table or {}
hit.shooter.mtl_table[mtl] = (hit.shooter.mtl_table[mtl] or 0) + 1
hit.shooter.mtl_ctr = (hit.shooter.mtl_ctr or 0)+1
local countNow = hit.shooter.mtl_table[mtl]
if hit.shooter.mtl_ctr>50 then
if countNow > (hit.shooter.mtl_ctr*0.6) then
printf("SUSPICIOUS!!! %s MIGHT BE USING HACKS!!! MTL: %s, ACCU: %.3f", hit.shooter:GetName(), mtl, 100*countNow/hit.shooter.mtl_ctr)
AntiCheat:DealWithPlayer(hit.shooter, "aimbot", true, "mtl: "..mtl, "accu: "..(countNow/hit.shooter.mtl_ctr));
end
end
end
end
combat.lastShotTime = _time
if hit.shooter.id==combat.side1.id then
combat.side1_t=_time;
else combat.side2_t=_time; end
combat.bulletsShot = (combat.bulletsShot or 0)+1
hit.shooter.combatBulletsShot = (hit.shooter.combatBulletsShot or 0)+1
hit.shooter.activeCombats[hit.target.id] = combat
hit.target.activeCombats[hit.shooter.id] = combat
--printf("active combat between %s : %s, time: %.2f, bullets shot: %d : %d",hit.shooter:GetName(), hit.target:GetName(), _time - combat.startTime, hit.shooter.combatBulletsShot or 0, hit.target.combatBulletsShot or 0)
end
end
end
function AimDetect:OnKill(hit)
if hit.target then
hit.target.allCombatTime = _time-1000
end
if hit.shooter and hit.target and (hit.shooter.IsOnVehicle and (not hit.shooter:IsOnVehicle())) and (hit.target.IsOnVehicle and (not hit.target:IsOnVehicle())) then
hit.target.activeCombats = hit.target.activeCombats or {}
hit.shooter.activeCombats = hit.shooter.activeCombats or {}
local targetsCombat = hit.target.activeCombats[hit.shooter.id]
local shootersCombat = hit.shooter.activeCombats[hit.target.id]
if hit.shooter.activeCombats[hit.target.id] then
local pos1,pos2=hit.shooter:GetPos(),hit.target:GetPos()
local x,y,z=pos1.x-pos2.x,pos1.y-pos2.y,pos1.z-pos2.z
local dst=math.sqrt(x*x+y*y+z*z)
if (_time - shootersCombat.startTime)<60 and dst<90 then
--printf("finished combat %s : %s, time: %.2f, bullets shot: %d : %d, bskll: %.3f",hit.shooter:GetName(), hit.target:GetName(), _time - shootersCombat.startTime, hit.shooter.combatBulletsShot or 0, hit.target.combatBulletsShot or 0,((hit.target.combatBulletsShot or 0)/math.max(1,hit.shooter.combatBulletsShot or 0)))
hit.shooter.totalCombats = (hit.shooter.totalCombats or 0)+1
hit.target.totalCombats = (hit.target.totalCombats or 0)+1
hit.target.lostCombats = (hit.target.lostCombats or 0) + 1;
hit.shooter.wonCombats = (hit.shooter.wonCombats or 0) + 1;
if hit.shooter.bulletSkill~=nil and hit.shooter.bulletSkill~=hit.shooter.bulletSkill then
hit.shooter.bulletSkill = 0
printf("corrected bulletskill for %s",hit.shooter:GetName())
end
hit.shooter.combatBulletsTotal = (hit.shooter.combatBulletsTotal or 0) + (hit.shooter.combatBulletsShot or 0)
hit.shooter.combatTimes = (hit.shooter.combatTimes or 0)+(_time - shootersCombat.startTime)
hit.shooter.combatDistance = (hit.shooter.combatDistance or 0)+dst
hit.shooter.bulletSkill = (hit.shooter.bulletSkill or 0)+((math.max(1,hit.target.combatBulletsShot or 0))/math.max(1,hit.shooter.combatBulletsShot or 0))
CalcSkill(hit.target)
CalcSkill(hit.shooter)
else
--printf("dropped finished combat between %s : %s, time: %.3f, dst: %.3f",hit.shooter:GetName(),hit.target:GetName(),_time - shootersCombat.startTime, dst)
end
end
hit.target.combatBulletsShot = 0
hit.shooter.combatBulletsShot = 0
hit.shooter.activeCombats[hit.target.id] = nil
end
if hit.target and hit.target.activeCombats then
for i,v in pairs(hit.target.activeCombats) do
if v.side1 and v.side2 and v.side1.activeCombats and v.side2.activeCombats then
if v.side1 == hit.target then
v.side2.activeCombats[hit.target.id]=nil
else
v.side1.activeCombats[hit.target.id]=nil
end
end
end
hit.target.activeCombats = {}
hit.target.combatBulletsShot = 0
end
end
function CalcSkill(v)
local shots, hits = v.aimStatsShots or 0, v.aimStatsHits or 0;
local accuracy = 100 * (hits / (math.max(1, shots)))
local combatRatio=(v.wonCombats or 0)/math.max(1,v.lostCombats or 0)
local bulletRatio=(v.bulletSkill or 0)/math.max(1,v.totalCombats or 0)
local avgDst=((v.combatDistance or 0)/math.max(1,v.totalCombats or 0))
local avgDstRatio = 1
if avgDst>=100 then avgDstRatio = avgDst^(1/3)
elseif avgDst>=50 and avgDst<100 then avgDstRatio = 1.2
elseif avgDst<50 and avgDst>=3 then avgDstRatio = 0.8
else avgDstRatio=1 end
local combatTime = (v.combatTimes or 0)/math.max(1,v.wonCombats or 0)
local timeRatio = (math.max(0.9,math.log(math.max(1, combatTime))))
if combatTime < 1.5 then timeRatio = 1 end
timeRatio = math.sqrt(timeRatio)
local skillQuotient = ((accuracy/40 + 2*combatRatio*bulletRatio + 2.5*combatRatio + 1.5*bulletRatio)/(math.max(1, avgDstRatio)))/timeRatio
v.skill = {
combatRatio = combatRatio;
bulletRatio = bulletRatio;
avgDst = avgDst;
avgDstRatio = avgDstRatio;
combatTime = combatTime;
skillQuotient = skillQuotient;
accuracy = accuracy;
shots = shots;
hits = hits;
timeRatio = timeRatio;
};
local avg=GetAvgSkill()
v.skill.difference = v.skill.skillQuotient - avg
end
SafeWriting.FuncContainer:LoadPlugin(AimDetect);
AddChatCommand("aimstats",function(self,player,msg,target)
if not (IsAdmin(player) or IsModerator(player)) then target=player; end
if not target then
local players=GetPlayers() or {};
Console:SendToTarget(player,"%26s %8s %8s %8s %8s %8s %8s %8s %8s","Player","ACCRC","SKILL","BSKLL","AVGDT","CMBTR","TMRTO","DIFF","FBONE")
for i,v in ipairs(players) do
if v.skill then
CalcSkill(v)
local topBone = "unknown"
local mat = v.mtl_table or {}
local mx = 0
for j,w in pairs(mat) do
if w>mx then
topBone = j
mx = w
end
end
Console:SendToTarget(player,"%26s %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f $5%s (%.3f %%)",v:GetName(), v.skill.accuracy, v.skill.skillQuotient,v.skill.bulletRatio,v.skill.avgDst,v.skill.combatRatio,v.skill.timeRatio,v.skill.difference or 0, topBone, 100*mx/(v.mtl_ctr or 1));
else
Console:SendToTarget(player,"%26s <no data yet>",v:GetName())
end
end
Console:SendToTarget(player,"Average skill: %.4f", GetAvgSkill())
else
local shots, hits = target.aimStatsShots or 0, target.aimStatsHits or 0;
local accuracy = 100 * (hits / (math.max(1, shots)))
local at = target.aimTable or {};
Console:SendToTarget(player,"$4Won combats: %d, lost combats: %d (r: %.4f) bullet skill: %.6f",target.wonCombats or 0,target.lostCombats or 0,target.skill.combatRatio or 0,target.skill.bulletRatio or 0)
Console:SendToTarget(player,"$4Skill quotient: %.7f, diff value: %.4f (avg: %.4f)", target.skill.skillQuotient, target.skill.difference or 0, GetAvgSkill())
Console:SendToTarget(player,"$7AimStats for player: $6%s$8",target:GetName());
Console:SendToTarget(player,"$8 shots: $6%5d$8, hits: $6%5d$8, accuracy: $6%.2f%%",shots, hits, accuracy);
Console:SendToTarget(player,"$7Weapon stats for player $6%s",target:GetName())
for i,v in pairs(at) do
Console:SendToTarget(player," $6%s$8 - shots: $6%d$8, hits: $6%d$8, accuracy: $6%.2f%%",i,v.shots,v.hits,100*(v.hits / math.max(1,v.shots)))
end
Console:SendToTarget(player,"$8First hit material stats: ");
local mat = target.mtl_table or {}
for i,v in pairs(mat) do
Console:SendToTarget(player," $6%s:$7 %d (%.2f)", i, v, 100*v/(target.mtl_ctr or 1));
end
end
self:OpenConsole(player)
end,{PLAYER},nil,"See your accuracy stats in console!");
function ShowAimStats(...)
local players=GetPlayers() or {};
printf("%26s %8s %8s %8s %8s %8s %8s %8s %8s","Player","ACCRC","SKILL","BSKLL","AVGDT","CMBTR","TMRTO","DIFF","PID")
for i,v in ipairs(players) do
if v.skill then
CalcSkill(v)
printf("%26s %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f %s",v:GetName(), v.skill.accuracy, v.skill.skillQuotient,v.skill.bulletRatio,v.skill.avgDst,v.skill.combatRatio,v.skill.timeRatio,v.skill.difference or 0,tostring(v.profile));
else
printf("%26s <no data yet>", v:GetName())
end
end
printf("Average skill: %.4f", GetAvgSkill())
end
function GetAvgSkill()
local players=GetPlayers() or {};
local totalSkill,cnt = 0, 0
for i,v in pairs(players) do
if v.skill and v.skill.skillQuotient>0 then
totalSkill = totalSkill + v.skill.skillQuotient
cnt = cnt + 1
end
end
return totalSkill/math.max(1, cnt)
end
System.AddCCommand("aim_stats","ShowAimStats(%%)","Shows aim stats table")
end
❤️ 0