Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- CONFIG SECTION
- checkInterval = 60 -- The interval in seconds after which the script will check all players' ratings and compare them.
- -- Ratings fluctuate a lot during the first minutes of playing and need some time to even out.
- -- The shorter you choose the interval, the higher the chance of unjustified warnings/kicks.
- minPlayTimePercentage = 40 -- The minimum percentage of _checkInterval that a player needs to have already spent playing
- -- for his rating to be taking into account (spectator time does not count).
- -- This is done to prevent recently joined players with biased ratings from affecting the average or getting kicked.
- -- EXAMPLE: If the interval is 10min and the playTimePercentage is 80, then all players who have not yet
- -- spent at least 8 minutes playing during the current map are ignored.
- percentageThreshold = 188 -- A player will be punished if they exceed all players' average rating by this many percent
- kickLimit = 0 -- A player will be warned this many times before being kicked from the server.
- -- Set to 0 to insta-kick without warnings.
- -- NOTE: The script only works per round, nothing is saved between maps!
- -- So keep in mind that it takes a player (_kickLimit + 1) * _checkInterval seconds to be kicked.
- -- On short maps, this might be unreachable with the default values.
- -- EXAMPLE: Your interval is 10 minutes, your kicklimit 2.
- -- That means it takes a player at least 30 minutes to be kicked by the script.
- -- Most matches will be over by that time meaning the player will go unaffected.
- -- An inter-round solution might be necessary, maybe in a future release
- kickReason = "AntiCheat has kicked - due to aimbot/multihack." -- The message that is displayed to kicked players
- banTime = 14400 -- The time in seconds that a kicked player will be banned from the server
- -- By default, the script will check all players Kills/Deaths, Damage Given/Received and Kills/Second ratio and calculate the average.
- -- If you want one ratio to have a higher weighting or completely disable one, alter their multipliers here.
- -- A multiplier of 0 means the ratio will be ignored.
- -- NOTE: Kills/Deaths & Kills/Second ratios respect the weapon whitelist (if enabled), damage ratio doesn't
- -- EXAMPLE: If all multipliers are equal, the average will consist of 33%/33%/33%
- -- If you set the multipliers to 2/1/3, the average will be 33%/17%/50%
- -- For 1/0/2, the average will be 33%/0%/67%
- multiplier_killDeathRatio = 1 -- multiplier of "kills per life" ratio
- multiplier_damageRatio = 1 -- multiplier of "damage given/received" ratio
- multiplier_killsPerSecondRatio = 1 -- multiplier of "kills per second" ratio
- minimumPlayers = 3 -- The script will only become active when at least this many people are playing and have served
- -- _minPlayTimePercentage of _checkInterval - spectators and newly joined players are ignored.
- -- With only two players playing, one being an average player and the other one a complete retard,
- -- it would get the normal player kicked because of the skill difference. Hence the minimum limit.
- --[[
- -- This script gives you the possibility to whitelist certain weapons.
- -- Kills/Deaths from a whitelisted weapons don't count.
- -- This is done to prevent e.g. artillery or landmine kills from getting a player kicked.
- -- If people start complaining about getting kicked for rifle grenade or mortar kills, you can whitelist these weapons.
- -- The whitelist is commented out and thus inactive by default. If you want to use it, remove the comment tags and PROPERLY SET IT UP.
- -- The damage ratio does not respect the whitelist, meaning it will also contain damage done by whitelisted weapons.
- -- NOTE: Below MOD list is for etpro, your mod might use a different one!
- -- See if you can find it by searching for "methodOfDeath" or "meansOfDeath"
- -- MOD list for No Quarter: http://shitstorm.org/noquarter/wiki/index.php?title=Lua_Scripting#MOD:_Means_of_Death
- -- NOTE: LUA TABLES START AT INDEX 1 !!!
- weaponWhitelist = {
- -- true = don't count kills
- -- false = count kills
- true, -- MOD_MACHINEGUN
- true, -- MOD_BROWNING
- true, -- MOD_MG42
- false, -- MOD_GRENADE
- true, -- MOD_ROCKET
- true, -- MOD_KNIFE
- false, -- MOD_LUGER
- false, -- MOD_COLT
- false, -- MOD_MP40
- false, -- MOD_THOMPSON
- false, -- MOD_STEN
- false, -- MOD_GARAND
- false, -- MOD_SNOOPERSCOPE
- false, -- MOD_SILENCER
- false, -- MOD_FG42
- false, -- MOD_FG42SCOPE
- false, -- MOD_PANZERFAUST
- false, -- MOD_GRENADE_LAUNCHER
- true, -- MOD_FLAMETHROWER
- false, -- MOD_GRENADE_PINEAPPLE
- false, -- MOD_CROSS
- false, -- MOD_MAPMORTAR
- false, -- MOD_MAPMORTAR_SPLASH
- false, -- MOD_KICKED
- false, -- MOD_GRABBER
- true, -- MOD_DYNAMITE
- true, -- MOD_AIRSTRIKE
- false, -- MOD_SYRINGE
- true, -- MOD_AMMO
- true, -- MOD_ARTY
- true, -- MOD_WATER
- true, -- MOD_SLIME
- true, -- MOD_LAVA
- true, -- MOD_CRUSH
- true, -- MOD_TELEFRAG
- true, -- MOD_FALLING
- false, -- MOD_SUICIDE
- true, -- MOD_TARGET_LASER
- true, -- MOD_TRIGGER_HURT
- true, -- MOD_EXPLOSIVE
- false, -- MOD_CARBINE
- false, -- MOD_KAR98
- false, -- MOD_GPG40
- false, -- MOD_M7
- true, -- MOD_LANDMINE
- true, -- MOD_SATCHEL
- true, -- MOD_TRIPMINE
- true, -- MOD_SMOKEBOMB
- false, -- MOD_MOBILE_MG42
- false, -- MOD_SILENCED_COLT
- false, -- MOD_GARAND_SCOPE
- true, -- MOD_CRUSH_CONSTRUCTION
- true, -- MOD_CRUSH_CONSTRUCTIONDEATH
- true, -- MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER
- false, -- MOD_K43
- false, -- MOD_K43_SCOPE
- true, -- MOD_MORTAR
- false, -- MOD_AKIMBO_COLT
- false, -- MOD_AKIMBO_LUGER
- false, -- MOD_AKIMBO_SILENCEDCOLT
- false, -- MOD_AKIMBO_SILENCEDLUGER
- true, -- MOD_SMOKEGRENADE
- true, -- MOD_SWAP_PLACES
- true -- MOD_SWITCHTEAM
- -- NOTE: THERE'S NO COMMA AFTER THE LAST ENTRY !!
- }
- --]]
- -- playerWhiteList = "nopro_playerWhitelist.dat"
- -- This script gives you the possibility to exclude players from being punished by the script.
- -- You can do this if you and the script can't agree whether a player is "too skilled" for the server.
- -- Enable the whitelist by removing the comment tags and creating the (empty) file inside your etmain or mod folder - the script can't do it !!
- -- Add players to the list at runtime with the server-side command "!nopro <name>".
- -- You can add a custom shrubbot command to let your admins do this without having to share the rcon password.
- -- debugSettings = true -- The default values are most likely non-functional.
- -- I have tested the script with bots to make sure it works properly but I have no human players to test this with
- -- so I leave tweaking the settings to you.
- -- If you enable debugging, the script prints some debug info to global chat every time the interval runs out.
- -- This will hopefully help you to adjust the settings to your needs.
- -- NOTE: When you first run the script, set kickLimit to something unreachably high and make sure you don't have
- -- unjustified kicks before actually "arming" the script or you might scare off your playerbase
- -- END OF CONFIG SECTION
- ----------------------------------------------------------------
- -- DONT CHANGE ANYTHING BELOW UNLESS YOU KNOW WHAT YOU ARE DOING
- ----------------------------------------------------------------
- timesWarned = {} -- number of times a player has already been warned
- whitelist = {} -- contains GUIDs of player whitelist
- kills = {} -- custom kills counter, for weapon white list
- deaths = {} -- custom deaths counter, for weapon white list
- lastStartTime = {} -- timestamp of when client joined a team (if on a team, else nil)
- timePlayedAlready = {} -- time that client has already spent on a team in current map (in milliseconds)
- function et_RunFrame( levelTime )
- if math.mod(levelTime,checkInterval) ~= 0 then return end
- if et.trap_Cvar_Get("gamestate") ~= "0" then return end
- local avg_killDeathRatio = 0
- local avg_damageRatio = 0
- local avg_killsPerSecondRatio = 0
- local killDeathRatio = {}
- local damageRatio = {}
- local killsPerSecondRatio = {}
- local ratedPlayers = {} -- contains all clients that are being checked for ratio violations
- local numRatedPlayers = 0 -- rated = (!BOT && !WHITELISTED && MINIMUM_INTERVAL_PERCENTAGE_SERVED)
- local numActivePlayers = 0 -- amount of human players not in spectator, for minimum player count
- for i=0,tonumber(et.trap_Cvar_Get("sv_maxclients"))-1 do
- if et.gentity_get(i, "pers.connected") > 0 and et.gentity_get(i, "pers.localClient") == 0 then
- local sessionPlayTime = (timePlayedAlready[i] or 0) + (lastStartTime[i] and (et.trap_Milliseconds() - lastStartTime[i]) or 0)
- if sessionPlayTime > (checkInterval * minPlayTimePercentage / 100) then
- local kills = (weaponWhitelist and (kills[i] or 0) or et.gentity_get(i, "sess.kills"))
- -- adding 1 to avoid division by 0
- local deaths = (weaponWhitelist and (deaths[i] or 0) or et.gentity_get(i, "sess.deaths")) + 1
- killDeathRatio[i] = kills / deaths
- damageRatio[i] = et.gentity_get(i, "sess.damage_given") / (et.gentity_get(i, "sess.damage_received") + 1)
- killsPerSecondRatio[i] = kills / sessionPlayTime -- kills per millisecond, really
- avg_killDeathRatio = avg_killDeathRatio + killDeathRatio[i]
- avg_damageRatio = avg_damageRatio + damageRatio[i]
- avg_killsPerSecondRatio = avg_killsPerSecondRatio + killsPerSecondRatio[i]
- numRatedPlayers = numRatedPlayers + 1
- local team = et.gentity_get(i, "sess.sessionTeam")
- if team == 1 or team == 2 then
- numActivePlayers = numActivePlayers + 1
- end
- if not whitelist[et.Info_ValueForKey(et.trap_GetUserinfo(i),"cl_guid")] then
- ratedPlayers[i] = true
- end
- end
- end
- end
- if numActivePlayers < minimumPlayers then return end -- don't continue if the minimum player count is not reached
- if numRatedPlayers == 0 then return end -- prevent division by 0
- avg_killDeathRatio = avg_killDeathRatio / numRatedPlayers
- avg_damageRatio = avg_damageRatio / numRatedPlayers
- avg_killsPerSecondRatio = avg_killsPerSecondRatio / numRatedPlayers
- if debugSettings then
- sendCmd("qsay Average killDeathRatio: " .. avg_killDeathRatio)
- sendCmd("qsay Average damageRatio: " .. avg_damageRatio)
- sendCmd("qsay Average killsPerSecondRatio: " .. avg_killsPerSecondRatio)
- end
- local ignore_killDeathRatio = (avg_killDeathRatio == 0 and true or false)
- local ignore_damageRatio = (avg_damageRatio == 0 and true or false)
- local ignore_killsPerSecondRatio = (avg_killsPerSecondRatio == 0 and true or false)
- if ignore_killDeathRatio and ignore_damageRatio and ignore_killsPerSecondRatio then return end -- no data yet
- for i, v in pairs(ratedPlayers) do
- ratio = ((ignore_killDeathRatio and 0 or ((killDeathRatio[i] - avg_killDeathRatio) / (avg_killDeathRatio / 100) * multiplier_killDeathRatio))
- + (ignore_damageRatio and 0 or ((damageRatio[i] - avg_damageRatio) / (avg_damageRatio / 100) * multiplier_damageRatio))
- + (ignore_killsPerSecondRatio and 0 or ((killsPerSecondRatio[i] - avg_killsPerSecondRatio) / (avg_killsPerSecondRatio / 100) * multiplier_killsPerSecondRatio)))
- / ((ignore_killDeathRatio and 0 or multiplier_killDeathRatio) + (ignore_damageRatio and 0 or multiplier_damageRatio) + (ignore_killsPerSecondRatio and 0 or multiplier_killsPerSecondRatio))
- if debugSettings then
- sendCmd("qsay Rating of " .. et.Info_ValueForKey(et.trap_GetUserinfo(i),"name") .. " ^7is off by " .. math.floor(ratio + 0.5) .. " percent")
- end
- if ratio > percentageThreshold then -- YUNOSUPPORTCONTINUE
- et.G_globalSound("sound/misc/referee.wav")
- if kickLimit > (timesWarned[i] or 0) then -- warn
- timesWarned[i] = (timesWarned[i] or 0) + 1
- sendCmd("qsay ^dnopro: ^7" .. et.Info_ValueForKey(et.trap_GetUserinfo(i),"name") .. " ^9has been warned for having a ratio of ^2"
- .. math.floor(ratio + 0.5) .. " ^9percent above average")
- et.trap_SendServerCommand(i, "cp \"^3*** ^1WARNING " .. timesWarned[i] .. "/" .. kickLimit .. " - OPEN CONSOLE FOR DETAILS! ^3***")
- et.trap_SendServerCommand(i, "print \"^1=========================\n")
- et.trap_SendServerCommand(i, "print \"^1*** ^3SKILL WARNING " .. timesWarned[i] .. "/" .. kickLimit .. " ^1***\n")
- et.trap_SendServerCommand(i, "print \"^1=========================\n")
- et.trap_SendServerCommand(i, "print \"^3You have exceeded this server's average skill rating of this session by ^2"
- .. math.floor(ratio + 0.5) .. "^3 percent.\n")
- et.trap_SendServerCommand(i, "print \"^3Only a deviation of " .. percentageThreshold .. " percent is allowed.\n")
- et.trap_SendServerCommand(i, "print \"^3You seem to be overqualified for this server. Please find a more suitable one!\n")
- et.trap_SendServerCommand(i, "print \"^1=========================\n")
- else
- et.trap_DropClient( i, kickReason, banTime ) -- kick
- end
- end
- end
- end
- function et_Print(text)
- if string.sub(text,1,13) ~= "ClientBegin: " then return end
- local id = tonumber(string.sub(text,14))
- if not id then return end
- local team = et.gentity_get(id, "sess.sessionTeam")
- if (team == 1 or team == 2) then
- if lastStartTime[id] then return end -- team -> team, ignore
- lastStartTime[id] = et.trap_Milliseconds() -- spec -> team
- else
- if not lastStartTime[id] then return end -- spec -> spec, ignore
- timePlayedAlready[id] = (timePlayedAlready[id] or 0) + (et.trap_Milliseconds() - lastStartTime[id])
- lastStartTime[id] = nil -- team -> spec
- end
- end
- function et_ClientConnect( clientNum, firstTime, isBot )
- if firstTime == 0 or isBot == 1 then return end
- timesWarned[clientNum] = nil
- end
- function et_Obituary( victim, killer, meansOfDeath )
- if killer == 1022 or victim == killer or killer == 1023
- or et.gentity_get(victim, "sess.sessionTeam") == et.gentity_get(killer, "sess.sessionTeam") then return end
- -- 1022 = worldspawn, 1023 = ENTITYNUM_NONE
- -- don't count kills by self, team and world
- kills[killer] = kills[killer] + 1
- deaths[victim] = deaths[victim] + 1
- end
- function sendCmd(cmd)
- et.trap_SendConsoleCommand(et.EXEC_APPEND, cmd .. ";")
- end
- function et_InitGame(levelTime, randomSeed, restart)
- if (multiplier_killDeathRatio + multiplier_damageRatio + multiplier_killsPerSecondRatio) == 0 then
- sendCmd("qsay ^dnopro: ^9Ratio multipliers add up to 0, set at least one > 0. Aborting..")
- et.RegisterModname("one4oneAC [INACTIVE]")
- timesWarned = nil
- whitelist = nil
- kills = nil
- deaths = nil
- lastStartTime = nil
- timePlayedAlready = nil
- et_RunFrame = nil
- et_Print = nil
- et_ClientConnect = nil
- et_Obituary = nil
- sendCmd = nil
- et_ConsoleCommand = nil
- return
- end
- checkInterval = checkInterval * 1000 -- transform to milliseconds
- if not weaponWhitelist then
- et_Obituary = nil
- kills = nil
- deaths = nil
- end
- et.RegisterModname("one4oneAC")
- if not playerWhiteList then
- et_ConsoleCommand = nil
- return
- end
- local fd,len = et.trap_FS_FOpenFile(playerWhiteList, et.FS_READ)
- if len < 0 then
- sendCmd("qsay ^dnopro: ^9Couldn't open whitelist file ^7" .. playerWhiteList .. "^9. Make sure it exists and has proper file permissions")
- else
- for line in string.gfind(et.trap_FS_Read(fd, len), "(%x+)") do
- if not line then break end
- if string.len(line) == 32 and not whitelist[line] then
- whitelist[line] = true
- end
- end
- end
- et.trap_FS_FCloseFile(fd)
- end
- function et_ConsoleCommand(command)
- if string.lower(et.trap_Argv(0)) ~= "!nopro" then return 0 end
- local feedback
- local arg1 = et.trap_Argv(1)
- local id = et.ClientNumberFromString(arg1)
- if arg1 == "" then
- feedback = "^9Usage: ^2!nopro <playerName> ^9to add a player to the whitelist"
- elseif not id or id == -1 then
- feedback = "^9No or multiple matches found for player ^7" .. arg1 .. "^9. Be more specific or use client #"
- else
- local guid = et.Info_ValueForKey(et.trap_GetUserinfo(id),"cl_guid")
- local name = et.Info_ValueForKey(et.trap_GetUserinfo(id),"name")
- if et.gentity_get(id, "pers.localClient") == 1 then
- feedback = "^7" .. name .. " ^9is a bot and can't be whitelisted"
- elseif whitelist[guid] then
- feedback = "^7" .. name .. " ^9is already on the whitelist"
- elseif not guid or string.len(guid) ~= 32 then
- feedback = "^7" .. name .. " ^9doesn't have a GUID and can't be whitelisted"
- else
- local fd,len = et.trap_FS_FOpenFile(playerWhiteList, et.FS_APPEND)
- if len < 0 then
- feedback = "^9Couldn't open whitelist file ^7" .. playerWhiteList .. "^9. Make sure it exists and has proper file permissions"
- else
- local data = guid .. " | " .. name .. "\n"
- bytes_written = et.trap_FS_Write(data, string.len(data), fd)
- if bytes_written <= 0 then
- feedback = "^9Couldn't write to whitelist file ^7" .. playerWhiteList .. "^9. Make sure it exists and has proper file permissions"
- else
- whitelist[guid] = true
- feedback = "^7" .. name " ^9has been successfully added to the whitelist"
- end
- end
- et.trap_FS_FCloseFile(fd)
- end
- end
- et.G_Print("^dnopro: " .. feedback .. "\n") -- this line prints to server console
- -- sendCmd("qsay ^dnopro: " .. feedback) -- this line prints to global chat
- return 1
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement