Advertisement
th3w1zard1

PhasorSappCompatibility

Apr 3rd, 2015
517
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 72.94 KB | None | 0 0
  1. -- Sapp and Phasor Compatibility Module
  2. -- Created by Wizard
  3. -- Add this line to the end of your script to use this module:
  4. -- _G = require"PhasorSappCompatibility"
  5.  
  6. local sapp_version = "1.7.0.0"
  7. local phasor_version = 200
  8.  
  9. _SERVERAPP = cb and say_all and "Sapp" or getrandomnumber and isinvehicle and "Phasor" --or error("Dafuq? What server app are you using?") -- easiest way
  10. _GAME = _SERVERAPP == "Sapp" and halo_type or readbyte and readbyte(0x630E78) == 7 and "PC" or "CE" -- skillz
  11. local _G = _G -- so the main script can't change this.
  12.  
  13. -- Localized functions.
  14. local random, abs = math.random, abs
  15. local type = type
  16. local clock, time = os.clock, os.time
  17. local concat = table.concat
  18. local gmatch, char, byte, match, find, format, lower, sub, gsub = string.gmatch, string.char, string.byte, string.match, string.find, string.format, string.lower, string.sub, string.gsub
  19. local orig_xpcall = xpcall
  20. local real_register_callback = register_callback
  21.  
  22. -- Lua Version Compatibility Definitions.
  23. bit = not bit32 and require"bit" or bit32
  24. bit32 = bit32 or bit
  25. getfenv = getfenv or function(f)
  26.     f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
  27.     local name, val
  28.     local up = 0
  29.     repeat
  30.         up = up + 1
  31.         name, val = debug.getupvalue(f, up)
  32.     until name == '_ENV' or name == nil
  33.     return val
  34. end
  35. math.atan = math.atan or math.atan2
  36. math.atan2 = math.atan2 or math.atan
  37. math.ldexp = math.ldexp or function(x, exp) return x * 2.0^exp end
  38. math.log10 = math.log10 or function(num) return math.log(num, 10) end
  39. package.loaders = package.loaders or package.searchers
  40. package.searchers = package.loaders
  41. load = load or loadstring
  42. loadstring = loadstring or load
  43. table.maxn = table.maxn or (
  44.     function(t)
  45.         local maxval = 0
  46.         for key,value in next,t do
  47.             if type(key) == "number" and key > maxval then
  48.                 maxval = key
  49.             end
  50.         end
  51.         return maxval
  52.     end
  53. )
  54. setfenv = setfenv or function(f, t)
  55.     f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
  56.     local name
  57.     local up = 0
  58.     repeat
  59.         up = up + 1
  60.         name = debug.getupvalue(f, up)
  61.     until name == '_ENV' or name == nil
  62.     if name then
  63.         debug.upvaluejoin(f, up, function() return name end, 1) -- use unique upvalue
  64.         debug.setupvalue (f, up, t)
  65.     end
  66. end
  67. table.getn = table.getn or function(t) return rawlen(t) end
  68. table.unpack = table.unpack or unpack
  69. unpack = unpack or table.unpack
  70. xpcall = _SERVERAPP == "Sapp" and function(f, msgh, ...) local args = {...} return orig_xpcall(function() f(unpack(args)) end, msgh) end or xpcall
  71.  
  72. local function WriteLog(filename, logStr)
  73.     local file = assert(io.open(filename, "a"))
  74.     file:write(string.format("%s\t%s\n", os.date "%Y/%m/%d %H:%M:%S", logStr))
  75.     file:close()
  76. end
  77.  
  78. local function ypcall(func, ...)
  79.     if type(func) ~= "function" then
  80.         return nil
  81.     end
  82.    
  83.     local success,result1,result2 = xpcall(func, function(err) print(debug.traceback(err)) end, ...)
  84.     if success == false and type(result1) == "string" then
  85.         local err = "Error in " .. result1
  86.         WriteLog(getprofilepath() .. "\\logs\\ScriptLogs.log", err)
  87.         hprintf(err)
  88.         pcall(OnError, result1)
  89.     end
  90.     return result1, result2
  91. end
  92.  
  93. -- Private variables.
  94. local prevent_join = {}
  95. local player_scores = {}
  96. local timers = {}
  97. local svcmd_echo
  98. local dont_doublecall_onvehicleeject
  99. local dont_doublecall_onvehicleentry
  100. local safe_read_val = false
  101. local safe_write_val = false
  102.  
  103. cb = cb or {
  104.     EVENT_TICK = 1,
  105.     EVENT_ALIVE = 2,
  106.     EVENT_AREA_ENTER = 3,
  107.     EVENT_AREA_EXIT = 4,
  108.     EVENT_PRESPAWN = 5,
  109.     EVENT_SPAWN = 6,
  110.     EVENT_KILL = 7,
  111.     EVENT_DIE = 8,
  112.     EVENT_SNAP = 9,
  113.     EVENT_WARP = 10,
  114.     EVENT_WEAPON_PICKUP = 11,
  115.     EVENT_WEAPON_DROP = 12,
  116.     EVENT_VEHICLE_ENTER = 13,
  117.     EVENT_VEHICLE_EXIT = 14,
  118.     EVENT_BETRAY = 15,
  119.     EVENT_SUICIDE = 16,
  120.     EVENT_SCORE = 17,
  121.     EVENT_TEAM_SWITCH = 18,
  122.     EVENT_JOIN = 19,
  123.     EVENT_LEAVE = 20,
  124.     EVENT_CAMP = 21,
  125.     EVENT_LOGIN = 22,
  126.     EVENT_GAME_START = 23,
  127.     EVENT_GAME_END = 24,
  128.     EVENT_CHAT = 25,
  129.     EVENT_COMMAND = 26,
  130.     EVENT_ECHO = 27,
  131.     EVENT_OBJECT_SPAWN = 28,
  132. }
  133.  
  134. local phasorEvents = {
  135.     OnScriptLoad = OnScriptLoad or true,
  136.     OnNewGame = OnNewGame or true,
  137.     OnGameEnd = OnGameEnd or true,
  138.     OnServerChat = OnServerChat or true,
  139.     OnServerCommandAttempt = OnServerCommandAttempt or true,
  140.     OnServerCommand = OnServerCommand or true,
  141.     OnNameRequest = OnNameRequest or true,
  142.     OnBanCheck = OnBanCheck or true,
  143.     OnPlayerJoin = OnPlayerJoin or true,
  144.     OnPlayerLeave = OnPlayerLeave or true,
  145.     OnPlayerKill = OnPlayerKill or true,
  146.     OnKillMultiplier = OnKillMultiplier or true,
  147.     OnPlayerSpawn = OnPlayerSpawn or true,
  148.     OnPlayerSpawnEnd = OnPlayerSpawnEnd or true,
  149.     OnWeaponAssignment = OnWeaponAssignment or true,
  150.     OnWeaponReload = OnWeaponReload or true,
  151.     OnObjectCreationAttempt = OnObjectCreationAttempt or true,
  152.     OnObjectCreation = OnObjectCreation or true,
  153.     OnObjectInteraction = OnObjectInteraction or true,
  154.     OnTeamDecision = OnTeamDecision or true,
  155.     OnTeamChange = OnTeamChange or true,
  156.     OnDamageLookup = OnDamageLookup or true,
  157.     OnDamageApplication = OnDamageApplication or true,
  158.     OnVehicleEntry = OnVehicleEntry or true,
  159.     OnVehicleEject = OnVehicleEject or true,
  160. }
  161.  
  162. local events
  163. events = {
  164.    
  165.     [cb.EVENT_TICK] = {
  166.         register = function(funcname)
  167.             if _SERVERAPP == "Phasor" then
  168.                 -- This won't work if you want to literally use it for like checking if someone is crouched (actually, it might depending on how Phasor timers work), but should imitate the behavior well enough
  169.                 local tick_id = registertimer(33, "__tick_event")
  170.                 function __tick_event(id)
  171.                     if tick_id ~= id then return false end
  172.                     ypcall(_G[funcname])
  173.                     return true
  174.                 end
  175.             else
  176.                 function __clientupdate_event()
  177.                     local playerId, playerObjId, m_playerObj, weaponObjId, m_weaponObj, weapstate
  178.                     for playerIndex = 1,16 do
  179.                         playerId = to_real_index(playerIndex)
  180.                         if playerId == -1 then goto continue end
  181.                        
  182.                         playerObjId = getplayerobjectid(playerId)
  183.                         m_playerObj = get_object_memory(playerObjId)
  184.                         if m_playerObj == 0 then goto continue end
  185.                        
  186.                         if OnClientUpdate then OnClientUpdate(playerId, playerObjId) end
  187.                         if not OnWeaponReload then goto continue end
  188.                        
  189.                         weaponObjId = read_dword(m_playerObj + 0x118)
  190.                         m_weaponObj = get_object_memory(weaponObjId)
  191.                         if m_weaponObj == 0 then goto continue end
  192.                        
  193.                         weapstate = read_byte(m_weaponObj + 0x238)
  194.                         if weapstate == 5 or weapstate == 6 then
  195.                             OnWeaponReload(playerId, weaponObjId) -- Not possible to block this yet.
  196.                         end
  197.                        
  198.                         ::continue::
  199.                     end
  200.                     ypcall(_G[funcname])
  201.                 end
  202.                 real_register_callback(cb.EVENT_TICK, "__clientupdate_event")
  203.             end
  204.         end
  205.     },
  206.     [cb.EVENT_ALIVE] = {
  207.         register = function(funcname)
  208.             if _SERVERAPP == "Phasor" then
  209.                 local __alive_id = registertimer(1000, "__alivetimer")
  210.                 function __alivetimer(id)
  211.                     if __alive_id ~= id then return false end
  212.                     for playerId = 0,15 do
  213.                         if getplayer(playerId) and getobject(getplayerobjectid(playerId)) then
  214.                             ypcall(_G[funcname], playerIndex)
  215.                         end
  216.                     end
  217.                     return true
  218.                 end
  219.             else
  220.                 real_register_callback(cb.EVENT_ALIVE, funcname)
  221.             end
  222.         end,
  223.     },
  224.     [cb.EVENT_AREA_ENTER] = {
  225.         register = function(funcname)
  226.             if _SERVERAPP == "Phasor" then
  227.                 events[cb.EVENT_AREA_ENTER][1] = funcname
  228.             else
  229.                 real_register_callback(cb.EVENT_AREA_ENTER, funcname)
  230.             end
  231.         end
  232.     },
  233.     [cb.EVENT_AREA_EXIT] = {
  234.         register = function(funcname)
  235.             if _SERVERAPP == "Phasor" then
  236.                 events[cb.EVENT_AREA_EXIT][1] = funcname
  237.             else
  238.                 real_register_callback(cb.EVENT_AREA_EXIT, funcname)
  239.             end
  240.         end
  241.     },
  242.     [cb.EVENT_PRESPAWN] = {
  243.         register = function(funcname)
  244.             if _SERVERAPP == "Phasor" then
  245.                 function OnPlayerSpawn(playerId, playerObjId)
  246.                     playerObjId = playerObjId or getplayerobjectid(playerId)
  247.                     if __orig_spawn_event then __orig_spawn_event(playerId, playerObjId) end
  248.                     local playerIndex = resolveplayer(playerId)
  249.                     if events[cb.EVENT_WEAPON_PICKUP][1] then
  250.                         local m_playerObj = getobject(playerObjId)
  251.                         for slot = 0,3 do
  252.                             if getobject(readdword(m_playerObj + 0x2F8+slot*4)) then
  253.                                 ypcall(_G[events[cb.EVENT_WEAPON_PICKUP][1]], playerIndex, slot+1, 1)
  254.                             end
  255.                         end
  256.                     end
  257.                     ypcall(_G[funcname], playerIndex)
  258.                 end
  259.             else
  260.                 function __onspawn_event(playerIndex)
  261.                     if prevent_join[playerIndex] then
  262.                         return nil
  263.                     end
  264.                     local playerId = to_real_index(playerIndex)
  265.                     local playerObjId = getplayerobjectid(playerId)
  266.                     ypcall(phasorEvents.OnPlayerSpawn, playerId, playerObjId)
  267.                     if phasorEvents.OnWeaponAssignment then
  268.                         local m_playerObj = get_object_memory(playerObjId)
  269.                         local m_weaponObj, mapId, result, weaponObjId
  270.                         for slot = 0,3 do
  271.                             weaponObjId = read_dword(m_playerObj + 0x2F8 + slot*4)
  272.                             m_weaponObj = get_object_memory(weaponObjId)
  273.                             mapId = m_weaponObj and read_dword(m_weaponObj)
  274.                             if mapId then
  275.                                 result = ypcall(phasorEvents.OnWeaponAssignment, playerId, playerObjId, slot, mapId)
  276.                                 if result == false then
  277.                                     destroy_object(weaponObjId)
  278.                                 elseif tonumber(result) then
  279.                                     destroy_object(weaponObjId)
  280.                                     assign_weapon(playerIndex, spawn_object("", "", 1, 2, 3, 0, tonumber(result)))
  281.                                 end
  282.                             end
  283.                         end
  284.                     end
  285.                 end
  286.                 real_register_callback(cb.EVENT_PRESPAWN, "__onspawn_event")
  287.             end
  288.         end,
  289.     },
  290.     [cb.EVENT_SPAWN] = {
  291.         register = function(funcname)
  292.             if _SERVERAPP == "Phasor" then
  293.                 function OnPlayerSpawnEnd(playerId, playerObjId)
  294.                     ypcall(phasorEvents.OnPlayerSpawnEnd, playerId, playerObjId)
  295.                     ypcall(_G[funcname], resolveplayer(playerId))
  296.                 end
  297.             else
  298.                 function __onspawnend_event(playerIndex)
  299.                     if prevent_join[playerIndex] then
  300.                         return nil
  301.                     end
  302.                     local playerId = to_real_index(playerIndex)
  303.                     ypcall(phasorEvents.OnPlayerSpawnEnd, playerId, getplayerobjectid(playerId))
  304.                     ypcall(_G[funcname], playerIndex)
  305.                 end
  306.                 real_register_callback(cb.EVENT_SPAWN, "__onspawnend_event")
  307.             end
  308.         end
  309.     },
  310.     [cb.EVENT_KILL] = {
  311.         dependencies = {cb.EVENT_DIE},
  312.         register = function(funcname)
  313.             if _SERVERAPP == "Phasor" then
  314.                 events[cb.EVENT_KILL][1] = funcname
  315.             else
  316.                 real_register_callback(cb.EVENT_KILL, funcname)
  317.             end
  318.         end,
  319.     },
  320.     [cb.EVENT_DIE] = {
  321.         register = function(funcname)
  322.             if _SERVERAPP == "Phasor" then
  323.                 function OnPlayerKill(killerPlayerId, victimPlayerId, mode)
  324.                     ypcall(phasorEvents.OnPlayerKill, killerPlayerId, victimPlayerId, mode)
  325.                     local killerPlayerIndex, victimPlayerIndex = killerPlayerId and resolveplayer(killerPlayerId), resolveplayer(victimPlayerId)
  326.                     if mode == 5 then
  327.                         ypcall(_G[events[cb.EVENT_BETRAY][1]], killerPlayerIndex, victimPlayerIndex)
  328.                     elseif mode == 6 then
  329.                         ypcall(_G[events[cb.EVENT_SUICIDE][1]], victimPlayerIndex)
  330.                     end
  331.  
  332.                     ypcall(_G[events[cb.EVENT_DIE][1]], victimPlayerIndex)
  333.                     if killerPlayerId then
  334.                         ypcall(_G[events[cb.EVENT_KILL][1]], killerPlayerId, victimPlayerId)
  335.                     end
  336.                 end
  337.             else
  338.                 -- Broken: Falling kill vs server kill.
  339.                 function __kill_event(victim, killer)
  340.                     if prevent_join[playerIndex] then
  341.                         return nil
  342.                     end
  343.                     local mode
  344.                     local kteam, vteam
  345.                     local victimPlayerId = to_real_index(victim) -- should always be valid
  346.                     local killerPlayerId = to_real_index(killer)
  347.                     killerPlayerId = killerPlayerId ~= -1 and killerPlayerId or nil
  348.                     if killer == "-1" then
  349.                         mode = 1 -- Server kill OR FALL DAMAGE since that's broken
  350.                     elseif killer == "guardians" then
  351.                         mode = 2 -- Guardian kill
  352.                     elseif killer == 0 then
  353.                         mode = 3 -- Killed by a vehicle
  354.                     else
  355.                         goto finishRemaining
  356.                     end
  357.  
  358.                     goto OnPlayerKillCall
  359.                    
  360.                     ::finishRemaining::
  361.                     kteam = killerPlayerId and getteam(killerPlayerId)
  362.                     vteam = getteam(victimPlayerId)
  363.                     if victimPlayerId == killerPlayerId then
  364.                         mode = 6 -- Suicide
  365.                     elseif victimPlayerId ~= killerPlayerId and vteam ~= kteam then
  366.                         mode = 4 -- Killed by another player.
  367.                         if OnKillMultiplier then
  368.                             local multiplier = 0
  369.                             local m_kplayer = get_player(killer)
  370.                             local multikill = read_word(m_kplayer + 0x98)
  371.                             local spree = read_word(m_kplayer + 0x96)
  372.                             if multikill == 2 or multikill == 16 then
  373.                                 multiplier = 7 -- Double Kill.
  374.                             elseif multikill == 3 or multikill == 15 then
  375.                                 multiplier = 9 -- Triple Kill.
  376.                             elseif spree == 5 then
  377.                                 multiplier = 11 -- Killing Spree.
  378.                             elseif spree == 10 or (spree ~= 0 and spree % 5 == 0) then
  379.                                 multiplier = 12 -- Running Riot.
  380.                             elseif multikill >= 4 then
  381.                                 multiplier = 10 -- Killtacular.
  382.                             else
  383.                                 goto OnPlayerKillCall
  384.                             end
  385.                             OnKillMultiplier(killerPlayerId, multiplier)
  386.                         end
  387.                     elseif victimPlayerId ~= killerPlayerId and vteam == kteam then
  388.                         mode = 5 -- Betrayed
  389.                     end
  390.                    
  391.                     ::OnPlayerKillCall::
  392.                     if ypcall(phasorEvents.OnPlayerKill, killerPlayerId, victimPlayerId, mode) == false then
  393.                         -- thanks 002 for the silent kill code
  394.                         local m_player = get_player(victim)
  395.                         timer(0, "__ResetPlayerKill", m_player, read_word(m_player + 0xD4))
  396.                         write_word(m_player + 0xD4, 0xFFFF)
  397.                     end
  398.                     ypcall(_G[funcname], victim, killer)
  399.                 end
  400.                 function __ResetPlayerKill(m_player, old_value)
  401.                     write_word(m_player + 0xD4, old_value)
  402.                     return false
  403.                 end
  404.                 real_register_callback(cb.EVENT_DIE, "__kill_event")
  405.             end
  406.         end
  407.     },
  408.     [cb.EVENT_SNAP] = {
  409.         register = function(funcname)
  410.             if _SERVERAPP == "Phasor" then
  411.                 events[cb.EVENT_SNAP][1] = funcname
  412.             else
  413.                 real_register_callback(cb.EVENT_SNAP, funcname)
  414.             end
  415.         end
  416.     },
  417.     [cb.EVENT_WARP] = {
  418.         register = function(funcname)
  419.             if _SERVERAPP == "Phasor" then
  420.                 events[cb.EVENT_WARP][1] = funcname
  421.             else
  422.                 real_register_callback(cb.EVENT_WARP, funcname)
  423.             end
  424.         end
  425.     },
  426.     [cb.EVENT_WEAPON_PICKUP] = {
  427.         dependencies = {cb.EVENT_PRESPAWN},
  428.         register = function(funcname)
  429.             local weapons = {[0]={}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}
  430.             local playerObjId, m_playerObj, weaponObjId, thisWeaponEntry, frags, plasmas, playerIndex
  431.             local pickup_id = registertimer(500, "__weaponCheckTimer")
  432.             function __weaponCheckTimer(id, count)
  433.                 if pickup_id ~= id then return false end
  434.                 for playerId = 0,15 do
  435.                     if not getplayer(playerId) then
  436.                         goto resetweapons
  437.                     end
  438.                    
  439.                     playerObjId = getplayerobjectid(playerId)
  440.                     m_playerObj = getobject(playerObjId)
  441.                     if not m_playerObj then
  442.                         goto resetweapons
  443.                     end
  444.                    
  445.                     playerIndex = resolveplayer(playerId)
  446.                     thisWeaponEntry = weapons[playerId]
  447.                     for slot = 1,4 do
  448.                         weaponObjId = readdword(m_playerObj + 0x2F8 + (slot-1)*4)
  449.                         if thisWeaponEntry[slot] ~= weaponObjId then
  450.                             if thisWeaponEntry[slot] then
  451.                                 if weaponObjId ~= 0xFFFFFFFF then
  452.                                     ypcall(_G[events[cb.EVENT_WEAPON_DROP][1]], playerIndex, slot, 1)
  453.                                 elseif thisWeaponEntry[slot] ~= 0xFFFFFFFF then
  454.                                     ypcall(_G[events[cb.EVENT_WEAPON_DROP][1]], playerIndex, slot, 1)
  455.                                     ypcall(_G[funcname], playerIndex, slot, 1)
  456.                                 else
  457.                                     ypcall(_G[funcname], playerIndex, slot, 1)
  458.                                 end
  459.                             end
  460.                             thisWeaponEntry[slot] = weaponObjId
  461.                         end
  462.                     end
  463.                    
  464.                     frags = readbyte(m_playerObj + 0x31E)
  465.                     if thisWeaponEntry[5] ~= frags then
  466.                         if thisWeaponEntry[5] then
  467.                             for i = (thisWeaponEntry[5] or 0),frags do
  468.                                 ypcall(_G[funcname], playerIndex, 2, 2)
  469.                             end
  470.                         end
  471.                         thisWeaponEntry[5] = frags
  472.                     end
  473.                     plasmas = readbyte(m_playerObj + 0x31F)
  474.                     if thisWeaponEntry[6] ~= plasmas then
  475.                         if thisWeaponEntry[6] then
  476.                             for i = (thisWeaponEntry[6] or 0),plasmas do
  477.                                 ypcall(_G[funcname], playerIndex, 2, 2)
  478.                             end
  479.                         end
  480.                         thisWeaponEntry[6] = plasmas
  481.                     end
  482.                    
  483.                     goto continue
  484.                    
  485.                     ::resetweapons::
  486.                     thisWeaponEntry = weapons[playerId]
  487.                     if next(thisWeaponEntry) then
  488.                         for slot = 1,6 do
  489.                             thisWeaponEntry[slot] = nil
  490.                         end
  491.                     end
  492.                    
  493.                     ::continue::
  494.                 end
  495.                 ::endFunc::
  496.                 return true
  497.             end
  498.         end
  499.     },
  500.     [cb.EVENT_WEAPON_DROP] = {
  501.         dependencies = {cb.EVENT_WEAPON_PICKUP},
  502.         register = function(funcname)
  503.             if _SERVERAPP == "Phasor" then
  504.                 events[cb.EVENT_WEAPON_DROP][1] = funcname
  505.             else
  506.                 real_register_callback(cb.EVENT_WEAPON_DROP, funcname)
  507.             end
  508.         end
  509.     },
  510.     [cb.EVENT_VEHICLE_ENTER] = {
  511.         register = function(funcname)
  512.             if _SERVERAPP == "Phasor" then
  513.                 function OnVehicleEntry(playerId, __, seat)
  514.                     ypcall(phasorEvents.OnVehicleEntry, playerId, __, seat)
  515.                     ypcall(_G[funcname], resolveplayer(playerId), seat)
  516.                 end
  517.             else
  518.                 -- Hacky: Player can drive the vehicle for a whole 2 seconds before the script can eject them.
  519.                 function __vehicleentry_event(playerIndex, seat)
  520.                     if prevent_join[playerIndex] then
  521.                         return nil
  522.                     end
  523.                    
  524.                     local vehicleObjId = read_dword(get_dynamic_player(playerIndex) + 0x11C)
  525.                     if ypcall(phasorEvents.OnVehicleEntry, to_real_index(playerIndex), vehicleObjId, seat, read_dword(get_object_memory(vehicleObjId)), true) == false then
  526.                         timer(2000, "__prevententry", playerIndex)
  527.                     else
  528.                         ypcall(_G[funcname], playerIndex, seat)
  529.                     end
  530.                    
  531.                     function __prevententry(playerIndex)
  532.                         dont_doublecall_onvehicleeject = true
  533.                         exit_vehicle(playerIndex)
  534.                         dont_doublecall_onvehicleeject = false
  535.                         return false
  536.                     end
  537.                 end
  538.                 real_register_callback(cb.EVENT_VEHICLE_ENTER, "__vehicleentry_event")
  539.             end
  540.         end
  541.     },
  542.     [cb.EVENT_VEHICLE_EXIT] = {
  543.         register = function(funcname)
  544.             if _SERVERAPP == "Phasor" then
  545.                 function OnVehicleEject(playerId)
  546.                     ypcall(phasorEvents.OnVehicleEject, playerId)
  547.                     ypcall(_G[funcname], resolveplayer(playerId))
  548.                 end
  549.             else
  550.                 -- Broken: No way to determine if the player is being forcibly ejected or not.
  551.                 -- Hacky: Puts player back in vehicle after 1 second.
  552.                 function __vehicleexit_event(playerIndex)
  553.                     if prevent_join[playerIndex] then
  554.                         return nil
  555.                     end
  556.                     local m_playerObj = get_dynamic_player(playerIndex)
  557.                     local seat = read_word(m_playerObj + 0x120)
  558.                     if ypcall(phasorEvents.OnVehicleEject, to_real_index(playerIndex), seat) == false then
  559.                         timer(1000, "__preventejection", vehicleObjId, playerIndex, read_word(m_playerObj + 0x120))
  560.                     else
  561.                         ypcall(_G[funcname], playerIndex)
  562.                     end
  563.                 end
  564.                 function __preventejection(vehicleObjId, playerIndex, seat)
  565.                     dont_doublecall_onvehicleentry = true
  566.                     enter_vehicle(vehicleObjId, playerIndex, seat)
  567.                     dont_doublecall_onvehicleentry = false
  568.                     return false
  569.                 end
  570.                 real_register_callback(cb.EVENT_VEHICLE_EXIT, "__vehicleexit_event")
  571.             end
  572.         end
  573.     },
  574.     [cb.EVENT_BETRAY] = {
  575.         dependencies = {cb.EVENT_DIE},
  576.         register = function(funcname)
  577.             if _SERVERAPP == "Phasor" then
  578.                 events[cb.EVENT_BETRAY][1] = funcname
  579.             else
  580.                 real_register_callback(cb.EVENT_BETRAY, funcname)
  581.             end
  582.         end
  583.     },
  584.     [cb.EVENT_SUICIDE] = {
  585.         dependencies = {cb.EVENT_DIE},
  586.         register = function(funcname)
  587.             if _SERVERAPP == "Phasor" then
  588.                 events[cb.EVENT_SUICIDE][1] = funcname
  589.             else
  590.                 real_register_callback(cb.EVENT_SUICIDE, funcname)
  591.             end
  592.         end
  593.     },
  594.     [cb.EVENT_SCORE] = {
  595.         register = function(funcname)
  596.            
  597.             local function getscore(playerId)
  598.                 if gametype == 1 then
  599.                     return readshort(getplayer(playerId) + 0xC8)
  600.                 elseif gametype == 2 then
  601.                     return readint((_GAME == "PC" and 0x63A0E8 or 0x5BE108) + 0x40+playerId*4)
  602.                 elseif gametype == 3 then
  603.                     return readint((_GAME == "PC" and 0x639E58 or 0x5BDE78) + 0x84+playerId*4)
  604.                 elseif gametype == 4 then
  605.                     return readshort(getplayer(playerId) + 0xC4)
  606.                 elseif gametype == 5 then
  607.                     return readshort(getplayer(playerId) + 0xC6)
  608.                 end
  609.             end
  610.  
  611.             local score_timer_id = registertimer(1000, "__OnPlayerScoreCheck")
  612.             function __OnPlayerScoreCheck(id, count)
  613.                 if score_timer_id ~= id then return false end
  614.                 for playerId = 0,15 do
  615.                     if getplayer(playerId) then
  616.                         local score = getscore(playerId)
  617.                         if score ~= player_scores[playerId] then
  618.                             ypcall(_G[funcname], resolveplayer(playerId))
  619.                             player_scores[playerId] = score
  620.                         end
  621.                     end
  622.                 end
  623.                 return true
  624.             end
  625.         end
  626.     },
  627.     [cb.EVENT_TEAM_SWITCH] = {
  628.         register = function(funcname)
  629.             if _SERVERAPP == "Phasor" then
  630.                 function OnTeamChange(playerId, old_team, new_team, relevant)
  631.                     ypcall(phasorEvents.OnTeamChange, playerId, old_team, new_team, relevant)
  632.                     ypcall(_G[funcname], resolveplayer(playerId))
  633.                 end
  634.             else
  635.                 function __teamchange_event(playerIndex)
  636.                     local playerId = to_real_index(playerIndex)
  637.                     local new_team = getteam(playerId)
  638.                     local old_team = abs(old_team - 1)
  639.                    
  640.                     -- Broken: No way to check if this can be blocked (team switch in escape menu) vs command-executed.
  641.                     -- A solution is to assume it always can be blocked and use our method of blocking it.
  642.                     if ypcall(phasorEvents.OnTeamChange, playerId, old_team, new_team, false) == false then
  643.                         write_byte(get_player(playerIndex) + 0x20, old_team)
  644.                     end
  645.                    
  646.                     ypcall(_G[funcname], playerIndex)
  647.                 end
  648.                 real_register_callback(cb.EVENT_TEAM_SWITCH, "__teamchange_event")
  649.             end
  650.         end
  651.     },
  652.     [cb.EVENT_JOIN] = {
  653.         register = function(funcname)
  654.             if _SERVERAPP == "Phasor" then
  655.                 function OnPlayerJoin(playerId)
  656.                     ypcall(phasorEvents.OnPlayerJoin, playerId)
  657.                     ypcall(_G[funcname], resolveplayer(playerId))
  658.                 end
  659.             else
  660.                 -- Broken: No way to change name OnNameRequest
  661.                 -- Hacky: Player is banned onplayerjoin, so they will still enter the server for a brief minute.
  662.                 function __onjoin_event(playerIndex)
  663.                     local team = get_var(playerIndex, "$team")
  664.                     local new_team = tonumber(ypcall(phasorEvents.OnTeamDecision, team))
  665.                     if new_team and team ~= new_team then
  666.                         write_byte(get_player(playerIndex) + 0x20, new_team)
  667.                     end
  668.                     local hash = get_var(playerIndex, "$hash")
  669.                     if ypcall(phasorEvents.OnNameRequest, hash, get_var(playerIndex, "$name")) == false then
  670.                         write_word(get_player(playerIndex) + 0x2C, 0x7FFF) -- Don't let them spawn.
  671.                         local msg = "Your name is not allowed in this server. Please leave and change it."
  672.                         say(msg, playerIndex)
  673.                         rprint(msg, playerIndex)
  674.                         prevent_join[playerIndex] = true -- Prevents the player from spawning, etc in scripts code.
  675.                     end
  676.                     if ypcall(phasorEvents.OnBanCheck, hash, get_var(playerIndex, "$ip")) == false then
  677.                         execute_command("sv_ban " .. playerIndex .. " 1s")
  678.                         prevent_join[playerIndex] = true -- Prevents the player from spawning, etc in scripts code.
  679.                     end
  680.                     if prevent_join[playerIndex] then
  681.                         return nil
  682.                     end
  683.                     ypcall(phasorEvents.OnPlayerJoin, to_real_index(playerIndex), new_team)
  684.                     ypcall(_G[funcname], playerIndex)
  685.                 end
  686.                 real_register_callback(cb.EVENT_JOIN, "__onjoin_event")
  687.             end
  688.         end
  689.     },
  690.     [cb.EVENT_LEAVE] = {
  691.         register = function(funcname)
  692.             if _SERVERAPP == "Phasor" then
  693.                 function OnPlayerLeave(playerId)
  694.                     ypcall(phasorEvents.OnPlayerLeave, playerId)
  695.                     ypcall(_G[funcname], resolveplayer(playerId))
  696.                 end
  697.             else
  698.                 function __playerleave_event(playerIndex)
  699.                     if prevent_join[playerIndex] then
  700.                         prevent_join[playerIndex] = nil
  701.                         return nil
  702.                     end
  703.                     ypcall(phasorEvents.OnPlayerLeave, to_real_index(playerIndex))
  704.                     ypcall(_G[funcname], playerIndex)
  705.                 end
  706.                 real_register_callback(cb.EVENT_LEAVE, "__playerleave_event")
  707.             end
  708.         end
  709.     },
  710.     [cb.EVENT_CAMP] = {
  711.         register = function(funcname)
  712.             if _SERVERAPP == "Phasor" then
  713.                 events[cb.EVENT_WARP][1] = funcname
  714.             else
  715.                 real_register_callback(cb.EVENT_WARP, funcname)
  716.             end
  717.         end
  718.     },
  719.     [cb.EVENT_LOGIN] = {
  720.         register = function(funcname)
  721.             if _SERVERAPP == "Phasor" then
  722.                 events[cb.EVENT_WARP][1] = funcname
  723.             else
  724.                 real_register_callback(cb.EVENT_WARP, funcname)
  725.             end
  726.         end
  727.     },
  728.     [cb.EVENT_GAME_START] = {
  729.         register = function(funcname)
  730.             if _SERVERAPP == "Phasor" then
  731.                 function OnNewGame(map)
  732.                     ypcall(phasorEvents.OnNewGame, map)
  733.                     ypcall(_G[funcname])
  734.                 end
  735.             else
  736.                 function __newgame_event()
  737.                     ypcall(phasorEvents.OnNewGame, get_var(0, "$map"))
  738.                     ypcall(_G[funcname])
  739.                 end
  740.                 real_register_callback(cb.EVENT_GAME_START, "__newgame_event")
  741.             end
  742.         end
  743.     },
  744.     [cb.EVENT_GAME_END] = {
  745.         register = function(funcname)
  746.             if _SERVERAPP == "Phasor" then
  747.                 local ongameend_called
  748.                 function OnGameEnd(mode)
  749.                     ypcall(phasorEvents.OnGameEnd, mode)
  750.                     if not ongameend_called then
  751.                         ypcall(_G[funcname])
  752.                         ongameend_called = true
  753.                     end
  754.                 end
  755.             else
  756.                 -- I don't even need to explain how hacky this is, but suprisingly it works perfectly.
  757.                 function __gameend_event()
  758.                     OnGameEnd(1)
  759.                     ypcall(_G[funcname])
  760.                     function __OnGameEndTimer1() OnGameEnd(2) end
  761.                     function __OnGameEndTimer2() OnGameEnd(3) end
  762.                     timer(7000,  "__OnGameEndTimer1")
  763.                     timer(12000, "__OnGameEndTimer2")
  764.                 end
  765.                 real_register_callback(cb.EVENT_GAME_END, "__gameend_event")
  766.             end
  767.         end
  768.     },
  769.     [cb.EVENT_CHAT] = {
  770.         register = function(funcname)
  771.             if _SERVERAPP == "Phasor" then
  772.                 function OnServerChat(playerId, chattype, message)
  773.                     if playerId and chattype ~= 4 then
  774.                         local response = ypcall(phasorEvents.OnServerChat, playerId, chattype, message)
  775.                         response = response ~= false and ypcall(_G[funcname], to_player_index(playerId), message)
  776.                     end
  777.                 end
  778.             else
  779.                 -- Broken: No way to modify messages
  780.                 -- Broken: No way to determine what TYPE of message is being passed.
  781.                 function __serverchat_event(playerIndex, message)
  782.                     if message:sub(1, 5) ~= "/lead" and message:sub(1, 5) ~= "\\lead" then
  783.                         local response = ypcall(phasorEvents.OnServerChat, to_real_index(playerIndex), 0, message)
  784.                         response = response ~= false and ypcall(_G[funcname], playerIndex, message)
  785.                     end
  786.                 end
  787.                 real_register_callback(cb.EVENT_CHAT, "__serverchat_event")
  788.             end
  789.         end
  790.     },
  791.     [cb.EVENT_COMMAND] = {
  792.         register = function(funcname)
  793.             local function respond(message)
  794.                 if env == 0 then
  795.                     cprint(message)
  796.                 elseif env == 1 then
  797.                     rprint(playerIndex, message)
  798.                 elseif env == 2 then
  799.                     say(playerIndex, message)
  800.                 elseif getplayer(playerId) then
  801.                     sendconsoletext(playerId, message)
  802.                 else
  803.                     hprintf(message)
  804.                 end
  805.             end
  806.             if _SERVERAPP == "Phasor" then
  807.                 local sappattemptcalled = true
  808.                 function OnServerCommandAttempt(playerId, command, password)
  809.                     local respond = respond
  810.                     local result = ypcall(phasorEvents.OnServerCommandAttempt, playerId, command, password)
  811.                    
  812.                     local playerIndex = resolveplayer(playerId)
  813.                     local result2 = ypcall(_G[funcname], playerIndex, command, playerId and 1 or 0, password)
  814.                     sappattemptcalled = true
  815.                     if result ~= false then
  816.                         return result or result2
  817.                     end
  818.                     return false
  819.                 end
  820.                 local __orig_command_event = __OnServerCommand
  821.                 function OnServerCommand(playerId, command)
  822.                     local respond = respond
  823.                     local result = ypcall(phasorEvents.OnServerCommand, playerId, command)
  824.                    
  825.                     if sappattemptcalled then
  826.                         sappattemptcalled = nil
  827.                         return result
  828.                     end
  829.                    
  830.                     local playerIndex = resolveplayer(playerId)
  831.                     ypcall(_G[funcname], playerIndex, command, playerId and 1 or 0, _GAME == "PC" and read_string(0x69BA5C8) or read_string(0x61FC8C8))
  832.                 end
  833.             else
  834.                 function __command_event(playerIndex, command, env, rcon)
  835.                     local respond = respond
  836.                     local playerId = to_real_index(playerIndex) or -1
  837.                     playerId = playerId ~= -1 and playerId or nil
  838.                     local result
  839.                     if env == 1 then
  840.                         if _GAME == "PC" and read_string(0x69BA5C8) == rcon or read_string(0x61FC8C8) == rcon then
  841.                             result = ypcall(phasorEvents.OnServerCommand, playerId, command)
  842.                         elseif ypcall(phasorEvents.OnServerCommandAttempt, playerId, command, rcon) then
  843.                             result = ypcall(phasorEvents.OnServerCommand, playerId, command)
  844.                         end
  845.                     else
  846.                         result = ypcall(OnServerCommand, playerId, command)
  847.                     end
  848.                    
  849.                     if result ~= false then
  850.                         return result or ypcall(_G[funcname], playerIndex, command, env, rcon)
  851.                     end
  852.                 end
  853.                 real_register_callback(cb.EVENT_COMMAND, "__command_event")
  854.             end
  855.         end
  856.     },
  857.     [cb.EVENT_ECHO] = {
  858.         register = function(funcname)
  859.             if _SERVERAPP == "Phasor" then
  860.                 events[cb.EVENT_ECHO][1] = funcname
  861.             else
  862.                 function __echo_event(playerIndex, output)
  863.                     ypcall(_G[funcname], playerIndex, output)
  864.                     if svcmd_echo then
  865.                         svcmd_echo = svcmd_echo .. "\n" .. output
  866.                     end
  867.                 end
  868.                 real_register_callback(cb.EVENT_ECHO, "__echo_event")
  869.             end
  870.         end
  871.     },
  872.     [cb.EVENT_OBJECT_SPAWN] = {
  873.         register = function(funcname)
  874.             if _SERVERAPP == "Phasor" then
  875.                 function OnObjectCreationAttempt(mapId, parentObjId, playerId)
  876.                     ypcall(phasorEvents.OnObjectCreationAttempt, mapId, parentObjId, playerId)
  877.                     ypcall(_G[funcname], resolveplayer(playerId), mapId, parentObjId, readword(0x4005062C + 0x32) * 0x10000 + readword(0x4005062C + 0x2C))
  878.                 end
  879.             else
  880.                 function __objectcreate_event(playerIndex, mapId, parentObjId, objectId)
  881.                     if prevent_join[playerIndex] then
  882.                         return nil
  883.                     end
  884.                    
  885.                     local playerId = to_real_index(playerIndex)
  886.                     playerId = playerId ~= -1 and playerId or nil
  887.                     local response = ypcall(phasorEvents.OnObjectCreationAttempt, mapId, parentObjId, playerId)
  888.                     if response ~= false then -- don't call onobjectcreation if the attempt was terminated.
  889.                         response = ypcall(phasorEvents.OnObjectCreation, objectId) ~= false and tonumber(response)
  890.                     end
  891.                    
  892.                     if response ~= false then
  893.                         local response2 = ypcall(_G[funcname], playerIndex, mapId, parentObjId, objectId)
  894.                         if response2 ~= false then
  895.                             response = response2 or response
  896.                         else
  897.                             response = false
  898.                         end
  899.                     end
  900.                    
  901.                     if response then
  902.                         return true,response
  903.                     elseif response ~= false and not playerId and parentObjId ~= 0xFFFFFFFF then
  904.                         local response2 = ypcall(phasorEvents.OnWeaponAssignment, playerId, parentObjId, 0, mapId)
  905.                         if response2 ~= false then
  906.                             response = response2 or response
  907.                         else
  908.                             response = false
  909.                         end
  910.                     end
  911.                    
  912.                     return response
  913.                 end
  914.                 real_register_callback(cb.EVENT_OBJECT_SPAWN, "__objectcreate_event")
  915.             end
  916.         end
  917.     },
  918. }
  919.  
  920. --[==[local eventsMT = {
  921.     __call = function(self, a,b,c,d,e,f,g)
  922.         for i = 1,#self do
  923.             _G[self[i]](a,b,c,d,e,f,g)
  924.         end
  925.     end
  926. }
  927. for k,v in next,events do
  928.     setmetatable(v, eventsMT)
  929. end]==]
  930.  
  931. -- Private functions
  932.  
  933. function events:Create(event, funcname)
  934.    
  935.     funcname = funcname ~= "##INTERNAL_ONLY##" and funcname
  936.    
  937.     -- Register our event.
  938.     self[#self+1] = funcname
  939.     self.register(funcname)
  940.    
  941.     -- Create dependencies.
  942.     local dependencies = self.dependencies
  943.     local dependency, dependencyEvent
  944.     local newBlankFuncStr
  945.     if dependencies then
  946.         for i = 1,#dependencies do dependency = dependencies[i]
  947.             dependencyEvent = events[dependency]
  948.             -- Only create the event dependency if it isn't already created.
  949.             if not dependencyEvent[1] then
  950.                 newBlankFuncStr = "__" .. funcname
  951.                 events.Create(dependencyEvent, dependency, newBlankFuncStr)
  952.                 _G[newBlankFuncStr] = function() end
  953.             end
  954.         end
  955.     end
  956. end
  957.  
  958. local function registerPhasorEvents()
  959.  
  960.     -- bool     OnObjectInteraction (halo::s_player &player, halo::ident objid, halo::ident mapid)
  961.         -- Called when a player interacts with an object (ie stands on it)
  962.      
  963.     -- bool     OnDamageLookup (halo::s_damage_info *dmg, void *metaData, halo::ident receiver, halo::damage_script_options &out)
  964.         -- Called when the server needs to apply damage to an object.
  965.      
  966.     -- bool     OnDamageApplication (const halo::s_damage_info *dmg, halo::ident receiver, const halo::s_hit_info *hit, bool backtap)
  967.         -- Called when the server is about to apply damage to an object.
  968.        
  969.     local nonexistant_func = "##INTERNAL_ONLY##"
  970.     register_callback(cb.EVENT_ECHO, nonexistant_func)
  971.     if OnServerChat then
  972.         register_callback(cb.EVENT_CHAT, nonexistant_func)
  973.     end
  974.     if OnTeamDecision or OnNameRequest or OnBanCheck or OnPlayerJoin then
  975.         register_callback(cb.EVENT_JOIN, nonexistant_func)
  976.     end
  977.     if OnWeaponReload or OnClientUpdate then
  978.         register_callback(cb.EVENT_TICK, nonexistant_func)
  979.     end
  980.     if OnGameEnd then
  981.         register_callback(cb.EVENT_GAME_END, nonexistant_func)
  982.     end
  983.     if OnNewGame then
  984.         register_callback(cb.EVENT_GAME_START, nonexistant_func)
  985.     end
  986.     if OnKillMultiplier or OnPlayerKill then
  987.         register_callback(cb.EVENT_DIE, nonexistant_func)
  988.     end
  989.     if OnObjectCreation or OnObjectCreationAttempt or OnWeaponAssignment then
  990.         register_callback(cb.EVENT_OBJECT_SPAWN, nonexistant_func)
  991.     end
  992.     if OnPlayerLeave then
  993.         register_callback(cb.EVENT_LEAVE, nonexistant_func)
  994.     end
  995.     if OnPlayerSpawn or OnWeaponAssignment then
  996.         register_callback(cb.EVENT_PRESPAWN, nonexistant_func)
  997.     end
  998.     if OnPlayerSpawnEnd then
  999.         register_callback(cb.EVENT_SPAWN, nonexistant_func)
  1000.     end
  1001.     if OnServerCommand or OnServerCommandAttempt then
  1002.         register_callback(cb.EVENT_COMMAND, nonexistant_func)
  1003.     end
  1004.     if OnTeamChange then
  1005.         register_callback(cb.EVENT_TEAM_SWITCH, nonexistant_func)
  1006.     end
  1007.     if OnVehicleEntry then
  1008.         register_callback(cb.EVENT_VEHICLE_ENTER, nonexistant_func)
  1009.     end
  1010.     if OnVehicleEject then
  1011.         register_callback(cb.EVENT_VEHICLE_EXIT, nonexistant_func)
  1012.     end
  1013. end
  1014.  
  1015. local __say = say
  1016. local kill = kill
  1017.  
  1018. local function trim(str)
  1019.     return gsub(str, "^[%c%s]*(.-)[%c%s]*$", "%1") or str
  1020. end
  1021.  
  1022. -- Definitions for All Phasor Functions
  1023.  
  1024. GetRequiredVersion = GetRequiredVersion or function() return phasor_version end
  1025. required_version = phasor_version
  1026.  
  1027. applycamo = applycamo or ( -- Good
  1028.     function(playerId, duration)
  1029.         local playerIndex = to_player_index(playerId)
  1030.         assert(playerIndex ~= 0, "invalid player id")
  1031.         camo(playerIndex, duration * 30)
  1032.     end
  1033. )
  1034. applydmg = applydmg -- Not in Sapp.
  1035. applydmgtag = applydmgtag -- Not in Sapp.
  1036. assignweapon = assignweapon or ( -- Good
  1037.     function(playerId, objectId)
  1038.         local playerIndex = to_player_index(playerId)
  1039.         assert(playerIndex ~= 0, "invalid player id")
  1040.         return assign_weapon(objectId, playerIndex)
  1041.     end
  1042. )
  1043. changeteam = changeteam or ( -- Good
  1044.     function(playerId, bKill)
  1045.         local playerIndex = to_player_index(playerId)
  1046.         assert(playerIndex ~= 0, "invalid player id")
  1047.         local m_player = get_player(playerIndex)
  1048.         local team = read_byte(m_player + 0x20)
  1049.         local new_team = abs(team - 1)
  1050.         if not OnTeamChange2 or OnTeamChange2(playerId, team, new_team, true) ~= false then
  1051.             write_byte(m_player + 0x20, new_team)
  1052.             if bKill then kill(playerIndex) end
  1053.         end
  1054.     end
  1055. )
  1056. createobject = createobject or ( -- Good
  1057.     function(mapId, parentObjId, respawn_time, bRecycle, x, y, z)
  1058.         local objectId = spawn_object("", "", x, y, z, 0, mapId)
  1059.         return objectId ~= 0 and objectId or nil
  1060.     end
  1061. )
  1062. destroyobject = destroyobject or ( -- Good
  1063.     function(objectId)
  1064.         assert(getobject(objectId), "invalid object id")
  1065.         destroy_object(objectId)
  1066.     end
  1067. )
  1068. entervehicle = entervehicle or ( -- Good
  1069.     function(playerId, objectId, seat)
  1070.         local playerIndex = to_player_index(playerId)
  1071.         assert(playerIndex ~= 0, "invalid player id")
  1072.         assert(getobject(objectId), "invalid object id")
  1073.         return enter_vehicle(objectId, playerIndex, seat) or nil
  1074.     end
  1075. )
  1076. exitvehicle = exitvehicle or ( -- Good
  1077.     function(playerId)
  1078.         local playerIndex = to_player_index(playerId)
  1079.         assert(playerIndex ~= 0, "invalid player id")
  1080.         exit_vehicle(playerIndex)
  1081.     end
  1082. )
  1083. gethash = gethash or ( -- Good
  1084.     function(playerId)
  1085.         local playerIndex = to_player_index(playerId)
  1086.         assert(playerIndex ~= 0, "invalid player id")
  1087.         local result = get_var(playerIndex, "$hash")
  1088.         return result ~= 0 and result or nil
  1089.     end
  1090. )
  1091. getip = getip or ( -- Good
  1092.     function(playerId)
  1093.         local playerIndex = to_player_index(playerId)
  1094.         assert(playerIndex ~= 0, "invalid player id")
  1095.         local network_machine_pointer = _GAME == "PC" and 0x745BA0 or 0x6C7980
  1096.         local network_pointer = read_dword(read_dword(read_dword(read_dword(network_machine_pointer) + 0xAA0 + read_byte(get_player(playerIndex) + 0x64)*4)))
  1097.         assert(network_pointer ~= 0, "'getip' cannot be used in OnPlayerLeave or EVENT_LEAVE")
  1098.         return format("%i.%i.%i.%i", read_byte(network_pointer), read_byte(network_pointer + 0x1), read_byte(network_pointer + 0x2), read_byte(network_pointer + 0x3)) -- Player's IP Address (127.0.0.1 if host)
  1099.     end
  1100. )
  1101. getname = getname or ( -- Good
  1102.     function(playerId)
  1103.         local playerIndex = to_player_index(playerId)
  1104.         assert(playerIndex ~= 0, "invalid player id")
  1105.         local result = get_var(playerIndex, "$name")
  1106.         return result ~= 0 and result or nil
  1107.     end
  1108. )
  1109. getobject = getobject or ( -- Good
  1110.     function(objectId)
  1111.         local m_object = get_object_memory(objectId)
  1112.         return m_object ~= 0 and m_object or nil
  1113.     end
  1114. )
  1115. getobjectcoords = getobjectcoords or ( -- Good
  1116.     function(objectId)
  1117.         local m_object = get_object_memory(objectId)
  1118.         assert(m_object ~= 0, "invalid object id")
  1119.  
  1120.         local m_vehicleObj = get_object_memory(read_dword(m_object + 0x11C))
  1121.         if m_vehicleObj ~= 0 then
  1122.             m_object = m_vehicleObj
  1123.         end
  1124.  
  1125.         return read_vector3d(m_object + 0x5C)
  1126.     end
  1127. )
  1128. getplayer = getplayer or ( -- Good
  1129.     function(playerId)
  1130.         playerId = tonumber(playerId)
  1131.         if not playerId then
  1132.             return nil
  1133.         end
  1134.        
  1135.         local playerIndex = to_player_index(playerId)
  1136.         if prevent_join[playerIndex] then return nil end
  1137.         local result = get_player(to_player_index(playerId))
  1138.         return result ~= 0 and read_dword(result) ~= 0 and result or nil
  1139.     end
  1140. )
  1141. getplayerobjectid = getplayerobjectid or ( -- Good
  1142.     function(playerId)
  1143.         local playerIndex = to_player_index(playerId)
  1144.         assert(playerIndex ~= 0, "invalid player id")
  1145.         return read_dword(get_player(playerIndex) + 0x34)
  1146.     end
  1147. )
  1148. getport = getport or ( -- Good
  1149.     function(playerId)
  1150.         local playerIndex = to_player_index(playerId)
  1151.         assert(playerIndex ~= 0, "invalid player id")
  1152.         return read_word(read_dword(read_dword(read_dword(read_dword(_GAME == "PC" and 0x745BA0 or 0x6C7980) + 0xAA0 + read_byte(get_player(playerIndex) + 0x64)*4))) + 0x4)
  1153.     end
  1154. )
  1155. getprofilepath = getprofilepath or ( -- Good
  1156.     function()
  1157.         return (_GAME == "PC" and read_string(0x635610) or read_string(0x5B9630) or "") .. "\\"
  1158.     end
  1159. )
  1160. getrandomnumber = getrandomnumber or rand or math.randomseed(clock() + time()) and random(1,2) and random(3,5) and random(8,13) and ( -- Good
  1161.     function(min, max)
  1162.         if min > max then
  1163.             min, max = max, min
  1164.         end
  1165.         return random(min, max+1)
  1166.     end
  1167. )
  1168. gettagaddress = gettagaddress or ( -- Good
  1169.     function(a, b)
  1170.         local tag = lookup_tag(a, b)
  1171.         return tag ~= 0 and read_dword(tag + 0x14) or nil
  1172.     end
  1173. )
  1174. gettagid = gettagid or ( -- Good
  1175.     function(a, b)
  1176.         local tag = lookup_tag(a, b)
  1177.         return tag ~= 0 and read_dword(tag + 0xC) or nil
  1178.     end
  1179. )
  1180. gettaginfo = gettaginfo or ( -- Good
  1181.     function(a)
  1182.         local tag = lookup_tag(a, b)
  1183.         return tag ~= 0 and read_string(read_dword(tag + 0x10)), read_string(tag)
  1184.     end
  1185. )
  1186. getteam = getteam or ( -- Good
  1187.     function(playerId)
  1188.         local playerIndex = to_player_index(playerId)
  1189.         assert(playerIndex ~= 0, "invalid player id")
  1190.         local m_player = get_player(playerIndex)
  1191.         return read_byte(m_player + 0x20) or nil
  1192.     end
  1193. )
  1194. getteamsize = getteamsize or ( -- Good
  1195.     function(team)
  1196.         local counter = 0
  1197.         for playerIndex = 1,16 do
  1198.             if player_present(playerIndex) and get_var(playerIndex, "$team") == team then
  1199.                 counter = counter + 1
  1200.             end
  1201.         end
  1202.         return counter
  1203.     end
  1204. )
  1205. getticks = getticks or function() return clock() * 1000 end -- Good
  1206. halointersect = halointersect or ( -- Good
  1207.     function(dist, x, y, z, vx, vy, vz, objectId)
  1208.         return intersect(x, y, z, vx*dist, vy*dist, vz*dist, objectId)
  1209.     end
  1210. )
  1211. hprintf = hprintf or print -- Good
  1212. isinvehicle = isinvehicle or ( -- Good
  1213.     function(playerId)
  1214.         local playerIndex = to_player_index(playerId)
  1215.         assert(playerIndex ~= 0, "invalid player id")
  1216.        
  1217.         local m_playerObj = get_object_memory(read_dword(get_player(playerIndex) + 0x34))
  1218.         return m_playerObj ~= 0 and get_object_memory(read_dword(m_playerObj + 0x11C)) ~= 0
  1219.     end
  1220. )
  1221. phasorkill = _SERVERAPP == "Phasor" and kill or ( -- Annoying workaround.
  1222.     function(playerId)
  1223.         kill(to_player_index(playerId))
  1224.     end
  1225. )
  1226. log_msg = log_msg -- Not in Sapp.
  1227. lookuptag = lookuptag or ( -- Good
  1228.     function(a)
  1229.         local tag = lookup_tag(a)
  1230.         return tag ~= 0 and read_dword(tag+0x14) or nil
  1231.     end
  1232. )
  1233. movobjectcoords = movobjectcoords or moveobjcoords or moveobjectcoords or movobjcoords or ( -- Good
  1234.     function(objectId, x, y, z)
  1235.         local m_object = get_object_memory(objectId)
  1236.         assert(m_object ~= 0, "invalid object id")
  1237.        
  1238.         local m_vehicleObj = get_object_memory(read_dword(m_object + 0x11C))
  1239.         write_vector3d( (m_vehicleObj ~= 0 and m_vehicleObj or m_object) + 0x5C, x, y, z)
  1240.     end
  1241. )
  1242. objectidtoplayer = objectidtoplayer or ( -- Good
  1243.     function(objectId)
  1244.         local m_object = get_object_memory(objectId)
  1245.         assert(m_object ~= 0, "invalid object id")
  1246.        
  1247.         local playerId = read_word(m_object + 0xC0)
  1248.         return to_player_index(playerId) ~= 0 and playerId or nil
  1249.     end
  1250. )
  1251. odl_causer = odl_causer -- Not in sapp.
  1252. odl_flags = odl_flags -- Not in sapp.
  1253. odl_multiplier = odl_multiplier -- Not in sapp.
  1254. odl_receiver = odl_receiver -- Not in sapp.
  1255. odl_tag = odl_tag -- Not in sapp.
  1256. privatesay = privatesay or ( -- Good
  1257.     function(playerId, message)
  1258.         local playerIndex = to_player_index(playerId)
  1259.         assert(playerIndex ~= 0, "invalid player id")
  1260.        
  1261.         if not find(message, "\n") then
  1262.             return say(message, playerIndex)
  1263.         else
  1264.             local strTable = tokenizestring(message, "\n")
  1265.             for i = 1,#strTable do
  1266.                 say(strTable[i], playerIndex)
  1267.             end
  1268.         end
  1269.     end
  1270. )
  1271. raiseerror = error -- Good
  1272. readbit = readbit or read_bit and ( -- Good
  1273.     function(address, offset, bit)
  1274.         address = assert(tonumber(address), "bad argument #1 to 'readbit' expected number, got " .. type(address))
  1275.         if not bit then
  1276.             bit = assert(tonumber(offset), "bad argument #2 to 'readbit' expected number, got " .. type(offset))
  1277.             offset = 0
  1278.         else
  1279.             offset = assert(tonumber(offset), "bad argument #2 to 'readbit' expected number, got " .. type(offset))
  1280.             bit = assert(tonumber(bit), "bad argument #3 to 'readbit' expected number, got " .. type(bit))
  1281.         end
  1282.         safe_read(true)
  1283.         local res = bit32.band(read_byte(address + offset + math.floor(bit / 8)), bit) ~= 0
  1284.         safe_read(safe_read_val)
  1285.         return res
  1286.     end
  1287. )
  1288. readbyte = readbyte or ( -- Good
  1289.     function(address, offset)
  1290.         address = assert(tonumber(address), "bad argument #1 to 'readbyte' expected number, got " .. type(address))
  1291.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readbyte' expected number, got " .. type(offset))
  1292.         safe_read(true)
  1293.         local res = read_byte(address + (offset == true and 0 or offset))
  1294.         safe_read(safe_read_val)
  1295.         return res
  1296.     end
  1297. )
  1298. readchar = readchar or ( -- Good
  1299.     function(address, offset)
  1300.         address = assert(tonumber(address), "bad argument #1 to 'readchar' expected number, got " .. type(address))
  1301.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readchar' expected number, got " .. type(offset))
  1302.         safe_read(true)
  1303.         local res = read_char(address + (offset == true and 0 or offset))
  1304.         safe_read(safe_read_val)
  1305.         return res
  1306.     end
  1307. )
  1308. readword = readword or ( -- Good
  1309.     function(address, offset)
  1310.         address = assert(tonumber(address), "bad argument #1 to 'readword' expected number, got " .. type(address))
  1311.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readword' expected number, got " .. type(offset))
  1312.         safe_read(true)
  1313.         local res = read_word(address + (offset == true and 0 or offset))
  1314.         safe_read(safe_read_val)
  1315.         return res
  1316.     end
  1317. )
  1318. readshort = readshort or ( -- Good
  1319.     function(address, offset)
  1320.         address = assert(tonumber(address), "bad argument #1 to 'readshort' expected number, got " .. type(address))
  1321.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readshort' expected number, got " .. type(offset))
  1322.         safe_read(true)
  1323.         local res = read_short(address + (offset == true and 0 or offset))
  1324.         safe_read(safe_read_val)
  1325.         return res
  1326.     end
  1327. )
  1328. readdword = readdword or ( -- Good
  1329.     function(address, offset)
  1330.         address = assert(tonumber(address), "bad argument #1 to 'readdword' expected number, got " .. type(address))
  1331.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readdword' expected number, got " .. type(offset))
  1332.         safe_read(true)
  1333.         local res = read_dword(address + (offset == true and 0 or offset))
  1334.         safe_read(safe_read_val)
  1335.         return res
  1336.     end
  1337. )
  1338. readint = readint or ( -- Good
  1339.     function(address, offset)
  1340.         address = assert(tonumber(address), "bad argument #1 to 'readint' expected number, got " .. type(address))
  1341.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readint' expected number, got " .. type(offset))
  1342.         safe_read(true)
  1343.         local res = read_int(address + (offset == true and 0 or offset))
  1344.         safe_read(safe_read_val)
  1345.         return res
  1346.     end
  1347. )
  1348. readfloat = readfloat or ( -- Good
  1349.     function(address, offset)
  1350.         address = assert(tonumber(address), "bad argument #1 to 'readfloat' expected number, got " .. type(address))
  1351.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readfloat' expected number, got " .. type(offset))
  1352.         safe_read(true)
  1353.         local res = read_float(address + (offset == true and 0 or offset))
  1354.         safe_read(safe_read_val)
  1355.         return res
  1356.     end
  1357. )
  1358. readdouble = readdouble or ( -- Good
  1359.     function(address, offset)
  1360.         address = assert(tonumber(address), "bad argument #1 to 'readdouble' expected number, got " .. type(address))
  1361.         offset = assert(not offset or tonumber(offset), "bad argument #2 to 'readdouble' expected number, got " .. type(offset))
  1362.         safe_read(true)
  1363.         local res = read_double(address + (offset == true and 0 or offset))
  1364.         safe_read(safe_read_val)
  1365.         return res
  1366.     end
  1367. )
  1368. readstring = read_string and ( -- Good
  1369.     function(a, l)
  1370.         a = assert(tonumber(a), "bad argument #1 to 'readstring' expected number, got '" .. type(a) .. "'")
  1371.         l = assert(not l or tonumber(l), "bad argument #2 to 'readstring' expected number, got '" .. type(l) .. "'")
  1372.         safe_read(true)
  1373.         local str = read_string(a)
  1374.         safe_read(safe_read_val)
  1375.         return str and sub(str, 1, l or #str)
  1376.     end
  1377. ) or (
  1378.     function(address, length)
  1379.         address = assert(tonumber(address), "bad argument #1 to 'readstring' expected number, got '" .. type(address) .. "'")
  1380.         length = assert(not length or tonumber(length), "bad argument #2 to 'readstring' expected number, got '" .. type(length) .. "'")
  1381.         local char_table = {}
  1382.         local newByte
  1383.         safe_read(true)
  1384.         for i = 0,(length == true and 256 or length)-1 do
  1385.             newByte = read_byte(address + i)
  1386.             if newByte == 0 or newByte == 255 then break end
  1387.             char_table[#char_table+1] = char(newByte)
  1388.         end
  1389.         safe_read(safe_read_val)
  1390.         return concat(char_table)
  1391.     end
  1392. )
  1393. readwidestring = read_wide_string and ( -- Good
  1394.     function(a, l)
  1395.         a = assert(tonumber(a), "bad argument #1 to 'readstring' expected number, got '" .. type(a) .. "'")
  1396.         l = assert(not l or tonumber(l), "bad argument #2 to 'readstring' expected number, got '" .. type(l) .. "'")
  1397.         safe_read(true)
  1398.         local str = read_wide_string(a)
  1399.         safe_read(safe_read_val)
  1400.         return str and sub(str, 1, l or #str)
  1401.     end
  1402. ) or (
  1403.     function(address, length)
  1404.         address = assert(tonumber(address), "bad argument #1 to 'readwidestring' expected number, got '" .. type(address) .. "'")
  1405.         length = assert(not length or tonumber(length), "bad argument #2 to 'readwidestring' expected number, got '" .. type(length) .. "'")
  1406.         local char_table = {}
  1407.         local newByte
  1408.         safe_read(true)
  1409.         for i = 0,(length == true and 51001 or length)-1,2 do
  1410.             newByte = read_byte(address + i)
  1411.             if newByte == 0 or newByte == 255 or read_byte(address + i+1) ~= 0 then break end
  1412.             char_table[#char_table+1] = char(newByte)
  1413.         end
  1414.         safe_read(safe_read_val)
  1415.         return concat(char_table)
  1416.     end
  1417. )
  1418. registertimer = registertimer or ( -- Good
  1419.     function(delay, funcname, arg)
  1420.         local id = #timers+1
  1421.         timers[id] = funcname
  1422.         timer(delay, "__" ..funcname)
  1423.         local count = 0
  1424.         _G["__" .. funcname] = (
  1425.             function()
  1426.                 if not timers[id] then return false end
  1427.                 count = count + 1
  1428.                 local response = ypcall(_G[funcname], id, count, arg)
  1429.                 if response == false then
  1430.                     timers[id] = nil
  1431.                 end
  1432.                 return response
  1433.             end
  1434.         )
  1435.         return id
  1436.     end
  1437. )
  1438. resolveplayer = resolveplayer or ( -- Good
  1439.     function(playerId)
  1440.         local playerIndex = to_player_index(playerId)
  1441.         return playerIndex ~= 0 and playerIndex or nil
  1442.     end
  1443. )
  1444. rresolveplayer = rresolveplayer or ( -- Good
  1445.     function(playerIndex)
  1446.         local playerId = to_real_index(playerIndex)
  1447.         return playerId ~= 0 and playerId or nil
  1448.     end
  1449. )
  1450. removetimer = removetimer or ( -- Good
  1451.     function(id)
  1452.         if id then -- just ignore invalid timer ids
  1453.             timers[id] = nil
  1454.         end
  1455.     end
  1456. )
  1457. respond = respond or function() end -- Good. (real function in onservercommand event)
  1458. say = function(a, b) -- Good
  1459.     if tonumber(b) then
  1460.         if _SERVERAPP == "Phasor" then
  1461.             privatesay(a, rresolveplayer(b))
  1462.         else
  1463.             __say(b, a)
  1464.         end
  1465.     elseif b == false then
  1466.         if _SERVERAPP == "Sapp" then
  1467.             execute_command('say_prefix false')
  1468.             __say(a)
  1469.             execute_command('say_prefix true')
  1470.         else
  1471.             __say(a, false)
  1472.         end
  1473.     elseif b == true or b == nil then
  1474.         if _SERVERAPP == "Phasor" then
  1475.             __say(a)
  1476.         elseif not find(a, "\n") then
  1477.             say_all(a)
  1478.         else
  1479.             local strTable = tokenizestring(a, "\n")
  1480.             for i = 1,#strTable do
  1481.                 say_all(strTable[i])
  1482.             end
  1483.         end
  1484.     end
  1485. end
  1486. sendconsoletext = sendconsoletext or ( -- Good
  1487.     function(playerId, message)
  1488.         rprint(to_player_index(playerId), message)
  1489.     end
  1490. )
  1491. setspeed = setspeed or (
  1492.     function(playerId, speed)
  1493.         local playerIndex = to_player_index(playerId)
  1494.         assert(playerIndex ~= 0, "invalid player id")
  1495.         speed = assert(tonumber(speed), "bad argument #2 to 'setspeed' expected number, got " .. type(speed))
  1496.         write_float(get_player(playerIndex) + 0x6C, speed)
  1497.     end
  1498. )
  1499. svcmd = svcmd or ( -- Good
  1500.     function(a, bResult)
  1501.         if a ~= "reload" and a ~= "lua_unload" and a ~= "lua_load" then
  1502.             bResult = not not bResult
  1503.             svcmd_echo = bResult and ""
  1504.             execute_command(a, 0, bResult)
  1505.             bResult = type(svcmd_echo) == "string" and tokenizestring(svcmd_echo, "\n") or nil
  1506.             svcmd_echo = false
  1507.             return bResult
  1508.         end
  1509.     end
  1510. )
  1511. svcmdplayer = svcmdplayer or ( -- Good
  1512.     function(a, playerId, bResult)
  1513.         if a ~= "reload" and a ~= "lua_unload" and a ~= "lua_load" then
  1514.             svcmd_echo = bResult and ""
  1515.             execute_command(a, to_player_index(playerId), not not bResult)
  1516.             bResult = type(svcmd_echo) == "string" and tokenizestring(svcmd_echo, "\n") or nil
  1517.             svcmd_echo = false
  1518.             return bResult
  1519.         end
  1520.     end
  1521. )
  1522. tokenizestring = tokenizestring or ( -- Good
  1523.     function(str, ...)
  1524.        
  1525.         local subs = {}
  1526.         if (...) == "" then
  1527.             for i = 1,#str do
  1528.                 subs[#subs+1] = sub(str, i, i)
  1529.             end
  1530.             return subs
  1531.         end
  1532.  
  1533.         local strPart = ""
  1534.         local char, iter, delim
  1535.         for i = 1,#str do
  1536.             char = sub(str, i, i)
  1537.             iter = 1
  1538.             delim = select(iter, ...)
  1539.             repeat
  1540.                 if delim == char then
  1541.                     strPart = sub(strPart, 1, -1)
  1542.                     if strPart ~= "" then
  1543.                         subs[#subs+1] = strPart
  1544.                         strPart = ""
  1545.                         goto continue
  1546.                     end
  1547.                 end
  1548.                 iter = iter + 1
  1549.                 delim = select(iter, ...)
  1550.             until not delim or delim == select(-1, ...)
  1551.             strPart = strPart .. char
  1552.             ::continue::
  1553.         end
  1554.        
  1555.         if strPart ~= "" then
  1556.             subs[#subs+1] = strPart
  1557.         end
  1558.  
  1559.         return subs
  1560.     end
  1561. )
  1562. tokenizecmdstring = tokenizecmdstring or ( -- Good
  1563.     function(str)
  1564.         --remove spaces at beginning and end
  1565.         str = trim(str) .. " "
  1566.        
  1567.         local strParts = {}
  1568.         -- return if no delims found
  1569.         if not find(str, '[%s"]') then strParts[1] = str return strParts end
  1570.        
  1571.         local strPart, newPos, pos
  1572.         repeat
  1573.             strPart,newPos = match(str, '^"(.-)"%s+()', pos)
  1574.             if not strPart then
  1575.                 strPart,newPos = match(str, '([^%s]+)%s+()', pos)
  1576.             end
  1577.             pos = newPos
  1578.             strParts[#strParts+1] = strPart
  1579.         until not strPart
  1580.        
  1581.         ::returnSplits::
  1582.        
  1583.         return strParts
  1584.     end
  1585. )
  1586. updateammo = updateammo or ( -- Good
  1587.     function(objectId)
  1588.         assert(get_object_memory(objectId) ~= 0, "invalid object id")
  1589.         sync_ammo(objectId)
  1590.     end
  1591. )
  1592. writebit = writebit or write_bit and ( -- Good
  1593.     function(address, offset, bit, val)
  1594.         address = assert(tonumber(address), "bad argument #1 to 'writebit' expected number, got " .. type(address))
  1595.         if not val then
  1596.             val = assert(tonumber(bit), "bad argument #3 to 'writebit' expected number, got " .. type(bit))
  1597.             bit = assert(tonumber(offset), "bad argument #2 to 'writebit' expected number, got " .. type(offset))
  1598.             offset = 0
  1599.         else
  1600.             offset = assert(tonumber(offset), "bad argument #2 to 'writebit' expected number, got " .. type(offset))
  1601.             val = assert(tonumber(val), "bad argument #4 to 'writebit' expected number, got " .. type(val))
  1602.         end
  1603.         offset = offset + math.floor((bit+1)/8)
  1604.         safe_write(true)
  1605.         write_bit(address + offset, bit, value)
  1606.         safe_write(false)
  1607.     end
  1608. )
  1609. writebyte = writebyte or ( -- Good
  1610.     function(address, offset, value)
  1611.         address = assert(tonumber(address), "bad argument #1 to 'writebyte' expected number, got " .. type(address))
  1612.         offset = assert(tonumber(offset), "bad argument #2 to 'writebyte' expected number, got " .. type(offset))
  1613.         if not value then
  1614.             value = offset
  1615.             offset = nil
  1616.         else
  1617.             value = assert(tonumber(value), "bad argument #3 to 'writebyte' expected number, got " .. type(value))
  1618.         end
  1619.         safe_write(true)
  1620.         write_byte(address + (offset or 0), value)
  1621.         safe_write(safe_write_val)
  1622.     end
  1623. )
  1624. writechar = writechar or ( -- Good
  1625.     function(address, offset, value)
  1626.         address = assert(tonumber(address), "bad argument #1 to 'writechar' expected number, got " .. type(address))
  1627.         offset = assert(tonumber(offset), "bad argument #2 to 'writechar' expected number, got " .. type(offset))
  1628.         if not value then
  1629.             value = offset
  1630.             offset = nil
  1631.         else
  1632.             value = assert(tonumber(value), "bad argument #3 to 'writechar' expected number, got " .. type(value))
  1633.         end
  1634.         safe_write(true)
  1635.         write_char(address + (offset or 0), value)
  1636.         safe_write(safe_write_val)
  1637.     end
  1638. )
  1639. writeword = writeword or ( -- Good
  1640.     function(address, offset, value)
  1641.         address = assert(tonumber(address), "bad argument #1 to 'writeword' expected number, got " .. type(address))
  1642.         offset = assert(tonumber(offset), "bad argument #2 to 'writeword' expected number, got " .. type(offset))
  1643.         if not value then
  1644.             value = offset
  1645.             offset = nil
  1646.         else
  1647.             value = assert(tonumber(value), "bad argument #3 to 'writeword' expected number, got " .. type(value))
  1648.         end
  1649.         safe_write(true)
  1650.         write_word(address + (offset or 0), value)
  1651.         safe_write(safe_write_val)
  1652.     end
  1653. )
  1654. writeshort = writeshort or ( -- Good
  1655.     function(address, offset, value)
  1656.         address = assert(tonumber(address), "bad argument #1 to 'writeshort' expected number, got " .. type(address))
  1657.         offset = assert(tonumber(offset), "bad argument #2 to 'writeshort' expected number, got " .. type(offset))
  1658.         if not value then
  1659.             value = offset
  1660.             offset = nil
  1661.         else
  1662.             value = assert(tonumber(value), "bad argument #3 to 'writeshort' expected number, got " .. type(value))
  1663.         end
  1664.         safe_write(true)
  1665.         write_short(address + (offset or 0), value)
  1666.         safe_write(safe_write_val)
  1667.     end
  1668. )
  1669. writedword = writedword or ( -- Good
  1670.     function(address, offset, value)
  1671.         address = assert(tonumber(address), "bad argument #1 to 'writedword' expected number, got " .. type(address))
  1672.         offset = assert(tonumber(offset), "bad argument #2 to 'writedword' expected number, got " .. type(offset))
  1673.         if not value then
  1674.             value = offset
  1675.             offset = nil
  1676.         else
  1677.             value = assert(tonumber(value), "bad argument #3 to 'writedword' expected number, got " .. type(value))
  1678.         end
  1679.         safe_write(true)
  1680.         write_dword(address + (offset or 0), value)
  1681.         safe_write(safe_write_val)
  1682.     end
  1683. )
  1684. writeint = writeint or ( -- Good
  1685.     function(address, offset, value)
  1686.         address = assert(tonumber(address), "bad argument #1 to 'writeint' expected number, got " .. type(address))
  1687.         offset = assert(tonumber(offset), "bad argument #2 to 'writeint' expected number, got " .. type(offset))
  1688.         if not value then
  1689.             value = offset
  1690.             offset = nil
  1691.         else
  1692.             value = assert(tonumber(value), "bad argument #3 to 'writeint' expected number, got " .. type(value))
  1693.         end
  1694.         safe_write(true)
  1695.         write_int(address + (offset or 0), value)
  1696.         safe_write(safe_write_val)
  1697.     end
  1698. )
  1699. writefloat = writefloat or ( -- Good
  1700.     function(address, offset, value)
  1701.         address = assert(tonumber(address), "bad argument #1 to 'writefloat' expected number, got " .. type(address))
  1702.         offset = assert(tonumber(offset), "bad argument #2 to 'writefloat' expected number, got " .. type(offset))
  1703.         if not value then
  1704.             value = offset
  1705.             offset = nil
  1706.         else
  1707.             value = assert(tonumber(value), "bad argument #3 to 'writefloat' expected number, got " .. type(value))
  1708.         end
  1709.         safe_write(true)
  1710.         write_float(address + (offset or 0), value)
  1711.         safe_write(safe_write_val)
  1712.     end
  1713. )
  1714. writedouble = writedouble or ( -- Good
  1715.     function(address, offset, value)
  1716.         address = assert(tonumber(address), "bad argument #1 to 'writedouble' expected number, got " .. type(address))
  1717.         offset = assert(tonumber(offset), "bad argument #2 to 'writedouble' expected number, got " .. type(offset))
  1718.         if not value then
  1719.             value = offset
  1720.             offset = nil
  1721.         else
  1722.             value = assert(tonumber(value), "bad argument #3 to 'writedouble' expected number, got " .. type(value))
  1723.         end
  1724.         safe_write(true)
  1725.         write_double(address + (offset or 0), value)
  1726.         safe_write(safe_write_val)
  1727.     end
  1728. )
  1729. writestring = write_string or ( -- Good
  1730.     function(address, offset, str)
  1731.         address = assert(type(address) == "number" and address, "bad argument #1 to 'writestring' expected number, got '" .. type(address) .. "'")
  1732.         if str then
  1733.             offset = assert(type(offset) == "number" and offset, "bad argument #2 to 'writestring' expected number, got '" .. type(offset) .. "'")
  1734.             str = assert(type(str) == "string" and str, "bad argument #3 to 'writestring' expected string, got '" .. type(str) .. "'")
  1735.         else
  1736.             str = assert(type(offset) == "string" and offset, "bad argument #2 to 'writestring' expected string, got '" .. type(offset) .. "'")
  1737.             offset = nil
  1738.         end
  1739.         address = address + (offset or 0x0)
  1740.         local byte_table = {}
  1741.         for char in gmatch(str, '.') do
  1742.             byte_table[#byte_table+1] = byte(char)
  1743.         end
  1744.         local length = #byte_table
  1745.         safe_write(true)
  1746.         for i = 0,length-1 do
  1747.             writebyte(address + i, byte_table[i+1])
  1748.         end
  1749.         safe_write(safe_write_val)
  1750.     end
  1751. )
  1752. writewidestring = write_wide_string or ( -- Good
  1753.     function(address, offset, str)
  1754.         address = assert(type(address) == "number" and address, "bad argument #1 to 'writewidestring' expected number, got '" .. type(address) .. "'")
  1755.         if str then
  1756.             offset = assert(type(offset) == "number" and offset, "bad argument #2 to 'writewidestring' expected number, got '" .. type(offset) .. "'")
  1757.             str = assert(type(str) == "string" and str, "bad argument #3 to 'writewidestring' expected string, got '" .. type(str) .. "'")
  1758.         else
  1759.             str = assert(type(offset) == "string" and offset, "bad argument #2 to 'writewidestring' expected string, got '" .. type(offset) .. "'")
  1760.             offset = nil
  1761.         end
  1762.         address = address + (offset or 0x0)
  1763.         local byte_table = {}
  1764.         for char in gmatch(str, '.') do
  1765.             byte_table[#byte_table+1] = byte(char)
  1766.         end
  1767.         local length = #byte_table
  1768.         safe_write(true)
  1769.         for i = 0,length*2 do
  1770.             writeword(address + i, 0)
  1771.         end
  1772.         safe_write(safe_write_val)
  1773.     end
  1774. )
  1775.  
  1776. -- Definitions for All Sapp Functions:
  1777. assign_weapon = assign_weapon or ( -- Good
  1778.     function(objectId, playerIndex)
  1779.         local playerId = rresolveplayer(playerIndex)
  1780.         return playerId and assignweapon(playerId, objectId)
  1781.     end
  1782. )
  1783. camo = camo or ( -- Good
  1784.     function(playerIndex, duration)
  1785.         local playerId = rresolveplayer(playerIndex)
  1786.         return playerId and applycamo(playerId, duration / 30)
  1787.     end
  1788. )
  1789. cprint = cprint or function(a) hprintf(a) end -- Good
  1790. destroy_object = destroy_object or ( -- Good
  1791.     function(objId)
  1792.         if getobject(objId) then destroyobject(objId) end
  1793.     end
  1794. )
  1795. drop_weapon = drop_weapon or ( -- Workaround
  1796.     function(playerIndex)
  1797.         local m_playerObj = getobject(getplayerobjectid(rresolveplayer(playerIndex)))
  1798.         if m_playerObj then
  1799.             destroyobject(readdword(m_playerObj + 0x118))
  1800.         end
  1801.     end
  1802. )
  1803. enter_vehicle = enter_vehicle or ( -- Good
  1804.     function(objectId, playerIndex, seat)
  1805.         local playerId = rresolveplayer(playerIndex)
  1806.         if playerId then entervehicle(playerId, objectId, seat) end
  1807.     end
  1808. )
  1809. execute_command = execute_command or ( -- Good
  1810.     function(command, playerIndex)
  1811.         local playerId = rresolveplayer(playerIndex)
  1812.         if events[cb.EVENT_ECHO][1] then
  1813.             local response = playerId and svcmdplayer(command, playerId, true) or svcmd(command, true)
  1814.             if type(response) == "table" then
  1815.                 for i = 1,#response do
  1816.                     ypcall(_G[events[cb.EVENT_ECHO][1]], 0, response[i])
  1817.                 end
  1818.             end
  1819.         elseif playerId then svcmdplayer(command, playerId, true)
  1820.         else svcmd(command, true)
  1821.         end
  1822.     end
  1823. )
  1824. exit_vehicle = exit_vehicle or ( -- Good
  1825.     function(playerIndex)
  1826.         local playerId = rresolveplayer(playerIndex)
  1827.         if playerId then exitvehicle(playerId) end
  1828.     end
  1829. )
  1830. get_dynamic_player = get_dynamic_player or ( -- Good
  1831.     function(playerIndex)
  1832.         local playerId = rresolveplayer(playerIndex)
  1833.         local playerObjId = playerId and getplayerobjectid(playerId)
  1834.         return playerObjId and getobject(playerObjId) or 0
  1835.     end
  1836. )
  1837. get_object_memory = get_object_memory or ( -- Good
  1838.     function(objectId)
  1839.         return objectId and getobject(objectId) or 0
  1840.     end
  1841. )
  1842. get_player = get_player or ( -- Good
  1843.     function(playerIndex)
  1844.         local playerId = rresolveplayer(playerIndex)
  1845.         return playerId and getplayer(playerId) or 0
  1846.     end
  1847. )
  1848. get_var = get_var or ( -- Some variables don't exist in Phasor.
  1849.     function(playerIndex, var)
  1850.         playerIndex = assert(tonumber(playerIndex), "bad argument #1 to 'get_var' expected number, got " .. type(playerIndex))
  1851.         var = lower(var)
  1852.         if var == "$n" then
  1853.             return playerIndex
  1854.         elseif var == "$name" then
  1855.             return getname(rresolveplayer(playerIndex))
  1856.         elseif var == "$hash" then
  1857.             return gethash(rresolveplayer(playerIndex))
  1858.         elseif var == "$ip" then
  1859.             local playerId = rresolveplayer(playerIndex)
  1860.             return getip(playerId) .. ":" .. getport(playerId)
  1861.         elseif var == "$tk" then
  1862.             local m_player = getplayer(rresolveplayer(playerIndex))
  1863.             return readshort(m_player + 0xAC) - readshort(m_player + 0xAE)
  1864.         elseif var == "$kills" then
  1865.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0x9C)
  1866.         elseif var == "$assists" then
  1867.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0xA4)
  1868.         elseif var == "$deaths" then
  1869.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0xAE)
  1870.         elseif var == "$suicides" then
  1871.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0xB0)
  1872.         elseif var == "$streak" then
  1873.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0x96)
  1874.         elseif var == "$combo" then
  1875.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0x98)
  1876.         elseif var == "$score" then
  1877.             return readshort(getplayer(rresolveplayer(playerIndex)) + 0xC8)
  1878.         elseif var == "$botscore" then
  1879.         elseif var == "$afk" then
  1880.         elseif var == "$ping" then
  1881.             return readdword(getplayer(rresolveplayer(playerIndex)) + 0xDC)
  1882.         elseif var == "$x" then
  1883.             return readfloat(getplayer(rresolveplayer(playerIndex)) + 0xF8)
  1884.         elseif var == "$y" then
  1885.             return readfloat(getplayer(rresolveplayer(playerIndex)) + 0xFC)
  1886.         elseif var == "$z" then
  1887.             return readfloat(getplayer(rresolveplayer(playerIndex)) + 0x100)
  1888.         elseif var == "$hp" then
  1889.             return readfloat(getplayer(rresolveplayer(playerIndex)) + 0xE0)
  1890.         elseif var == "$sh" then
  1891.             return readfloat(getplayer(rresolveplayer(playerIndex)) + 0xE4)
  1892.         elseif var == "$invis" then
  1893.             return readword(getplayer(rresolveplayer(playerIndex)) + 0x68) > 0 and 1 or 0
  1894.         elseif var == "$team" then
  1895.             return getteam(playerId)
  1896.         elseif var == "$oteam" then
  1897.             return abs(getteam(playerId)-1)
  1898.         elseif var == "$lvl" then
  1899.             return getadminlvl(playerId)
  1900.         elseif var == "$map" then
  1901.             return _GAME == "PC" and readstring(0x698F21) or readstring(0x61D151)
  1902.         elseif var == "$mode" then
  1903.             local gt = _GAME == "PC" and readbyte(0x671340 + 0x30) or readbyte(0x5F5498 + 0x30)
  1904.             return gt == 1 and "ctf" or gt == 2 and "slayer" or gt == 3 and "koth" or gt == 4 and "oddball" or gt == 5 and "race"
  1905.         elseif var == "$gt" then
  1906.             return _GAME == "PC" and readwidestring(0x671340 + 0x2C) or readwidestring(0x5F5498 + 0x2C)
  1907.         elseif var == "$ffa" then
  1908.             return _GAME == "PC" and readbyte(0x671340 + 0x34) or readbyte(0x5F5498 + 0x34)
  1909.         elseif var == "$svname" then
  1910.             return getservername()
  1911.         elseif var == "$pn" then
  1912.             local counter = 0
  1913.             for playerId = 0,15 do
  1914.                 if getplayer(playerId) then
  1915.                     counter = counter + 1
  1916.                 end
  1917.             end
  1918.             return counter
  1919.         elseif var == "$reds" then
  1920.             return getteamsize(0)
  1921.         elseif var == "$blues" then
  1922.             return getteamsize(1)
  1923.         elseif var == "$rand" then
  1924.             return getrandomnumber(1, 17)
  1925.         elseif var == "$game" then
  1926.             return _GAME
  1927.         end
  1928.         return "Variable doesn't exist on Phasor, sorry!"
  1929.     end
  1930. )
  1931. lookup_tag = lookup_tag or (
  1932.     function(a,b)
  1933.         for i=0,(tag_table_count - 1),0x20 do
  1934.             if a == readdword(0x40440034+i) or a == readstring(0x40440028+i, 4) and b == readstring(readdword(0x40440038+i)) then
  1935.                 return 0x40440028+i
  1936.             end
  1937.         end
  1938.     end
  1939. )
  1940. sappkill = _SERVERAPP == "Sapp" and kill or function(playerIndex) kill(to_real_index(playerIndex)) end -- Annoying.
  1941. intersect = intersect or ( -- Good
  1942.     function(x, y, z, vx, vy, vz, objectId)
  1943.         return halointersect(1, x, y, z, vx, vy, vz, objectId)
  1944.     end
  1945. )
  1946. player_present = player_present or function(playerIndex) return not not rresolveplayer(playerIndex) end -- Good
  1947. rand = rand or getrandomnumber -- Good
  1948. read_bit = read_bit or readbit -- Good
  1949. read_byte = read_byte or readbyte -- Good
  1950. read_char = read_char or readchar -- Good
  1951. read_word = read_word or readword -- Good
  1952. read_short = read_short or readshort -- Good
  1953. read_dword = read_dword or readdword -- Good
  1954. read_int = read_int or readint -- Good
  1955. read_float = read_float or readfloat -- Good
  1956. read_double = read_double or readdouble -- Good
  1957. read_string = read_string or ( -- Good
  1958.     function(address, length)
  1959.         address = type(address) == "number" and address or error("bad argument #1 to 'readstring' expected number, got '" .. type(address) .. "'")
  1960.         if length then
  1961.             length = type(length) == "number" and length or error("bad argument #2 to 'readstring' expected number, got '" .. type(length) .. "'")
  1962.         else
  1963.             length = length or 256
  1964.         end
  1965.         local char_table = {}
  1966.         local newByte
  1967.         for i = 0,length-1 do
  1968.             newByte = readbyte(address + i)
  1969.             if newByte == 0 or newByte == 255 then break end
  1970.             char_table[#char_table+1] = char(newByte)
  1971.         end
  1972.         return concat(char_table)
  1973.     end
  1974. )
  1975. read_vector3d = read_vector3d or ( -- Good
  1976.     function(address)
  1977.         return readfloat(address),readfloat(address+4),readfloat(address+8)
  1978.     end
  1979. )
  1980. read_wide_string = read_wide_string or ( -- Good
  1981.     function(address, length)
  1982.         address = type(address) == "number" and address or error("bad argument #1 to 'readwidestring' expected number, got '" .. type(address) .. "'")
  1983.         if length then
  1984.             length = type(length) == "number" and length or error("bad argument #2 to 'readwidestring' expected number, got '" .. type(length) .. "'")
  1985.         else
  1986.             length = length or 51001
  1987.         end
  1988.         local char_table = {}
  1989.         local newByte
  1990.         for i = 0,length-1,2 do
  1991.             newByte = readbyte(address + i)
  1992.             if newByte == 0 or newByte == 255 or readbyte(address + i+1) ~= 0 then break end
  1993.             char_table[#char_table+1] = char(newByte)
  1994.         end
  1995.         return concat(char_table)
  1996.     end
  1997. )
  1998. -- register_callback will ALWAYS take priority over functions that Phasor calls by default
  1999. -- This means that if you have a function named 'OnTeamChange' in your script, it will be treated as a Phasor function and will pass the default Phasor arguments because it is a phasor event function.
  2000. -- However, if you do 'register_callback(cb.EVENT_TEAM_SWITCH, "OnTeamChange"), now it will be treated like a Sapp event function, and will be called with a playerIndex only. So be careful.
  2001. register_callback = function(event, funcname)
  2002.     local internalEvent = phasorEvents[funcname]
  2003.     if internalEvent then
  2004.         if type(internalEvent) == "function" then
  2005.             _G["__" .. funcname] = internalEvent
  2006.             if internalEvent == _G[funcname] then
  2007.                 _G[funcname] = nil
  2008.             end
  2009.         end
  2010.         funcname = "__" .. funcname
  2011.     end
  2012.     local thisEvent = events[event]
  2013.     assert(thisEvent, "Invalid event passed to 'register_event'")
  2014.     events.Create(thisEvent, event, funcname)
  2015. end
  2016. rprint = rprint or ( -- Good
  2017.     function(playerIndex, message)
  2018.         sendconsoletext(rresolveplayer(playerIndex), message)
  2019.     end
  2020. )
  2021. local __safe_read = safe_read
  2022. local __safe_write = safe_write
  2023. safe_read = safe_read and ( -- Phasor does not have this.
  2024.     function(bool)
  2025.         safe_read_val = not not bool
  2026.         __safe_read(safe_read_val)
  2027.     end
  2028. )
  2029. safe_write = safe_write and ( -- Phasor does not have this.
  2030.     function(bool)
  2031.         safe_write_val = not not bool
  2032.         __safe_write(safe_write_val)
  2033.     end
  2034. )
  2035. say = say -- Good
  2036. say_all = say_all or __say -- Good
  2037. sig_scan = sig_scan -- Phasor does not have this.
  2038. spawn_object = spawn_object or ( -- Good
  2039.     function(tagtype, tagname, x, y, z, rot, mapId)
  2040.         mapId = tagtype and tagname and gettagid(tagtype, tagname) or mapId
  2041.         return createobject(mapId or gettagid(tagtype, tagname), 0, 0x7FFF, false, x, y, z) or 0
  2042.     end
  2043. )
  2044. sync_ammo = sync_ammo or function(objectId) if getobject(objectId) then updateammo(objectId) end end -- Good
  2045. timer = timer or ( -- Good
  2046.     function(delay, funcname, ...)
  2047.         local args = {...}
  2048.         for i = 1,#args do
  2049.             args[i] = tostring(args[i]) -- all sapp arguments are actually passed as strings
  2050.         end
  2051.         _G[funcname .. "_overhead"] = (
  2052.             function()
  2053.                 return ypcall(_G[funcname], unpack(args))
  2054.             end
  2055.         )
  2056.         registertimer(delay, funcname .. "_overhead", args)
  2057.     end
  2058. )
  2059. to_player_index = to_player_index or resolveplayer and ( -- Good
  2060.     function(playerId)
  2061.         return resolveplayer(playerId) or 0
  2062.     end
  2063. ) or error("Functions 'to_player_index' and 'resolveplayer' not found. What server app are you even using?")
  2064. to_real_index = to_real_index or rresolveplayer and ( -- Good
  2065.     function(playerIndex)
  2066.         return rresolveplayer(playerIndex) or -1
  2067.     end
  2068. ) or error("Functions 'to_real_index' and 'rresolveplayer' not found. What server app are you even using?")
  2069. write_bit = writebit -- Good
  2070. write_byte = write_byte or writebyte -- Good
  2071. write_char = write_char or writechar -- Good
  2072. write_word = write_word or writeword -- Good
  2073. write_short = write_short or writeshort -- Good
  2074. write_dword = write_dword or writedword -- Good
  2075. write_int = write_int or writeint -- Good
  2076. write_float = write_float or writefloat -- Good
  2077. write_double = write_double or writedouble -- Good
  2078. write_string = write_string or ( -- Good
  2079.     function(address, offset, str)
  2080.         address = type(address) == "number" and address or error("bad argument #1 to 'writestring' expected number, got '" .. type(address) .. "'")
  2081.         if str then
  2082.             offset = type(offset) == "number" and offset or error("bad argument #2 to 'writestring' expected number, got '" .. type(offset) .. "'")
  2083.             str = type(str) == "string" and str or error("bad argument #3 to 'writestring' expected string, got '" .. type(str) .. "'")
  2084.         else
  2085.             str = type(offset) == "string" and offset or error("bad argument #2 to 'writestring' expected string, got '" .. type(offset) .. "'")
  2086.             offset = nil
  2087.         end
  2088.         address = address + (offset or 0x0)
  2089.         local byte_table = {}
  2090.         for char in gmatch(str, '.') do
  2091.             byte_table[#byte_table+1] = byte(char)
  2092.         end
  2093.         local length = #byte_table
  2094.         for i = 0,length-1 do
  2095.             writebyte(address + i, byte_table[i+1])
  2096.         end
  2097.     end
  2098. )
  2099. write_vector3d = write_vector3d or (
  2100.     function(address, a, b, c)
  2101.         writefloat(address,   a)
  2102.         writefloat(address+4, b)
  2103.         writefloat(address+8, c)
  2104.     end
  2105. )
  2106. write_wide_string = write_wide_string or ( -- Good
  2107.     function(address, offset, str)
  2108.         address = type(address) == "number" and address or error("bad argument #1 to 'writewidestring' expected number, got '" .. type(address) .. "'")
  2109.         if str then
  2110.             offset = type(offset)  == "number" and offset or error("bad argument #2 to 'writewidestring' expected number, got '" .. type(offset) .. "'")
  2111.             str = type(str)  == "string" and str or error("bad argument #3 to 'writewidestring' expected string, got '" .. type(str) .. "'")
  2112.         else
  2113.             str = type(offset) == "string" and offset or error("bad argument #2 to 'writewidestring' expected string, got '" .. type(offset) .. "'")
  2114.             offset = nil
  2115.         end
  2116.         address = address + (offset or 0x0)
  2117.         local byte_table = {}
  2118.         for char in gmatch(str, '.') do
  2119.             byte_table[#byte_table+1] = byte(char)
  2120.         end
  2121.         local length = #byte_table
  2122.         for i = 0,length*2 do
  2123.             writeword(address + i, 0)
  2124.         end
  2125.     end
  2126. )
  2127.  
  2128. local OnScriptLoad2 = OnScriptLoad
  2129. function OnScriptLoad(process, game, persistent)
  2130.     if _SERVERAPP == "Sapp" then
  2131.         registerPhasorEvents()
  2132.     end
  2133.     ypcall(OnScriptLoad2, process or pid, game or halo_type or _GAME, persistent == nil or persistent)
  2134. end
  2135.  
  2136. collectgarbage() -- No doubt there's tons of functions and variables to be cleaned up since this script overrided most of them.
  2137. _G.kill = nil -- Been renamed, keep it out of the global table in case of accidents.
  2138.  
  2139. api_version = sapp_version
  2140.  
  2141. return _G
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement