timeafkbeforeset = 1 -- minutes timeafkbeforekick = 3 -- minutes maxplayersbeforekick = 16 zombies = true afkkick_msg = "%s get kicked to be afk!" afkset_msg = "%s enter in afk mode!" afkunset_msg = "%s kicked afk mode!" CurrentAim = {} playerWasKilled = {} afk = {} afktime = {} currentplayers = 0 isKicked = {} afkSpot = {} function GetRequiredVersion() return 10057 end function OnScriptLoad(processid) if zombies then zombie_team = getZombieTeam() end for i = 0,15 do if getplayer(i) then afktime[gethash(i)] = 0 currentplayers = currentplayers + 1 afkSpot[i] = {} end end afktimer = registertimer(500, "afkTimer") handleafks = registertimer(1000, "handleAfks") --using the hide method seemed to crash the server occasionally --hiddentimer = registertimer(20, "hiddenTimer") end function OnScriptUnload() end function OnNewGame(map) end function OnGameEnd(mode) if mode == 1 then removetimer(afktimer) removetimer(handleafks) --removetimer(hiddentimer) ongameend = true end end function OnServerChat(player, mode, message) if message:find("!afkstatus") then player = tonumber(message:sub(12, 13)) privatesay(player, tostring(getname(player)) .. ": " .. tostring(playerIsAfk(player))) return 0 end local hash = gethash(player) if hash then afktime[hash] = 0 end return 1 end function OnServerCommand(player, command) return 1 end function OnTeamDecision(team) return team end function OnPlayerJoin(player, team) if not ongameend then currentplayers = currentplayers + 1 afktime[gethash(player)] = 0 local hash = gethash(player) CurrentAim[hash] = {} afkSpot[player] = {} else sayWizard("WTF! ONGAMEEND IS TRUE BRO") end end function OnPlayerLeave(player, team) currentplayers = currentplayers - 1 afktime[gethash(player)] = 0 afk[player] = nil local hash = gethash(player) CurrentAim[hash] = nil isKicked[player] = nil afkSpot[player] = {} end function OnPlayerKill(killer, victim, mode) if mode == 0 then --sayWizard(tostring(getname(victim)) .. " is killed by the server") end playerWasKilled[victim] = true end function OnKillMultiplier(player, multiplier) end function OnPlayerSpawn(player, m_objectId) end function OnPlayerSpawnEnd(player, m_objectId) registertimer(800, "JustSpawned", player) end function JustSpawned(id, count, player) if playerWasKilled[player] then playerWasKilled[player] = nil updatePlayerAim(player) --sayWizard(tostring(getname(player)) .. " has spawned! Possibly no longer afk!") end if afk[player] then local m_object = getobject(getplayerobjectid(player)) writebit(m_object, 0x10, 7, 0) local m_objectId = getplayerobjectid(player) local x,y,z = getobjectcoords(m_objectId) movobjcoords(m_objectId, x, y, z-100) local m_object = getobject(m_objectId) afkSpot[player] = {x, y, z} end return 0 end function OnTeamChange(relevant, player, team, change) playerWasKilled[player] = true return 1 end function OnClientUpdate(player, m_objectId) end function OnObjectInteraction(player, m_objectId, tagtype, tagname) return 1 end function OnWeaponReload(player, weapon) return 1 end function OnVehicleEntry(relevant, player, vehicle, tagname, seat) return 1 end function OnVehicleEject(player, forced) return 1 end function OnDamageLookup(receiving_obj, causing_obj, tagdata, tagname) local receiver = objecttoplayer(receiving_obj) if receiver then if (tagname == "globals\\falling" or tagname == "globals\\distance") and afk[receiver] then writefloat(tagdata, 0x1D0, 0.0000001) writefloat(tagdata, 0x1D4, 0.0000001) writefloat(tagdata, 0x1D8, 0.0000001) end end end function OnWeaponAssignment(player, m_objectId, count, tagname) return 0 end function OnObjectCreation(m_objectId, owner, tagname) end --This timer will add the AFK times of all the players to a table --so it can be used by the other timers. This timer also unsets afk players. function afkTimer(id, count) for i = 0,15 do if getplayer(i) then local hash = gethash(i) if playerIsAfk(i) then afktime[hash] = afktime[hash] + (1/120) else --check if the player is set as afk --if they are, unafk them. if afk[i] then afk[i] = nil unsetAfkPlayer(i) say(string.format(afkunset_msg, getname(i))) end afktime[hash] = 0 end end end return 1 end --this timer is responsible for handling AFK players if they're AFK for a set amount of time function handleAfks(id, count) local player = getLongestAfkPlayer() if player[2] >= timeafkbeforekick then if currentplayers >= maxplayersbeforekick and not isKicked[player[1]] then say(string.format(afkkick_msg, getname(player[1]))) svcmd("sv_kick " .. resolveplayer(player[1])) isKicked[player[1]] = true end end for i = 0,15 do if getplayer(i) then local hash = gethash(i) if afktime[hash] >= timeafkbeforeset and not afk[i]then setAfkPlayer(i) say(string.format(afkset_msg, getname(i))) end end end checkIfAllZombiesAfk() return 1 end --this timer is responsible for hiding afk players. function hiddenTimer(id, count) if afk ~= {} then for k,v in pairs(afk) do local m_player = getplayer(k) --say("HIDING: " .. tostring(getname(k))) .. " Player #: " .. k) writefloat(m_player, 0xF8, 9999) writefloat(m_player, 0xFC, 9999) writefloat(m_player, 0x100, 9999) end end return 1 end --this function will loop through all the players and return the player --that has been AFK the longest. function getLongestAfkPlayer() local max = {0,0} for k,v in pairs(afktime) do if max[2] < afktime[k] and not afk[k] then max = {hashtoplayer(k), v} end end return max end --This function will update the player's aim in the currentaim table. function updatePlayerAim(player) local m_object = getobject(getplayerobjectid(player)) local x_aim = readfloat(m_object, 0x230) local y_aim = readfloat(m_object, 0x234) local z_aim = readfloat(m_object, 0x238) local hash = gethash(player) if hash then CurrentAim[hash] = {x_aim, y_aim, z_aim} else sayWizard("AIM COULD NOT BE UPDATED FOR PLAYER: " .. tostring(getname(player)) .. " Number: " .. tostring(player)) end end --This function will determine if the passed player is AFK function playerIsAfk(player) local m_player = getplayer(player) if m_player then local m_object = getobject(getplayerobjectid(player)) local x_aim = readfloat(m_object, 0x230) local y_aim = readfloat(m_object, 0x234) local z_aim = readfloat(m_object, 0x238) local hash = gethash(player) if playerWasKilled[player] then --sayWizard("playerwaskilled: " .. tostring(getname(player)) .. " returning true") return true end if not CurrentAim[hash] then CurrentAim[hash] = {x_aim, y_aim, z_aim} sayWizard(tostring(getname(player)) .. " this shouldn't be called when killed") return false else if (x_aim ~= CurrentAim[hash][1]) or (y_aim ~= CurrentAim[hash][2]) or (z_aim ~= CurrentAim[hash][3]) then CurrentAim[hash] = {x_aim, y_aim, z_aim} --sayWizard(tostring(getname(player)) .. " this shouldn't be called when killed either") return false else --sayWizard(tostring(getname(player)) .. " is afk (towiz)") return true end end else --sayWizard("M_PLAYER IS NIL IN PLAYERISAFK") return true end --sayWizard("EPIC ERROR IN PLAYERISAFK") return false end function checkIfAfk(player) if afk[player] then return true end return false end --This function will check if all the zombies are afk, if they are --then this function will change a random person's team function checkIfAllZombiesAfk() local zombies = getZombies() if #zombies > 1 then --this next section will determine if all the zombies are afk or not local bool = true for i = 1,#zombies do if not checkIfAfk(zombies[i]) then bool = false break end end --now we change a random person to zombie cuz all the zombies are currently afk if bool then local player = ChooseRandomPlayer(1) say(tostring(getname(player)) .. " will be changed to zombie because all the zombies are afk!") --sayWizard(tostring(#zombies)) changeteam(player, false) kill(player) else --sayWizard("NO ZOMBIES ARE AFK") end end end function sayWizard(message) for i = 0,15 do if getplayer(i) then if gethash(i):find("56d5f") then privatesay(i, message) break end end end end -- this function searches through current players and selects a random one function ChooseRandomPlayer(excludeTeam) local t = {} -- loop through all 16 possible spots and add to table for i=0,15 do -- check if the player exists local team = getteam(i) if team and team ~= excludeTeam then table.insert(t, i) end end if #t > 0 then -- generate a random number that we will use to select a player local tableCount = #t local r = getrandomnumber(1, tableCount+1) return t[r] else return nil end end --This function will project the player at coords 9999,9999,9999 by setting a boolean to true in a table --and it will also ghost them, meaning that people will walk through them. They can be killed by vehicles. function setAfkPlayer(player) updatePlayerAim(player) if zombies then if getteam(player) == zombie_team then --checkIfAllZombiesAfk() --say("CHECKING IF ALL ZOMBIES IS AFK") local m_objectId = getplayerobjectid(player) local x,y,z = getobjectcoords(m_objectId) z = z or 69 movobjcoords(m_objectId, x, y, z-100) local m_object = getobject(m_objectId) afkSpot[player] = {x, y, z} writebit(m_object, 0x10, 7, 1) else --sayWizard("CHANGING TEAM") changeteam(player, false) kill(player) afkSpot[player] = {} end end afk[player] = true end --This function unsets an AFK player so they can return to the game. function unsetAfkPlayer(player) afk[player] = nil local m_objectId = getplayerobjectid(player) movobjcoords(m_objectId, afkSpot[player][1], afkSpot[player][2], afkSpot[player][3] + 2) local m_object = getobject(m_objectId) writebit(m_object, 0x10, 7, 0) afkSpot[player] = {} end function getZombies() local zombies = {} for i = 0,15 do local m_player = getplayer(i) local team = readbyte(m_player, 0x20) if team == zombie_team then table.insert(zombies, i) end end local msgz = "" for i = 1,#zombies do msgz = msgz .. tostring(getname(zombies[i])) .. " " end --sayWizard(msgz) return zombies end function getZombieTeam() return 1 end function hashtoplayer(hash) for i = 0, 15 do if gethash(i) == hash then return i end end end