-- General infection settings zombie_team = 1 -- 0 is red, 1 is blue human_team = 1 - zombie_team zombie_speed = 2 -- zombie speed join_team = zombie_team -- the team that people will join as if a game is currently running lastman_speed = 1.5 -- last man speed lastman_dmgmodifier = 1.5 -- damage modifier for the last man (on top of human damage) lastman_invistime = 10 -- in seconds human_speed = 1.0 -- speed when not infected zombie_count = 1 -- if value is less than 1 is it used as a percentage, more than or equal to one is absolute count last_man_next_zombie = true -- if this value is true the last man standing becomes the next zombie, if not it's random max_zombie_count = 2 -- this caps what the zombie count would be w/ ratio (nil is disable) lastman_invulnerable = 5 -- time (in seconds) the last man is invulnerable for: replace with nil to disable alphazombie_frag_count = 0 -- number of frag nades they spawn with alphazombie_plasma_count = 0 -- number of plasma nades they spawn with zombie_frag_count = 0 -- number of frag nades they spawn with zombie_plasma_count = 0 -- number of plasma nades they spawn with alphazombie_clip_count = 0 -- number of shots in clip (loaded ammo) alphazombie_ammo_count = 0 -- backpack ammo they get (unloaded ammo) alphazombie_battery_count = 0 -- stored as a percent (0 to 1, do NOT go over or under) zombie_clip_count = 0 -- number of shots in clip for zombies once there are not only alpha zombies (loaded ammo) zombie_ammo_count = 0 -- backpack ammo zombies once there are not only alpha zombies (unloaded ammo) zombie_battery_count = 0 -- stored as a percent (0 to 1, do NOT go over or under) infect_on_fall = true -- if this is set to true then people who die from fall damage will become zombies. infect_on_guardians = false -- if this is set to true then people who get killed by the guardians will become zombies. infect_on_suicide = true -- if this is set to true then people who kill themselves will become a zombie. infect_on_betray = true -- if this is set to true then people who betray their teammates will become a zombie. humans_allowed_in_vehis = true -- if this is set to false then humans cannot enter vehicles zombies_allowed_in_vehis = false -- if this is set to false then zombies cannot enter vehicles. zombies_invisible_on_crouch = true -- if this is set to true then zombies will be invisible when they crouch. humans_invisible_on_crouch = false -- if this is set to true then humans will become invisible when they crouch. --Zombie weapons. -- Note: If you decide the player holds a flag or a ball, make sure the secondary, tertiary, and quarternary fields are "". -- DO NOT make zombies hold multiple weapons if you want them to hold an oddball or a flag. If you do it will not work right, and it's entirely your fault. zombie_weapon = {} -- don't touch this zombie_weapon[1] = "weapons\\flag\\flag" -- Primary weapon for zombies zombie_weapon[2] = "" -- Secondary weapon for zombies. zombie_weapon[3] = "" -- Tertiary weapon for zombies. zombie_weapon[4] = "" -- Quarternary weapon for zombies. -- Game messages zombie_message = "YOU'RE A ZOMBIE. KILL THE HUMANS!" human_message = "YOU'RE A HUMAN. SURVIVE." rejoin_message = "Please don't leave and rejoin. You've been put back onto your last team." infected_message = " has been infected!" teamkill_message = "Don't team kill..." blockteamchange_message = "You're not allowed to change team." zombieinvis_message = "The zombies are invisible for 20 seconds!" timer_team_change_msg = "Thank you. The game will now continue" in_hill_too_long_msg = " has been infected because they were in the hill too long!" welcome_message = "Welcome to Zombies, brought to you by Phasor\nhttp://phasor.proboards.com" koth_additional_welcome_msg = "The hill is a safezone! Use it for quick getaways!" slayer_additional_welcome_msg = "The nav points are not just for decoration!\nThey will point to the last man surviving!" lastman_message = "%s is the last human alive and is invisible for %.0f seconds!" nozombiesleftmessage = "There are no zombies left. Someone needs to change team, otherwise a random player will be forced to." -- Don't modify below variables unless you know what you're doing cur_zombie_count = 0 cur_human_count = 0 alpha_zombie_count = 0 human_time = {} cur_players = 0 cur_last_man = nil last_man_hash = 0 processid = 0 game_started = false allow_change = false new_game_timer = 0 player_change_timer = 0 flagball_weap = {} flags_balls_table = {} last_hill_time = {} hash_table = {} inhill_time = {} -- This function is required for scripts to run on Phasor (including and after 01.00.03.104) -- You should return the minimum required version of Phasor -- Official releases: -- 01.00.03.104 - 3104 -- 01.00.10.057 - 10057 function GetRequiredVersion() return 10057 end -- called when the script is loaded function OnScriptLoad(process) for i = 1,4 do if zombie_weapon[i] == "weapons\\ball\\ball" or zombie_weapon[i] == "weapons\\flag\\flag" then oddball_or_flag = zombie_weapon[i] end end processid = process -- assume a game is running game_started = true game = GetGameAddresses() gametype = readbyte(gametype_base, 0x30) if gametype == 1 then gametype = "CTF" writedword(flag_respawn_addr, 0x0, 0xFFFFFFFF) registertimer(0, "DelayWriteCoords") elseif gametype == 2 then gametype = "Slayer" writebyte(gametype_base, 0x58, 3) speedtimer = registertimer(1000, "SpeedTimer") elseif gametype == 4 then gametype = "KOTH" end team_play = readbyte(gametype_base, 0x34) -- Confirmed. (Off = 0) (On = 1) if team_play == 1 then team_play = true else team_play = false zombie_team = 0 function getteam(player) local m_player = getplayer(player) if m_player then local team = readbyte(m_player, 0x20) if team then return team end end end function changeteam(player, forcekill, team, updatecounters) local m_player = getplayer(player) local cur_team = readbyte(m_player, 0x20) if not team then if cur_team ~= zombie_team then team = zombie_team end end if m_player then if team == zombie_team then writebyte(m_player, 0x20, team) writebyte(m_player, 0x60, 3) if forcekill == true or forcekill == 1 then kill(player) end if team ~= cur_team then OnFFATeamChange(player, cur_team, team, updatecounters) end return elseif team then writebyte(m_player, 0x20, team) else for i = 1,15 do local bool for j = 0,15 do local m_player = getplayer(j) if m_player then local team = readbyte(m_player, 0x20) if team == i then bool = true break end end end if not bool then team = i writebyte(m_player, 0x20, i) break end end end for i = 0,17 do if i ~= 3 then local bool for j = 0,15 do local m_player = getplayer(j) if m_player then local color = readbyte(m_player, 0x60) if color == i then bool = true break end end end if not bool then writebyte(m_player, 0x60, i) break end end end if forcekill == true or forcekill == 1 then kill(player) end end if team ~= cur_team then OnFFATeamChange(player, cur_team, team, updatecounters) end end function OnFFATeamChange(player, cur_team, dest_team, updatecounters) -- update team counts if not updatecounters then if dest_team == zombie_team then cur_human_count = cur_human_count - 1 cur_zombie_count = cur_zombie_count + 1 elseif dest_team ~= zombie_team then cur_human_count = cur_human_count + 1 cur_zombie_count = cur_zombie_count - 1 end end -- check if the game has started yet if game_started == true then --[[-- set attributes if dest_team == zombie_team then makezombie(player, false) elseif dest_team ~= zombie_team then makehuman(player, false) end--]] checkgamestate(player) end -- update team with local thisHash = gethash(player) hash_table[thisHash] = dest_team end end starting_equipment = readbit(gametype_base, 0x38, 2) -- Generic = 0, Custom = 1 if starting_equipment == 1 then starting_equipment = "Generic" else starting_equipment = "Custom" end humantimer = registertimer(1000, "HumanTimer") crouch_timer = registertimer(200, "invisCrouch") if oddball_or_flag then for i = 0,15 do if getplayer(i) then local m_object = getobject(getplayerobjectid(i)) if m_object then local weapID = readdword(m_object, 0x118) local weap = getobject(weapID) local tagName = getobjecttag(weapID) if tagName == oddball_or_flag then flagball_weap[i] = weapID table.insert(flags_balls_table, weapID) end end end end end -- recalculate team counters cur_zombie_count = getzombiesize() cur_human_count = gethumansize() cur_players = cur_zombie_count + cur_human_count -- recalculate how many "alpha" zombies there are alpha_zombie_count = getalphacount() -- load the last man hash (if there is one) local file = io.open("lasthash_" .. processid .. ".tmp", "r") if (file ~= nil) then -- read the ip last_man_hash = file:read("*line") file:close() -- delete the file os.remove("lasthash_" .. processid .. ".tmp") end checkgamestate() end function SpeedTimer(id, count) for i = 0,15 do if getteam(i) == zombie_team then local m_player = getplayer(i) local speed = readfloat(m_player, 0x60) if speed < zombie_speed then setspeed(i, zombie_speed) end end end return 1 end function gethumansize() local size = 0 for i = 0,15 do local m_player = getplayer(i) if m_player then local team = readbyte(m_player, 0x20) if team ~= zombie_team then size = size + 1 end end end return size end function getzombiesize() local size = 0 for i = 0,15 do local m_player = getplayer(i) if m_player then local team = readbyte(m_player, 0x20) if team == zombie_team then size = size + 1 end end end return size end GetGameAddresses = function() local map_header_version = readbyte(0x630E74, 0x4) if map_header_version == 7 then map_pointer = 0x63525c ctf_globals = 0x639B98 slayer_globals = 0x63A0E8 gametype_base = 0x671340 ctf_flag_stolen = 0x639BB4 ball_holder_addr = 0x639F1C team_oddball_score_array = 0x639E9C oddball_score_array = 0x639E5C koth_move_timer = 0x639D78 team_koth_score_array = 0x639BD0 team_race_score_array = 0x63A028 machine_pointer = 0x745BA0 flag_respawn_addr = 0x488A7E inhill_addr = 0x639C50 return "PC" else map_pointer = 0x5B927C ctf_globals = 0x5BDBB8 slayer_globals = 0x5BE108 gametype_base = 0x5F5498 ctf_flag_stolen = 0x5BD8B4 ball_holder_addr = 0x5BDF3C team_oddball_score_array = 0x5BDE9C oddball_score_array = 0x5BDE5C koth_move_timer = 0x5BDD78 team_koth_score_array = 0x5BDBF0 team_race_score_array = 0x5BD028 machine_pointer = 0x6C7980 flag_respawn_addr = 0x4638EE inhill_addr = 0x5BDC70 return "CE" end end -- called when the script is unloaded -- Do not return a value function OnScriptUnload() end function getobjecttag(object) local m_object = getobject(object) local object_map_id = readdword(m_object, 0x0) local map_base = readdword(map_pointer, 0x0) local map_tag_count = todec(endian(map_base, 0xC, 0x3)) local tag_table_base = map_base + 0x28 local tag_table_size = 0x20 for i=0,(map_tag_count - 1) do local tag_id = todec(endian(tag_table_base, 0xC + (tag_table_size * i), 0x3)) if tag_id == object_map_id then tag_name_address = endian(tag_table_base, 0x10 + (tag_table_size * i), 0x3) tag_name = readtagname("0x" .. tag_name_address) return tag_name end end end function endian(address, offset, length) local data_table = {} local data = "" for i=0,length do local hex = string.format("%X", readbyte(address, offset + i)) if tonumber(hex, 16) < 16 then hex = 0 .. hex end table.insert(data_table, hex) end for k,v in pairs(data_table) do data = v .. data end return data end function todec(number) return tonumber(number, 16) end -- called when a game is starting (before any players join) -- Do not return a value. function OnNewGame(Map) -- reset our variables cur_zombie_count = 0 cur_human_count = 0 cur_players = 0 map = Map -- the game hasn't started yet, will once timer runs down game_started = false new_game_timer = registertimer(2000, "NewGameTimer") if map == "putput" or map == "longest" or map == "beavercreek" then zombie_speed = 1.5 lastman_speed = 1.25 end end function DelayWriteCoords(id, count) writefloat(readdword(ctf_globals, 0x0), 0x8, readfloat(readdword(ctf_globals, 0x0), 0x8) - 100) writefloat(readdword(ctf_globals, 0x4), 0x8, readfloat(readdword(ctf_globals, 0x4), 0x8) - 100) return 0 end -- called when a game is ending -- Do not return a value. function OnGameEnd(mode) -- mode 1 = score menu (F1) is being displayed to clients, they are still ingame -- mode 2 = post game menu appeared -- mode 3 = players can quit via the post game score card -- remove the new game timer (if still active) if mode == 1 then removetimer(new_game_timer) removetimer(crouch_timer) game_started = false end end -- Called when there is chat within the server -- It must return a value which indicates whether or not the chat is sent. function OnServerChat(player, chattype, message) return 1 end -- Called when a server command is being executed -- It must return a value which indicates whether or not the command should be processed -- Note: It is only called when an authenticated (and allowed) player attempts to use the command. -- player is -1 when being executed via the server console. function OnServerCommand(player, command) local allow = 1 local tokencount = getcmdtokencount(command) if tokencount > 0 then local cmd = getcmdtoken(command, 0) if cmd == "sv_changeteam" and tokencount == 2 then local player = getcmdtoken(command, 1) player = rresolveplayer(player) if getplayer(player) then local cur_team = getteam(player) if cur_team == zombie_team then makehuman(player, true) privatesay(player, human_message) elseif cur_team ~= zombie_team then makezombie(player, true) privatesay(player, zombie_message) end hprintf("The player's team has been changed.") else hprintf("The specified player is invalid") end allow = 0 elseif cmd == "sv_map_reset" then for i = 0,15 do local m_player = getplayer(i) if m_player then local m_object = getobject(getplayerobjectid(i)) if m_object then local team = getteam(i) if team == zombie_team then destroyweaps(i) end end end end end end return allow end function HumanTimer(id, count) if game_started == true then for i = 0,15 do local m_player = getplayer(i) if m_player then local hash = gethash(i) local team = readbyte(m_player, 0x20) local m_object = getobject(getplayerobjectid(i)) if team ~= zombie_team and game_started then local m_playerObjId = getplayerobjectid(i) if getobject(m_playerObjId) then if tonumber(human_time[hash]) then human_time[hash] = tonumber(human_time[hash]) + 1 else human_time[hash] = 1 end end end if gametype == "KOTH" then if PlayerInHill(i) == true and m_object then --if cur_last_man ~= i then if inhill_time[hash] == nil then inhill_time[hash] = 0 writebit(m_object, 0x10, 7, 1) --[[say(getname(i) .. " is in the hill and they are immortal until they leave!") if team ~= zombie_team then say(getname(i) .. " must leave the hill in 10 seconds or they will be infected!") else say(getname(i) .. " must leave the hill in 10 seconds or they will be killed!") end--]] elseif inhill_time[hash] >= 10 then if team ~= zombie_team then makezombie(i, true) say(getname(i) .. " is now a zombie because they were in the hill too long!") else kill(i) say(getname(i) .. " has been killed because they were in the hill too long!") end inhill_time[hash] = nil elseif team ~= zombie_team then privatesay(i, "You have " .. math.abs(inhill_time[hash] - 10) .. " seconds to leave the hill!") inhill_time[hash] = inhill_time[hash] + 1 end --end elseif m_object then inhill_time[hash] = nil writebit(m_object, 0x10, 7, 0) end end end end end return 1 end function PlayerInHill(player) player = tonumber(player) local bool = false local m_player = getplayer(player) if m_player then local InHill = readbyte(inhill_addr + player, 0x0) if InHill == 1 then bool = true end end return bool end function invisCrouch(id, count) if not zombies_invisible_on_crouch and not humans_invisible_on_crouch then return 0 end for i = 0,15 do if getplayer(i) then local m_object = getobject(getplayerobjectid(i)) if m_object then local obj_crouch = readbyte(m_object, 0x2A0) if obj_crouch == 3 then local team = readbyte(getplayer(i), 0x20) if (team == zombie_team and zombies_invisible_on_crouch) or (team ~= zombie_team and humans_invisible_on_crouch) then applycamo(i, 1) end end end end end return 1 end -- Called when a player's team is being chosen as the join the server. -- It must return a value which indicates the team the player is to be put on. -- Note: this function being called doesn't guarantee that the player will be able to successfully join. function OnTeamDecision(cur_team) local dest_team = join_team if game_started then if cur_players == 0 then -- if no zombies make them human dest_team = human_team elseif cur_zombie_count > 0 and cur_human_count == 0 then dest_team = human_team end end return dest_team end -- Called when a player joins the server. -- Do not return a value. function OnPlayerJoin(player, team) -- update the player counts cur_players = cur_players + 1 -- onteamdecision isn't called for ffa gametypes if not team_play then -- initialize the destination team as the join team local dest_team = join_team -- make sure the game is started if game_started then -- if no zombies make them human if cur_players == 0 then -- change the destination team to human if cur_players 0 (doesn't matter if join_team is humanteam) dest_team = human_team -- check if there are zombies but no humans elseif cur_zombie_count > 0 and cur_human_count == 0 then -- change the destination team to human if condition met (doesn't matter if join_team is humanteam) dest_team = human_team end end -- we need to overwrite the 'team' variable being passed to onplayerjoin if dest_team == zombie_team then team = zombie_team elseif tonumber(dest_team) then team = 2 end end local thisTeamSize = 0 -- used so we don't create empty teams for rejoining players if team == zombie_team then cur_zombie_count = cur_zombie_count + 1 thisTeamSize = cur_zombie_count else cur_human_count = cur_human_count + 1 thisTeamSize = cur_human_count end alpha_zombie_count = getalphacount() local thisHash = gethash(player) local alreadyExists = false -- check if the player has joined this game previously for k,v in pairs(hash_table) do if thisHash == k then if thisTeamSize > 1 then if v ~= team then --check what team they currently are (only added for ffa gametypes) if team == zombie_team then makehuman(player, false) else makezombie(player, false) end end --privatesay(player, rejoin_message) team = v end alreadyExists = true break end end -- add team entry for this hash if alreadyExists == false then hash_table[thisHash] = team end -- make sure the game is started if game_started == true then -- check if the player is a zombie if team == zombie_team then --we don't need to update the counters since they're already on the zombieteam makezombie(player, false, true) --send them the zombie message privatesay(player, zombie_message) else -- if we're at last man, make this player a zombie if cur_last_man then --make this person a zombie (they're currently a human) makezombie(player, true) --send them the zombie message privatesay(player, zombie_message) else --make this person a human (they're currently a zombie) makehuman(player, false, true) --send them the human message privatesay(player, human_message) end end --send the player the welcome message privatesay(player, welcome_message) if gametype == "KOTH" then privatesay(player, koth_additional_welcome_msg) elseif gametype == "Slayer" then privatesay(player, slayer_additional_welcome_msg) end checkgamestate(-1) else registertimer(10000, "MsgTimer", player) end end --called when a person joins before the game is started so that the welcome message --doesn't get lost in the spam function MsgTimer(id, count, player) privatesay(player, welcome_message) if gametype == "KOTH" then privatesay(player, koth_additional_welcome_msg) elseif gametype == "Slayer" then privatesay(player, slayer_additional_welcome_msg) end return 0 end -- Called when a player the server. -- Do not return a value. function OnPlayerLeave(player, team) --check if they're a zombie if team == zombie_team then --get their object struct local m_object = getobject(getplayerobjectid(player)) if m_object then -- make sure the player is alive for i = 0,3 do -- loop through all their weapons (primary through quartenary) --get their weapon's ID local weapID = readdword(m_object, 0x2F8 + i*4) --get their weapon's struct local weap = getobject(weapID) --make sure the weapon exists if weap then --weapon needs to be destroyed registertimer(0, "destroyweaps", weapID) end end end --take one away from the current zombie count cur_zombie_count = cur_zombie_count - 1 elseif team ~= zombie_team then --take one away from the current human count cur_human_count = cur_human_count - 1 end -- if last man is leaving, reset it if cur_last_man == player then cur_last_man = nil end --minus one from current players cur_players = cur_players - 1 --check the current game state (the player that left might have been the last man or the only zombie) checkgamestate(-1) -- update team within table local thisHash = gethash(player) hash_table[thisHash] = team end -- called when a player kills another, 'killer' is the index of the killing player, 'victim' is the index of the dead player -- Do not return a value. function OnPlayerKill(killer, victim, mode) -- make sure this kill doesn't add to the score so that the game won't end prematurely if gametype == "Slayer" and killer and getplayer(killer) then writedword(slayer_globals, 0x40 + killer*4, 0) end -- make sure the game is started if game_started then -- get the victim's team local team = getteam(victim) -- i used this for debugging lol --hprintf("Victim Team: " .. tostring(team)) if mode == 0 then -- server kill elseif mode == 1 then -- fall damage -- if this is true then a person who dies from falling will be infected if infect_on_fall then --chech if the team is the human team if tonumber(team) and team ~= zombie_team then --get the victim's name local name = getname(victim) --send the victim the infected message say(name .. infected_message) --make the victim a zombie makezombie(victim, false) end end elseif mode == 2 then -- killed by guardians -- if this is true then a person who dies from the guardians will be infected if infect_on_guardians then --check if the victim's team is the human team if tonumber(team) and team ~= zombie_team then --get the victim's name local name = getname(victim) --send the victim the infected message say(name .. infected_message) --make the victim a zombie makezombie(victim, false) end end elseif mode == 3 then -- killed by vehicle elseif mode == 4 then -- killed by another player --get the killer's team local killer_team = getteam(killer) -- check to see if a zombie killed them if tonumber(killer_team) and killer_team == zombie_team and tonumber(team) and team ~= zombie_team then --get the victim's name name = getname(victim) --send the victim the infected message say(name .. infected_message) --make the victim a zombie makezombie(victim, false) --privatesay(victim, zombie_message) end --i used this for debugging --hprintf("Killer Team: " .. killer_team) elseif mode == 5 then -- betrayed --if this is true then a person who betrays will be infected if infect_on_betray then --get the killer's team local killer_team = getteam(killer) --check if the killer is a human if tonumber(killer_team) and killer_team ~= zombie_team then --get the betrayer's name name = getname(killer) --send the betrayer the infected message say(tostring(name) .. infected_message) --make the betrayer a zombie makezombie(killer, true) end end elseif mode == 6 then -- suicide --if this is true then a person who suicides will be come a zombie if infect_on_suicide then -- if they're human, make them zombies if tonumber(team) and team ~= zombie_team then --get the suicider's name name = getname(victim) --they're not going to end their life that easily say(name .. infected_message) --make the suicider a zombie makezombie(victim, false) end end end -- this next block of code gets rid of any weapons a zombie is holding if tonumber(team) and team == zombie_team then local m_player = getplayer(victim) --get the player's struct local m_object = getobject(readdword(m_player, 0x34)) -- get the player's object struct --there's an off chance that the player might be dead (phasor bug) can't hurt to add this check if m_object then for i = 0,3 do -- loop through the player's weapons (primary to quartenary) local weapID = readdword(m_object, 0x2F8 + i*4) local weap = getobject(weapID) --make sure the weapon exists if weap then --destroy their weapons registertimer(0, "destroyweaps", weapID) end end end end end end --I made this function because there's a bug with destroyobject in phasor version 058X --basically all it does is move the objects under the map lol function destroyweaps(id, count, m_weaponId) local m_weapon = getobject(m_weaponId) if m_weapon then writefloat(m_weapon, 0x5C, readfloat(m_weapon, 0x5C) - 1000) end return 0 end -- called when a player gets a double kill, killing spree etc -- see Phasor documentation for multiplier values function OnKillMultiplier(player, multiplier) end -- Called when a player s (after object is created, before players are notified) -- Do not return a value function OnPlayerSpawn(player, m_objectId) --get the player's team local team = getteam(player) --check if the player is a zombie if team == zombie_team then --get the player's object ID local m_objectId = getplayerobjectid(player) --get the player's object struct local m_object = getobject(m_objectId) --make sure the player is alive (off chance that there's a glitch in phasor) if m_object then -- set nade counts writebyte(m_object, 0x31E, zombie_frag_count) writebyte(m_object, 0x31F, zombie_plasma_count) -- set the ammo local clipcount = alphazombie_clip_count local ammocount = alphazombie_ammo_count local batterycount = alphazombie_battery_count -- set ammo counts for zombies when others have been infected if cur_zombie_count > alpha_zombie_count then clipcount = zombie_clip_count ammocount = zombie_ammo_count batterycount = zombie_battery_count else -- set alpha nades writebyte(m_object, 0x31E, alphazombie_frag_count) writebyte(m_object, 0x31F, alphazombie_plasma_count) end --check if the starting equipment is generic if starting_equipment == "Generic" then -- initialize this boolean as false local bool = false for i=0,3 do --loop through the player's weapons (primary through quartenary) --get the player's weapon's ID local m_weaponId = readdword(m_object, 0x2F8 + i*4) --check if the zombie weapon is an oddball or a flag if oddball_or_flag then --make sure the boolean is still false and the player's weapon exists. if bool == false and getobject(m_weaponId) then --get the weapon's tagname local tagName = getobjecttag(m_weaponId) --make sure the weapon's tagname is the zombie weapon (oddball/flag) if tagName == oddball_or_flag then --store the weapon's ID in the flagball_weap table flagball_weap[player] = m_weaponId --set bool to true bool = true end end --zombie weapon is not a flag or a ball elseif m_weaponId ~= 0xFFFFFFFF then --get the weapon's struct local m_weapon = getobject(m_weaponId) --make sure the weapon exists if m_weapon then -- set the ammo writeword(m_weapon, 0x2B6, ammocount) writeword(m_weapon, 0x2B8, clipcount) -- set the battery (math.abs is absolute value meaning it takes the opposite of battery count (meaning 0 needs to be 1 and 1 needs to be 0)) writefloat(m_weapon, 0x240, math.abs(batterycount - 1)) -- force it to sync updateammo(m_weaponId) end end end -- check if we still need to assign leftover weapons to zombies (tertiary and quartenary weapons) if (zombie_weapon[3] and zombie_weapon[3] ~= "") then -- make sure the script user isn't retarded --assign the leftover weapons to the player registertimer(0, "AssignLeftoverZombieWeapons", player, clipcount, ammocount, batterycount) end elseif starting_equipment == "Custom" then --assign the correct weapons to the player registertimer(0, "AssignZombieWeapons", player, clipcount, ammocount, batterycount) end end end --check if the gametype is slayer if gametype == "Slayer" then local m_player = getplayer(player) --check if we're at the last_man if cur_last_man then --write the navpoint to the current last man writeword(m_player, 0x88, cur_last_man) else --there is no last man so put a nav above this player's head writeword(m_player, 0x88, player) end end end --basically this timer assigns the tertiary and quarternary weapons to zombies if specified at the top --this is needed since onweaponassignment isn't called for tertiary and quartenary weapons function AssignLeftoverZombieWeapons(id, count, player, clipcount, ammocount, batterycount) local m_objectId = getplayerobjectid(player) if m_objectId ~= 0xFFFFFFFF then local m_object = getobject(m_objectId) if m_object then local m_weaponId = createobject("weap", zombie_weapon[3], 0, 0, false, 5, 2, 2) if m_weaponId ~= 0xFFFFFFFF then local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon, 0x2B6, ammocount) writeword(m_weapon, 0x2B8, clipcount) writefloat(m_weapon, 0x240, math.abs(batterycount - 1)) -- force it to sync updateammo(m_weaponId) end end --make sure the script user isn't retarded so we don't get errors if zombie_weapon[4] and zombie_weapon[4] ~= "" then --create the quarternary weapon local m_weaponId = createobject("weap", zombie_weapon[4], 0, 0, false, 5, 5, 2) --make sure createobject didn't screw up if m_weaponId ~= 0xFFFFFFFF then --assign the weapon to the player assignweapon(player, m_weaponId) --make sure we can safely set the ammo local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon, 0x2B6, ammocount) writeword(m_weapon, 0x2B8, clipcount) writefloat(m_weapon, 0x240, math.abs(batterycount - 1)) -- force it to sync updateammo(m_weaponId) end end end end end return 0 end --this function is called when a gametype is 'custom' --this function will delete the player's weapons and reassign the weapon's specified at the top function AssignZombieWeapons(id, count, player, clipcount, ammocount, batterycount) local m_objectId = getplayerobjectid(player) if m_objectId ~= 0xFFFFFFFF then local m_object = getobject(m_objectId) if m_object then --count is increased everytime the timer is called if count == 1 then for i = 0,3 do -- this is used to remove any weapons they already have local m_weaponId = readdword(m_object, 0x2F8 + i*4) if getobject(m_weaponId) then destroyobject(m_weaponId) end end end local i = count if zombie_weapon and zombie_weapon[i] and zombie_weapon[i] ~= "" then local m_weaponId = createobject("weap", zombie_weapon[i], 0, 0, false, 1, 1, 1) if m_weaponId ~= 0xFFFFFFFF then assignweapon(player, m_weaponId) if oddball_or_flag then flagball_weap[player] = m_weaponId else local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon, 0x2B6, ammocount) writeword(m_weapon, 0x2B8, clipcount) writefloat(m_weapon, 0x240, 1) -- force it to sync updateammo(m_weaponId) end end end end if count < 4 then return 1 else return 0 end end end return 0 end -- Called after clients have been notified of a player spawn -- Do not return a value function OnPlayerSpawnEnd(player, m_objectId) end -- Called when a player is attempting to change their team. -- A value must be returned. The return value indicates whether or not the player is allowed the change team. -- Notes: If relevant is 1 the return value is considered, if it's 0 then the return value is ignored. function OnTeamChange(relevant, player, team, dest_team) if relevant == 1 or relevant == true then if not allow_change then privatesay(player, blockteamchange_message) elseif allow_change and dest_team == zombie_team then -- this is so memory is updated for processing -- when relevant is 0 OnTeamChange is called once the changes -- have been committed changeteam(player, 1) end -- we don't let people change team return 0 elseif (relevant == 0 or relevant == false) and dest_team ~= team then -- we can't stop the person changing teams, bein done by an admin -- update team counts if dest_team == zombie_team then cur_human_count = cur_human_count - 1 cur_zombie_count = cur_zombie_count + 1 elseif dest_team ~= zombie_team then cur_human_count = cur_human_count + 1 cur_zombie_count = cur_zombie_count - 1 end -- they're allowed to change if the timer is active, if it is disable it if allow_change == true and dest_team == zombie_team then allow_change = false -- remove change timer removetimer(player_change_timer) player_change_timer = 0 say(timer_team_change_msg) end -- check if the game has started yet if game_started == true then -- set attributes if dest_team == zombie_team then makezombie(player, false) elseif dest_team ~= zombie_team then makehuman(player, false) end checkgamestate(player) end -- update team withf local thisHash = gethash(player) hash_table[thisHash] = dest_team end return 1 end --i made code in here to make the oddball/flag impossible to be dropped except that was a long time ago and i have no idea how it works, sorry :( --there's a bunch of redundant code in here, i wouldn't touch it if i were you. -- this function is also used to continually set the scores function OnClientUpdate(player, m_objectId) local m_player = getplayer(player) local m_object = getobject(m_objectId) local hash = gethash(player) --if gametype == "CTF" then writebit(ctf_globals, 0x1C, human_team, 0) end if m_object and game_started == true then local team = readbyte(m_player, 0x20) if team == zombie_team and oddball_or_flag then local shooting = readbit(m_object, 0x209, 4) local nading2 = readbit(m_object, 0x209, 2) local nading = readbit(m_object, 0x209, 3) if shooting == 1 or nading == 1 then --[[local weapID = readdword(m_object, 0x2FC) local weap = getobject(weapID) say("IS SHOOTING") if weap then--]] weapID = flagball_weap[player] local m_player = getplayer(player) if m_player then if weapID == nil then flagball_weap[player] = createobject("weap", oddball_or_flag, 0, 0, false, 5, 5, 2) assignweapon(player, flagball_weap[player]) else if getobject(weapID) then if IsFlagOrBall(weapID) then assignweapon(player, weapID) else flagball_weap[player] = createobject("weap", oddball_or_flag, 0, 0, false, 5, 5, 2) assignweapon(player, flagball_weap[player]) end else flagball_weap[player] = createobject("weap", oddball_or_flag, 0, 0, false, 5, 5, 2) assignweapon(player, flagball_weap[player]) end end end --end end end -- this block of code sets the player's score according to what it should be. if tonumber(human_time[hash]) then if gametype == "KOTH" then local hill_time = readword(m_player, 0xC4) if tonumber(hill_time) then writewordsigned(m_player, 0xC4, tonumber(human_time[hash])*30) end elseif gametype == "CTF" then local player_score = readdword(m_player, 0xC8) if tonumber(player_score) then writedwordsigned(m_player, 0xC8, human_time[hash]) end elseif gametype == "Slayer" then writedwordsigned(slayer_globals, 0x40 + player * 4, human_time[hash]) end else human_time[hash] = 0 end end --continually write 0 to these addresses if gametype == "KOTH" then writedword(team_koth_score_array, 0x0, 0) writedword(team_koth_score_array, 0x4, 0) elseif gametype == "CTF" then writedword(ctf_globals, 0x10, 0) writedword(ctf_globals, 0x14, 0) elseif gametype == "Slayer" then writedword(slayer_globals, 0x0, 0) writedword(slayer_globals, 0x4, 0) end --this makes sure that people won't camp in unreachable places. local x,y,z = getobjectcoords(m_objectId) local team = getteam(player) if map == "damnation" and team ~= zombie_team then if object_in_sphere(m_objectId, 1.99, 9.03, 7.82, 5) then kill(player) privatesay(player, "Do not camp in unreachable spots!") elseif object_in_sphere(m_objectId, 11.4, 11.21, 10.51, 5) then kill(player) privatesay(player, "Do not camp in unreachable spots!") end elseif map == "icefields" and team ~= zombie_team then if object_in_sphere(m_objectId, -31.27, 42.44, 11.48, 5) then kill(player) privatesay(player, "Do not camp in unreachable spots!") elseif object_in_sphere(m_objectId, -71.29, 70.83, 6.67, 10) then kill(player) privatesay(player, "Do not camp in unreachable spots!") elseif object_in_sphere(m_objectId, -17.28, 19.63, 11.55, 5) then kill(player) privatesay(player, "Do not camp in unreachable spots!") end end end function writewordsigned(address, offset, value) if value and value > 0x7FFF then local max = 0xFFFF local difference = max - value value = -1 - difference end writeword(address, offset, value) end function writedwordsigned(address, offset, value) if value and value > 0x7FFFFFFF then local max = 0xFFFFFFFF local difference = max - value value = -1 - difference end writedword(address, offset, value) end --called to check if an object is in a virtual sphere --i use this to check if a person is in a unreachable spot. function object_in_sphere(m_objectId, X, Y, Z, R) local Pass = false if getobject(m_objectId) then local x,y,z = getobjectcoords(m_objectId) if (X - x)^2 + (Y - y)^2 + (Z - z)^2 <= R then Pass = true end end return Pass end --checks if the object is a flag or a ball function IsFlagOrBall(weapID) for i = 1,#flags_balls_table do if flags_balls_table[i] == weapID then return true end end end -- Called when a player interacts with an object -- It can be called while attempting to pick the object up -- It is also called when standing above an object so can be called various times quickly function OnObjectInteraction(player, m_ObjectId, tagType, tagName) local response = 1 if game_started == true then -- we don't need to stop people from taking the flag -- since the flag is moved under the map if tagType == "weap" then if tagName == oddball_or_flag then local team = getteam(player) if team == zombie_team then return 1 end return 0 end end if response == 1 then local team = getteam(player) if team == zombie_team then -- we want to stop zombies picking up weapons if tagType == "weap" then response = 0 elseif tagType == "eqip" then if tagName == "weapons\\frag grenade\\frag grenade" or tagName == "weapons\\plasma grenade\\plasma grenade" then response = 0 -- don't let them pick the nades elseif tagName == "powerups\\active camouflage" then -- check if the picking player is already invisible local m_player = getplayer(player) if m_player then local m_playerObjId = readdword(m_player, 0x34) local m_object = getobject(m_playerObjId) if m_object then local camoFlag = readdword(m_object, 0x204) if camoFlag ~= 0x51 then -- check if zombies are to be made invisible local doInvis = getrandomnumber(1, 10) if doInvis > 5 then -- make the whole zombie team invis for 20 seconds for x = 0,15 do local team = getteam(x) if team == zombie_team and x ~= player then --hprintf("applying camo to player " .. x) applycamo(x, 30.00) end end say(zombieinvis_message) end end end end end end end end end return response end -- Called when a player attempts to reload their weapon. -- A value must be returned. The return value indicates whether or not the player is allowed to reload. -- Notes: If player is -1 then the weapon being reload wasn't located (it could be a vehicle's weapon) function OnWeaponReload(player, weapon) return 1 end -- Called when a player attempts to enter a vehicle. -- A value must be returned. The return value indicates whether or not the player is allowed to enter. function OnVehicleEntry(relevant, player, vehicleId, vehicle_tag, seat) local response = 0 if game_started and relevant == 1 then local team = getteam(player) if (team == zombie_team and zombies_allowed_in_vehis) or (tonumber(team) and team ~= zombie_team and humans_allowed_in_vehis) then response = 1 end end return response end function OnVehicleEject(player, forceEject) return 1 end -- Called when damage is being done to an object. -- This doesn't always need to be a player. -- Do not return a value function OnDamageLookup(receiving_obj, causing_obj, tagdata, tagname) -- Resolve the object ids into player ids -- Remember, the damage doesn't always need to be done by a player. local receiver = objecttoplayer(receiving_obj) local causer = objecttoplayer(causing_obj) -- We want to amplify human damage, so make sure the causer is human if causer then local c_team = getteam(causer) -- Make sure the team was found if tonumber(c_team) then -- Check if it's a human causing the damage if c_team ~= zombie_team then -- It's human damage, read the current damage the weapon has local min_dmg = readfloat(tagdata, 0x1D0) local max_dmg_min = readfloat(tagdata, 0x1D4) local max_dmg_max = readfloat(tagdata, 0x1D8) -- This is used to increase human damage (for last man) local modifier = 1.0 -- Check if we're up to last man if cur_last_man then -- Change the damage modifier to the last man's modifier = lastman_dmgmodifier end -- Change the damage that will be done writefloat(tagdata, 0x1D0, min_dmg * 1.75 * modifier) writefloat(tagdata, 0x1D4, max_dmg_min * 1.75 * modifier) writefloat(tagdata, 0x1D8, max_dmg_max * 1.75 * modifier) -- It's a zombie causing the damage elseif c_team == zombie_team then -- check if it is melee damage, if so increase it to instant kill local found = string.find(tagname, "melee", -5) local r_team = getteam(receiver) -- We only want to increase zombie's melee damage if found then -- make melee instant kill writefloat(tagdata, 0x1D0, 500) writefloat(tagdata, 0x1D4, 500) writefloat(tagdata, 0x1D8, 500) end --check if a person is trying to damage their own team (ffa only, basically friendly fire is on to reduce confusion) if not team_play and c_team == r_team and causer ~= receiver then writefloat(tagdata, 0x1D0, 0) writefloat(tagdata, 0x1D4, 0) writefloat(tagdata, 0x1D8, 0) privatesay(causer, "Do not hit your own team.") end end end end end -- Called when a player is being assigned a weapon (usually when they spawn) -- A value must be returned. The return value is the id of the weapon they're to spawn with. Return zero if the weapon shouldn't change. -- Notes: This is called for all weapon spawns the player has -- This is also called with player 255 when vehicles are being assigned weapons. -- This is only considered if in gametype, the weapon set is 'Custom' if not this has no effect. function OnWeaponAssignment(player, object, count, tag) if starting_equipment == "Custom" then return 0 end -- this function does nothing if starting equipment is Custom local actualWeapon = 0 local team = getteam(player) if team == zombie_team then if count == 0 and zombie_weapon[1] ~= "" and zombie_weapon[1] then actualWeapon = lookuptag("weap", zombie_weapon[1]) elseif count == 1 and zombie_weapon[2] ~= "" and zombie_weapon[2] then actualWeapon = lookuptag("weap", zombie_weapon[2]) end end if not actualWeapon then actualWeapon = 0 end return actualWeapon end function readtagname(address) local char_table = {} local i = 0 local string = "" while readbyte(address, i) ~= 0 do table.insert(char_table, string.char(readbyte(address, i))) i = i + 1 end for k,v in pairs(char_table) do string = string .. v end return string end -- Called when an object is created -- Do not return a value. function OnObjectCreation(m_objectId, player_owner, tag) if gametype == "CTF" then -- move the ctf flags under the map if tag == "weapons\\flag\\flag" then local red_scoreflag_objId = readdword(ctf_globals, 0x8) local blue_scoreflag_objId = readdword(ctf_globals, 0x12) if m_objectId == red_scoreflag_objId or m_objectId == blue_scoreflag_objId then registertimer(0, "PutUnderMap", m_objectId) return -- return so it won't add this weapon to the flags_balls_table end end end if tag == oddball_or_flag then table.insert(flags_balls_table, m_objectId) end end --i basically use this to put the object under the map, i could use destroyweaps like i do above but w/e function PutUnderMap(id, count, m_objectId) local m_object = getobject(m_objectId) if m_object then local x,y,z = getobjectcoords(m_objectId) movobjcoords(m_objectId, x, y, z - 20) end return 0 end -- The below functions are used internally within the Lua script function NewGameTimer(id, count) if count == 5 then say("The game is starting...") if cur_players ~= 0 then local newgame_zombie_count = 0 -- by default make all players human for x=0,15 do local thisTeam = getteam(x) local hash = gethash(x) if thisTeam then if thisTeam == zombie_team then changeteam(x, 0) end human_time[hash] = 0 end end local possible_count = cur_players -- make players zombie until the count has been met local finalZombies = 0 if zombie_count >= 1 then finalZombies = zombie_count else finalZombies = round((possible_count * zombie_count) + 0.5) end -- make last man zombie local last_man_index = -1 -- check if the last man is to be made a zombie -- if so find who was last man if last_man_next_zombie == true and cur_players > 1 then -- loop through all hashes and check if any match the last man for i=0,15 do if getplayer(i) then local hash = gethash(i) if last_man_hash == hash then -- make them a zombie and save their info makezombie(i, true) newgame_zombie_count = 1 last_man_index = i break end end end end -- reset last man last_man_hash = 0 --hprintf("Expecting " .. finalZombies .. " zombies. Cur players " .. cur_players .. " possibles " .. possible_count) if finalZombies == cur_players then -- if 0 players they will be human finalZombies = finalZombies - 1 elseif finalZombies > possible_count then -- fix the count finalZombies = possible_count elseif max_zombie_count and finalZombies > max_zombie_count then -- cap the zombie count finalZombies = max_zombie_count elseif finalZombies < 0 then finalZombies = 0 end -- set counters such that changeteam wont end the game cur_zombie_count = 16 cur_human_count = 16 --hprintf("Expecting " .. finalZombies .. " zombies. Cur players " .. cur_players .. " possibles " .. possible_count) -- loop through the players, randomly selecting ones to become -- zombies while (newgame_zombie_count < finalZombies) do -- randomly choose a player local newzomb = ChooseRandomPlayer(zombie_team) if newzomb == nil then break elseif newzomb ~= last_man_index then makezombie(newzomb, true) newgame_zombie_count = newgame_zombie_count + 1 end end -- fix the team counters cur_zombie_count = newgame_zombie_count cur_human_count = cur_players - finalZombies -- reset the map svcmd("sv_map_reset") -- loop through and tell players which team they're on for i=0,15 do local pteam = getteam(i) if pteam then -- check if they're a zombie if pteam == zombie_team then privatesay(i, zombie_message) else if not team_play then makehuman(i) end privatesay(i, human_message) end end end end game_started = true return 0 -- remove timer else say("The game will start in " .. 10 - 2*count .. " seconds.") return 1 -- keep timer end end function PlayerChangeTimer(id, count) if count ~= 10 then local zombsize = cur_zombie_count if allow_change == false or zombsize > 0 then allow_change = false if team_play then say("Thank you, the game can continue.") end return 0 end say("In " .. 10 - count .. " seconds a player will be forced to become a zombie.") return 1 else -- timer up, force team change allow_change = false -- pick a human and make them zombie. local newZomb = ChooseRandomPlayer(zombie_team) if newZomb then makezombie(newZomb, true) privatesay(player, zombie_message) end return 0 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 = table.getn(t) local r = getrandomnumber(1, tableCount+1) return t[r] else return nil end end function RemoveLastmanProtection(id, count, m_object) writebit(m_object, 0x10, 7, 0) return 0 end -- there are no zombies left function noZombiesLeft() allow_change = true say(nozombiesleftmessage) player_change_timer = registertimer(1000, "PlayerChangeTimer") end --this function writes navpoints to zombies which will point to the last man function WriteNavsToZombies() for i = 0,15 do local team = getteam(i) if team == zombie_team then local m_player = getplayer(i) if m_player then local slayer_target = readword(m_player, 0x88) if slayer_target < 16 and slayer_target > -1 then writeword(m_player, 0x88, cur_last_man) end end end end end -- called when a last man exists function onlastman() -- lookup the last man for x=0,15 do local team = getteam(x) if team ~= zombie_team and team then cur_last_man = x if gametype == "Slayer" then WriteNavsToZombies(x) end -- give the last man speed and extra ammo setspeed(x, lastman_speed) -- find the last man's weapons local m_player = getplayer(x) if m_player then local m_ObjId = readdword(m_player, 0x34) -- find the player's object local m_object = getobject(m_ObjId) if m_object then if lastman_invulnerable and lastman_invulnerable > 0 then -- setup the invulnerable timer writebit(m_object, 0x10, 7, 1) registertimer(lastman_invulnerable * 1000, "RemoveLastmanProtection", m_object) end -- give all weapons 600 ammo for i=0,3 do local m_weaponId = readdword(m_object, 0x2F8 + (i*4)) if m_weaponId ~= 0xffffffff then -- get the weapons memory address local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon, 0x2B6, 600) end end end end end end end if cur_last_man then local lastman_name = getname(cur_last_man) local msg = string.format(lastman_message, tostring(lastman_name), lastman_invistime) say(msg) applycamo(cur_last_man, lastman_invistime) end end -- checks the game state, for last man, all zombies etc -- called onteamchange, onplayerjoin, onplayerleave, onffateamchange, and onscriptload function checkgamestate(player) -- check if the game has started yet if game_started == true then local zombie_count = cur_zombie_count local human_count = cur_human_count --hprintf("zombie count " .. tostring(zombie_count)) --hprintf("human count " .. tostring(human_count)) -- if no humans, but there are zombies, end the game if human_count == 0 and zombie_count > 0 then all_players_zombies(player) elseif human_count > 1 and zombie_count == 0 then noZombiesLeft() elseif human_count == 1 and zombie_count > 0 and not cur_last_man then onlastman() elseif cur_last_man and zombie_count == 0 then makehuman(cur_last_man, false) cur_last_man = nil elseif cur_last_man and human_count > 1 then if gametype == "Slayer" then takenavsaway(cur_last_man) end makehuman(cur_last_man, false) cur_last_man = nil end end end --called when the lastman no longer exists function takenavsaway(lastman) for i = 0,15 do local m_player = getplayer(i) if m_player then writeword(m_player, 0x88, i) end end end -- called when all players are zombies (no shit) function all_players_zombies(player) -- if there is a last man, store their hash if player ~= -1 then last_man_hash = gethash(player) -- write the hash to file local file = io.open("lasthash_" .. processid .. ".tmp", "w") if (file ~= nil) then file:write(tostring(last_man_hash)) file:close() end end -- move onto the next map svcmd("sv_map_next") end --called when a player needs to be made a zombie function makezombie(player, forcekill, updatecounters) -- change the player's speed setspeed(player, zombie_speed) local team = getteam(player) if team ~= zombie_team then if team_play then changeteam(player, forcekill) else changeteam(player, forcekill, nil, updatecounters) end end end --called when a player needs to be a human function makehuman(player, forcekill, updatecounters) -- change the player's speed setspeed(player, human_speed) local team = getteam(player) if team == zombie_team then if team_play then changeteam(player, forcekill) else changeteam(player, forcekill, updatecounters) end end end --gets the number of alpha zombies function getalphacount() -- recalculate how many "alpha" zombies there are if zombie_count < 1 then alpha_zombie_count = round((cur_players * zombie_count) + 0.5) else alpha_zombie_count = zombie_count end if alpha_zombie_count > max_zombie_count then alpha_zombie_count = max_zombie_count end return alpha_zombie_count end --rounds the number function round(num) under = math.floor(num) upper = math.floor(num) + 1 underV = -(under - num) upperV = upper - num if (upperV > underV) then return under else return upper end end