Aimbot, cloak hack detection and skill balancer

  • Zi;

    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


  • Lukas

    Gj Zi, I hope we're gonna see Smirnoff on this server or he will dodge.. :)

  • SashsBrest

    Without any anticheats all know,Smirnoff aka SadamHussein =cheater nab. I do not understand why he is still not banned?! every cheater should get what they deserve!!!
    Him account n2 /profile/17608/Kontra__SadamHusein_

  • HoneY^

    Smirnoff with VPN :D

  • SashsBrest

    Remove server with hacker name Smirnoff's combat school. or rename Smirnoff's aimbot school.Zi make new anticheat and he stop play ahahah

  • SashsBrest

    Today in noobspot player Artem2023 strange teleport on 10 meters,maybe big lags or hacks idk . do not take his eyes off him
    look him video


  • Lycor

    Its not a surprise that many russian players prefer cheating instead of getting better with training. Not only in Crysis and not just Sashka.

  • misterSD

    This video is from 2011 ....
    So what is the interest to show it in this thread.

  • SashsBrest

    This video is from 2011 ....
    So what is the interest to show it in this thread.

    Read what I wrote above! Perhaps he again use hacks

  • Lukas

    YouTube name Artem2023, player name Artem2023... Probably just an old cheater cheating again.