Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
-- Tank Block Example required_version = 200 function OnNewGame(map) cur_map = map -- Create global variable for map. if map == "deathisland" then -- Create GEOs. anti_tank_red = GEO.newRectPrism("no_tank_red", 4, 18, 3, -27.2, -7.6, 9.6) -- Anti-Tank Red Base anti_tank_blue = GEO.newRectPrism("no_tank_blue", 4, 18, 3, 29.8, 16, 8.4) -- Anti-Tank Blue Base end end -- OnObjectCreation is important for monitoring non-player objects. -- If you want OnGeoEnter and OnGeoExit to work for a non-player object, you must monitor them. function OnObjectCreation(objId) -- Get the TagType and TagName of the object being created. local mapId = readdword(getobject(objId)) local tagname, tagtype = gettaginfo(mapId) -- If this map is Death Island... if cur_map == "deathisland" then -- If this object is a scorpion... if tagtype == "vehi" and tagname == "vehicles\\scorpion\\scorpion_mp" then -- Make anti_tank_red and anti_tank_blue monitor for it. anti_tank_red:monitor(objId) anti_tank_blue:monitor(objId) end end end -- GEO 2.3.2 (Geometric Environment Objects) function OnGeoEnter(geo, player, objId) -- If this map is Death Island... if cur_map == "deathisland" then -- If this geo is either Anti-Tank Red Base or Anti-Tank Blue Base... if geo == anti_tank_red or geo == anti_tank_blue then -- Get mapId of a scorpion local mapId = gettagid("vehi", "vehicles\\scorpion\\scorpion_mp") -- Check if the object entering the GEO has the same mapId as a scorpion. if readdword(getobject(objId)) == mapId then -- Block it from entering. return false end end end end function OnGeoExit(geo, player, objId) return true end --[[ Documentation: This script allows the creation of environmental volumes in the shapes of spheres, rectangular prisms, cylinders, rectangles, or circles. These environmental volumes allow you to create complex environments with just a few lines of code, including the ability to make a volume a killzone, in which players will immediately die upon entering the volume or any user-defined actions as defined by the functions OnGeoEnter and OnGeoExit. GEOs can be returned and manipulated as objects in Lua; this means you can set a variable to be equal to a GEO, making it easy to manipulate in various areas of code. Changes from GEOs for Phasor 058 and GEOs for 2.0: -- GEO:damagezone now has the following function header: GEO:damagezone(boolean, damage). -- GEO:freeze has been changed to GEO:unfollow. Changes in GEO 2.2: -- Players are now automatically monitored for every GEO. If you want a GEO to monitor other objects, you still need to use GEO:monitor. -- Support for cylinder orientation. You can now orient your cylinder along the x, y, or z axis. -- Added GEO.clear() to destroy all GEOs. -- Added GEO:antigeo(); an AntiGEO subtracts from the volume of another GEO. This allows for you to create complex geometry beyond only spheres, cylinders, and rectangular prisms. Read docs for more info. -- GEO:killzone() improved; now takes three arguments: <boolean> <delay> <kill_message> -- GEO:surface() now works; use this to show 3D representations of your GEOs. -- GEO:perimeter() and GEO:surface create objects which are unaffected by physics. -- Returning false in OnGeoEnter and OnGeoExit now works on non-player objects. -- Various bug fixes Changes in GEO 2.3.1: -- GEO:killzone() further improved; now takes infinite arguments: <boolean> <delay> <kill_message> <function> <args...> -- GEO:damagezone() improved; now takes infinite arguments: <boolean> <damage> <delay> <damage_message> <function> <args...> -- GEO:surface() fixed for rectangular prisms (performance should be better too), spheres (the rings are now more uniform), and cylinders (the base of the cylinder was sometimes drawn too high) -- Added GEO:vectorintersect(); returns the points at which a vector (given by two points) intersects the given GEO (does not take AntiGEOs into account yet). Arguments: <point1>, <point2> -- Added GEO:containspoint(); returns a boolean (true or false) if the specified GEO contains the specified point. Arguments: <point> -- Added GEO:randomcoords(); returns random coordinates within the specified GEO (does not take AntiGEOs into account yet). No arguments. -- Fixed a terrible handling of AntiGEOs (now uses GEO:contains() like it should have in the first place) GEO Creation Functions: GEO.newSphere(name, radius, x_coord, y_coord, z_coord) -- name: <string> Name of this new GEO (must be unique). -- radius: <float> Radius of this sphere. -- x_coord: <float> X-coordinate of the center of this sphere. -- y_coord: <float> Y-coordinate of the center of this sphere. -- z_coord: <float> Z-coordinate of the center of this sphere. Example: local sphere = GEO.newSphere("Sphere1", 5, 0, 0, 0) Notes: GEO.newSphere creates a spherical GEO with the specified name (keep in mind GEO names must be unique from each other), radius, and x, y, and z-coordinates of the center of the sphere. Returns the sphere as an object. GEO.newRectPrism(name, x_length, y_length, z_length, x_coord, y_coord, z_coord) -- name: <string> Name of this new GEO (must be unique). -- x_length: <float> Length of this rectangular prism in the X direction. -- y_length: <float> Length of this rectangular prism in the Y direction. -- z_length: <float> Length of this rectangular prism in the Z direction. -- x_coord: <float> X-coordinate of the center of this rectangular prism. -- y_coord: <float> Y-coordinate of the center of this rectangular prism. -- z_coord: <float> Z-coordinate of the center of this rectangular prism. Example: local rectprism = GEO.newRectPrism("RectPrism1", 3, 3, 10, 0, 0, 5) Notes: GEO.newRectPrism creates a rectangular prism GEO with the specified name (keep in mind GEO names must be unique from each other), x, y, and z lengths, and x, y, and z-coordinates of the center of the rectangular prism. Returns the rectangular prism as an object. GEO.newCylinder(name, radius, height, x_coord, y_coord, z_coord, [orientation]) -- name: <string> Name of this new GEO (must be unique). -- radius: <float> Radius of this cylinder. -- height: <float> Height of this cylinder. -- x_coord: <float> X-coordinate of the center of this cylinder. -- y_coord: <float> Y-coordinate of the center of this cylinder. -- z_coord: <float> Z-coordinate of the center of this cylinder. -- orientation: <string> Axis of orientation ("x", "y", or "z") (default = "z"). Example: local cylinder = GEO.newCylinder("Cylinder1", 3, 10, 0, 0, 0) Notes: GEO.newCylinder creates a cylindrical GEO with the specified name (keep in mind GEO names must be unique from each other), radius, height, and x, y, and z-coordinates of the center of the cylinder. Returns the cylinder as an object. GEO.newRect(name, width, height, x_coord, y_coord, z_coord, [orientation]) -- name: <string> Name of this new GEO (must be unique). -- width: <float> Width of this rectangle. -- height: <float> Height of this rectangle. -- x_coord: <float> X-coordinate of the center of this rectangle. -- y_coord: <float> Y-coordinate of the center of this rectangle. -- z_coord: <float> Z-coordinate of the center of this rectangle. -- orientation: <string> Axis of orientation ("x", "y", or "z") (default = "z"). Example: local rectangle = GEO.newRect("Rect1", 5, 10, 0, 0, 5, "x") Notes: GEO.newRect creates a rectangular GEO with the specified name (keep in mind GEO names must be unique from each other), width, height, x, y, and z-coordinates of the center of the rectangle, and orientation. The orientation specifies which axis ("x", "y", or "z") has a length of 0 in the rectangle. For example, by default, orientation is "z". This means you would see the rectangle if you were looking down on top of it (or up from underneath). You can also think of the orientation axis as being the axis that punches through the center of the object. GEO.newCircle(name, radius, x_coord, y_coord, z_coord, [orientation]) -- name: <string> Name of this new GEO (must be unique). -- radius: <float> Radius of this circle. -- x_coord: <float> X-coordinate of the center of this circle. -- y_coord: <float> Y-coordinate of the center of this circle. -- z_coord: <float> Z-coordinate of the center of this circle. -- orientation: <string> Axis of orientation ("x", "y", or "z") (default = "z") Example: local circle = GEO.newCircle("Circle1", 10, 0, 0, 5, "x") Notes: GEO.newCircle creates a circular GEO with the specified name (keep in mind GEO names must be unique from each other), radius, x, y, and z-coordinates of the center of the circle, and orientation. The orientation specifies which axis ("x", "y", or "z") has a length of 0 in the circle. For example, by default, orientation is "z". This means you would see the circle if you were looking down on top of it (or up from underneath). You can also think of the orientation axis as being the axis that punches through the center of the object. Once you've created your GEO, you want to make it do something. The following are GEO-editing functions. Note that the following functions are members of the GEO metatable. This means to call the function, you specify the GEO variable before the function (separated by a colon). See the functions below for more specific examples. GEO Editing Functions: GEO:delete() Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) sphere:delete() Notes: Deletes the specified GEO. GEO:move(x_coord, y_coord, z_coord) -- x_coord: <float> New x-coordinate of the center of this GEO. -- y_coord: <float> New y-coordinate of the center of this GEO. -- z_coord: <float> New z-coordinate of the center of this GEO. Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) sphere:move(0, 0, 10) Notes: Moves the center of the specified GEO to the specified x, y, and z-coordinates. GEO:radius([new_radius]) -- new_radius: <float> New radius of specified GEO (if no radius is specified, the radius of the GEO is returned). Example: local cylinder = GEO.newCylinder("Cylinder", 10, 20, 0, 0, 0) local cyl_radius = cylinder:radius() if cyl_radius < 20 then cylinder:radius(20) end Notes: If a new_radius is specified, changes the radius of the specified GEO to the value of new_radius. Otherwise, returns the radius of the specified GEO. Note that this can only be used for spheres, circles, and cylinders. GEO:size([x_length], [y_length], [z_length]) -- x_length: <float> New length of GEO in the x direction. -- y_length: <float> New length of GEO in the y direction. -- z_length: <float> New length of GEO in the z direction. -- Read the notes for descriptions about how the optional parameters work in this function. Example: -- Create three GEOs local rectprism = GEO.newRectPrism("RectPrism", 5, 5, 10, 0, 0, 5) local rectangle = GEO.newRect("Rect", 5, 10, 0, 0, 5, "y") local cylinder = GEO.newCylinder("Cylinder", 5, 20, 0, 0, 10) -- Get sizes of all three shapes local rpx, rpy, rpz = rectprism:size() local rw, rh = rectangle:size() local cyl_height = cylinder:size() -- Double their sizes rectprism:size(rpx * 2, rpy * 2, rpz * 2) rectangle:size(rw * 2, 0, rh * 2) cylinder:size(cyl_height * 2) Notes: If any coordinate is specified, changes the GEO's size in the x, y, and z directions respectively. If no coordinate is specified in any direction, this returns the size of the object. Note this can only be used for rectangular prisms, rectangles, and cylinders. Also note if you're attempting to retrieve the size of an object, rectangular prisms will return three values (x, y, and z), rectangles will return two values (width and height), and cylinders will return one value (height). Also note that when changing the height of a cylinder, you need only specify one number (since you're only changing the height). If you're trying to change the size of a rectangle, keep its orientation in mind when changing the x, y, and z lengths (changes in length of the axis of which the rectangle is oriented will be ignored). GEO:contains(objId) objId: <object id> Object being tested to see if it is inside of the specfied GEO. Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) function OnPlayerSpawn(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) if sphere:contains(objId) then say(getname(player) .. " has spawned inside of the sphere") end end Notes: Checks if the specified objId is within the specified GEO. Returns true or false. GEO:containspoint(point) point: <table> Coordinates being checked. Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) local point = {10, 10, 0} local insphere = GEO:containspoint(point) if insphere(point) then say("(10, 10, 0) is in the sphere!") end Notes: Make sure the table passed is in {x, y, z} format. GEO:vectorintersect(pointA, pointB) pointA: <table> First point in vector. pointB: <table> Second point in vector. Example: -- This is a poor example that shows simply functionality sphere = GEO.newSphere("sphere", 5, 0, 0, 0) function OnPlayerSpawn(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) local x, y, z = getobjectcoords(objId) local point1, point2 = sphere:vectorintersect({x, y, z}, {x, y, z + 10}) -- This will check if the line between where the player is standing and 10 units above them ever intersects the sphere. if point1 then say("x: " .. point1[1] .. " y: " .. point1[2] .. " z: " .. point1[3]) end if point2 then say("x: " .. point2[1] .. " y: " .. point2[2] .. " z: " .. point2[3]) end end Notes: This function can return as many as two intersection points and as few as zero. If a point does not exist, this function returns nil for that point. This function does not yet take AntiGEOs into account. Make sure the tables for the points passed are in {x, y, z} format. GEO:follow(objId) objId: <object id> Object this GEO should follow. Example: function OnPlayerSpawn(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) -- Create a sphere with the objId in the name so you know it is unique local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0) sphere:follow(objId) end Notes: Sets a GEO to follow the specified objId. The GEO will be automatically deleted if the object it is following has also been deleted. GEO:unfollow() Example: function OnPlayerSpawn(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) -- Create a sphere with the objId in the name so you know it is unique local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0) sphere:follow(objId) sphere:unfollow() end Notes: Tells the specified GEO to stop following the objId it is currently following. GEO:velocity(x_velocity, y_velocity, z_velocity) x_velocity: <float> GEO's velocity in the x direction. y_velocity: <float> GEO's velocity in the y direction. z_velocity: <float> GEO's velocity in the z direction. Example: local rectangle = GEO.newRectPrism("RectPrism", math.inf, math.inf, 100, 0, 0, -50) rectangle:velocity(0, 0, 0.1) Notes: Sets the velocity of the specified GEO in the x, y, and z directions. GEO:killzone([boolean], [delay], [kill_message], [func], [args...]) boolean: <boolean> The ability of this GEO to be a killzone (if no boolean is specified, the current killzone boolean is returned). delay: <int> The time (in seconds) the GEO should wait to kill a player after they enter. kill_message: <string> The message a player will receive when they are killed by this GEO. func: <function> A special function that MUST return true or false and MUST pass the GEO, then player as its first two arguments. args...: <data> Additional arguments to be passed into the function. Example: -- Kill a player immediately for entering a sphere local killsphere = GEO.newSphere("Sphere", 10, 0, 0, 0) killsphere:killzone(true) function isredwednesday(geo, player, day) if getteam(player) == 0 then if day == "Wednesday" then return true end end return false end -- Kill a player after being in a cube for 5 seconds if they're on the Red Team and today is Wednesday. local killcube = GEO.newRectPrism("Cube", 5, 5, 5, 10, -10, 5) killcube:killzone(true, 5, "Since you're on the red team and were in this cube for five seconds and today is a Wednesday, you shall now die.", isredwednesday, os.date("%A")) Notes: Toggles the ability for a GEO to be a killzone. If a function is specified, the function header's first two arguments MUST be the geo, then the player (such as in the example above) and returns true if the player should be killed and false if the player should not be. If a GEO is a killzone and no delay is specified or the delay = 0, any player to enter the GEO will automatically die. If a delay is specified, the player will be killed after the amount of seconds specified by delay. If a kill_message is specified, the player will receive that message when they die. Otherwise, no message will be sent. GEO:damagezone([boolean], [damage], [delay], [damage_message], [func], [args...]) boolean: <boolean> Indicates whether or not this GEO is a damagezone (if no boolean is specified, the current damagezone boolean is returned). damage: <float> Amount of damage per second this GEO does to a player within it. delay: <int> The time (in seconds) the GEO should wait to damage a player after they enter. damage_message: <string> The message a player will receive when they are initially damaged by this GEO. func: <function> A special function that MUST return true or false and MUST pass the GEO, then player as its first two arguments. args...: <data> Additional arguments to be passed into the function. Example: -- Damage a player as soon as they enter this sphere. local damagesphere = GEO.newSphere("Sphere", 10, 0, 0, 0) damagesphere:damagezone(true, 10) -- Damage a player after 10 seconds if they are named Nuggets and there is a GEO called "Sphere". function isnuggetssphere(geo, player, sphere_exists) if getname(player) == "Nuggets" then if sphere_exists then return true end end return false end local damagecylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 5) damagecylinder:damagezone(true, 50, 10, "Your name is Nuggets and there is a sphere somewhere around here.", isnuggetssphere, GEO.get("Sphere")) Notes: Toggles the ability for a GEO to be a damagezone. If a GEO is a damagezone, the player will be damaaged at the rate you specify. GEO:face(orientation, direction) orientation: <string> The axis on which the face will be created ("x", "y", or "z"). direction: <string> The specification of the "top" or "bottom" face in the specified orientation ("+" or "-"). Example: local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 5) local topcircle = cylinder:face("z", "+") local bottomcircle = cylinder:face("z", "-") Notes: Cuts the face of the specified three-dimensional GEO off to create a two-dimensional GEO given the orientation ("x", "y", or "z") and direction ("+" or "-"). For example, if the orientation is "z" and the direction is "+", and you're passing a rectangular prism, you will end up with the a rectangle with the same position and size as the top face of your rectangular prism. Note you can only use this for rectangular prisms and cylinders. Also note that for cylinders, you may only use the "z" orientation. Returns the new two-dimensional GEO as an object. GEO:extend(orientation, direction, amount) orientation: <string> The axis on which the face will be extended ("x", "y", or "z"). direction: <string> The specification of the "top" or "bottom" face in the specified orientation ("+" or "-"). amount: <float> Distance the specified face will be extended. Example: local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 5) cylinder:extend("z", "+", 10) Notes: Extends the specified face by the specified amount (see the function face for how to specify orientation and direction). Note that this may only be used on rectangular prisms, rectangles, and cylinders. Also note that extending a face does not change the object's center. If you use GEO:surface() after using GEO:extend(), you will not see the changes GEO:extend() has made. GEO:antigeo([boolean, geos...]) boolean: <boolean> Toggles whether or not this is an AntiGEO. geos...: <data> Defines for which GEOs this is an AntiGEO (infinite number of argumnets). Example: -- Battle Creek Blue Base Roof blue_base_roof = GEO.newRectPrism("blue_roof", 9.5, 7.8, 1.3, 1.95, 13.9, 1.85) blue_roof_anti = GEO.newRectPrism("blue_roof_anti", 10, 10, 2, 28.75, 14, 1.5) -- Cut out the section of the blue_base_roof GEO that is inside of the room where the CTF flag is blue_roof_anti:antigeo(true, blue_base_roof) Notes: This function works like object subtraction in CAD programs. If you are unfamiliar with this, this link should help describe it: http://codevisually.com/wp-content/uploads/2011/12/cvdec1_06.jpg (look at the a.subtract(b) picture). If you are within a GEO and enter one of its AntiGEOs, it will count as exiting the first GEO. Keep in mind that AntiGEOs are also GEOs and may have their own AntiGEOs. If no boolean or GEOs are specified, this returns a boolean (true or false) describing if this GEO is an AntiGEO. When using GEO:surface() or GEO:perimeter on a GEO, all of that GEO's AntiGEOs will be shown as well with Overshield powerups. GEO:copy([name]) name: <string> Name given to the copy of the specified GEO (if no name is specified, a default name is given). Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) local sphere2 = sphere:copy() Notes: Returns a copy of the specified GEO with the specified name. If no name is specified, a default name will be given. GEO:monitor(objId) objId: <object id> The object this GEO should monitor for entering/exiting. Example: local rectprism = GEO.newRectPrism("RectPrism", math.inf, math.inf, 100, 0, 0, -50) function OnObjectCreation(objId) local m_object = getobject(objId) local mapId = readdword(m_object) local _, tagtype = gettaginfo(mapId) if tagtype == "vehi" then rectprism:monitor() -- Monitor all vehicles end end Notes: Tells the specified GEO to monitor when objId enters and exits it. Note that this must be used in order for OnGeoEnter and OnGeoExit to work for the specified GEO and objId. This is for the sake of the script not having to check the coordinates of every single object and comparing them to the volumes of every single GEO every 1/100 of a second. Also note that as of GEO 2.2, it is not necessary to use this function on players; GEOs will automatically monitor players. GEO:coords() Example: local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0) local x, y, z = sphere:coords() Notes: Returns the x, y, and z coordinates of the center of the specified GEO. GEO:high(orientation) orientation: <string> Axis of which you're attempting to find the highest point ("x", "y", or "z"). Example: local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0) local zhigh = sphere:high("z") Notes: Returns the highest coordinate in the specified orientation (i.e. geo:high("z") would return the highest z coordinate still considered to be inside of the GEO). GEO:low(orientation) orientation: <string> Axis of which you're attempting to find the lowest point ("x", "y", or "z") Example: local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0) local zlow = sphere:low("z") Notes: Returns the lowest coordinate in the specified orientation (i.e. geo:low("z") would return the lowest z coordinate still considered to be inside of the GEO). GEO:randomcoords() Example: local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0) local x, y, z = cylinder:randomcoords() Notes: Returns random x, y, and z coordinates within the specified GEO. GEO:type() Example: local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0) local type = cylinder:type() Notes: Returns the type of the specified GEO as a string. GEO:orientation() Example: local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0) local orientation = cylinder:orientation() Notes: Returns the orientation of a 2-dimensional GEO or Cylinder. Note that this cannot be used on Spheres or RectPrisms. GEO:name() Example: local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0) local name = sphere:name() Notes: Returns the name of the specified GEO. GEO:perimeter([density], [mapId]) density: <int> Amount of objects that should spawn around the perimeter of the GEO. mapId: <tag id> The tag of the objects that should spawn around the GEO's perimeter (default = Full-Spectrum Vision) Example: local sphere = GEO.newSphere("sphere", 5, 0, 0, 0.5) sphere:perimeter(20) local rectprism = GEO.newRectPrism("rectprism", 3, 4, 5, 0, 0, 0.5) rectprism:perimeter(7, gettagid("weap", "weapons\\flag\\flag")) Notes: Spawns the specified object (given via mapId) with the specified density (default 10) about the perimeter of the Z-center of the specified GEO. For spheres and cylinders, the amount of objects spawned will be equal to the density. For rectangular prisms, the density specifies the amount of objects spawned per edge (so a density of 10 will spawn a total of 40 objects). You may want to make sure the GEO's center is slightly above the ground so the objects don't spawn under the map. Also be careful when this function is used, as it does create a lot of objects. If you aren't careful, you'll reach Halo's object limit. GEO:surface([density], [mapId]) density: <int> Amount of objects that should spawn to create a 3D representation of the GEO. mapId: <tag id> The tag of the objects that should spawn to create the 3D representation of the GEO (default = Full-Spectrum Vision) Example: local sphere = GEO.newSphere("sphere", 5, 0, 0, 1) sphere:surface() local cylinder = GEO.newCylinder("cylinder", 4, 7, 0, 0, 1, "x") cylinder:surface(20, gettagid("weap", "weapons\\plasma grenade\\plasma grenade")) Notes: Spawns the specified object (given via mapId) with the specified density (default 12) to create a 3D representation of the specified GEO. Cannot be used on Circles or Rectangles. The density of these approximate an appropriate amount of objects to be made in order to get a good idea of where a GEO is. It is highly suggested that you use this function only as a means to aid in visualization during testing. This function creates a lot of objects and it is very easy to hit the object limit using it. OnGeoEnter and OnGeoExit Event Functions: OnGeoEnter(geo, player, objId) geo: <GEO object> The GEO the player or object is entering. player: <player memory id> The player entering the GEO. objId: <object id> The objId entering the GEO. Example: sphere = GEO.newSphere("sphere", 5, 0, 0, 0) function OnGeoEnter(geo, player, objId) if geo == sphere then privatesay(player, "You may not enter this GEO.") return false end return true end Notes: Called when an object that is being monitored by a GEO enters that GEO. Return 1 to allow objects to enter, return 0 to disallow this. OnGeoExit(geo, player, objId) geo: <GEO object> The GEO the player or object is exiting. player: <player memory id> The player exiting the GEO. objId: <object id> The objId exiting the GEO. Example: sphere = GEO.newSphere("sphere", 5, 0, 0, 0) function OnGeoExit(geo, player, objId) if geo == sphere then privatesay(player, "You may not exit this GEO.") return false end return true end Notes: Called when an object that is being monitored by a GEO exits that GEO. Return 1 to allow objects to exit, return 0 to disallow this. Miscellaneous GEO functions: GEO.get(name) name: <string> Name of the GEO you're trying to access. Example: function OnPlayerSpawn(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0) sphere:follow(objId) end function OnPlayerKill(killer, victim, mode) local m_victim = getplayer(victim) local v_objectId = readdword(m_victim, 0x34) local victim_sphere = GEO.get("Sphere" .. v_objectId) victim_sphere:unfollow() end Notes: Returns a GEO given the specified name. GEO.followedBy(objId) objId: <object id> Object being followed by GEOs. Example: function OnPlayerKill(killer, victim, mode) local geos = GEO.followedBy(victim) for k,v in ipairs(geos) do v:unfollow() end end Notes: Returns a list of GEOs following the specified objId. GEO.cleanup(player) player: <player memory id> Player whose following of GEOs you want to delete. Example: -- Note that this is here only for the sake of example; this is not necessary, as the GEOTimer takes care of this automatically. function OnPlayerKill(killer, victim, mode) GEO.cleanup(victim) end Notes: Deletes all of the GEOs currently following the specified player. GEO.clear() Example: function OnNewGame(map) -- Global variable for map name cur_map = map end function OnServerChat(player, message, type) if message == "reset" then svcmd("sv_map_reset") GEO.clear() OnNewGame(cur_map) end end Notes: Deletes all GEOs currently active on the map. If you have any questions about how GEOs work, PM me (Nuggets) at phasor.proboards.com. --]] -- GEO -- -- Create Metatable GEO = {} GEO.__index = GEO -- Set random seed and define infinity math.randomseed(os.time()) math.inf = 1 / 0 function inSphere(objId, x, y, z, r) local ox, oy, oz = getobjectcoords(objId) if ox then -- Pythagorean local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2 + (z - oz) ^ 2) if dist <= r then return true end end return false end function inCircle(objId, x, y, z, r, orientation) local ox, oy, oz = getobjectcoords(objId) if ox then -- Default orientation to "z" orientation = orientation or "z" -- Pythagorean based on circle's orientation if orientation == "z" then local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2) if dist <= r and oz == z then return true end elseif orientation == "y" then local dist = math.sqrt((x - ox) ^ 2 + (z - oz) ^ 2) if dist <= r and oy == y then return true end elseif orientation == "x" then local dist = math.sqrt((y - oy) ^ 2 + (z - oz) ^ 2) if dist <= r and ox == x then return true end end end return false end function inCylinder(objId, x, y, z, hlow, hhigh, r, orientation) local ox, oy, oz = getobjectcoords(objId) if ox then if orientation == "z" then -- Pythagorean to see if object is within radius of circle local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2) -- Make sure the object is also within the height of the cylinder if dist <= r and oz >= hlow and oz <= hhigh then return true end elseif orientation == "x" then local dist = math.sqrt((y - oy) ^ 2 + (z - oz) ^ 2) if dist <= r and ox >= hlow and ox <= hhigh then return true end elseif orientation == "y" then local dist = math.sqrt((z - oz) ^ 2 + (x - ox) ^ 2) if dist <= r and oy >= hlow and oy <= hhigh then return true end end end return false end function inRectangle(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh) -- These functions are essentially the same return inRectPrism(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh) end function inRectPrism(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh) local x, y, z = getobjectcoords(objId) if x then -- Make sure the coordinates are inside of each extreme of the rectangular prism if x <= xhigh and x >= xlow and y <= yhigh and y >= ylow and z <= zhigh and z >= zlow then return true end end return false end function randomInSphere(x, y, z, r) -- Increase precision x = math.floor(x * 100) y = math.floor(y * 100) z = math.floor(z * 100) r = math.floor(r * 100) -- Find random values inside of the sphere. return math.random(x - r, x + r + 1) / 100, math.random(y - r, y + r + 1) / 100, math.random(z - r, z + r + 1) / 100 end function randomInCircle(x, y, z, r, orientation) -- Increase precision r = math.floor(r * 100) -- Possible values depend on circle's orientation. if orientation == "z" then x = math.floor(x * 100) y = math.floor(y * 100) return math.random(x - r, x + r + 1) / 100, math.random(y - r, y + r + 1) / 100, z elseif orientation == "x" then y = math.floor(y * 100) z = math.floor(z * 100) return x, math.random(y - r, y + r + 1) / 100, math.random(z - r, z + r + 1) / 100 elseif orientation == "y" then x = math.floor(x * 100) z = math.floor(z * 100) return math.random(x - r, x + r + 1) / 100, y, math.random(z - r, z + r + 1) / 100 end end function randomInCylinder(x, y, z, hlow, hhigh, r, orientation) -- Increase precision x = math.floor(x * 100) y = math.floor(y * 100) z = math.floor(z * 100) hlow = math.floor(hlow * 100) hhigh = math.floor(hhigh * 100) r = math.floor(r * 100) -- Find random values inside of the cylinder depending on its orientation. if orientation == "z" then return math.random(x - r, x + r + 1) / 100, math.random(y - r, y + r + 1) / 100, math.random(hlow, hhigh + 1) / 100 elseif orientation == "y" then return math.random(x - r, x + r + 1) / 100, math.random(hlow, hhigh + 1) / 100, math.random(z - r, z + r + 1) / 100 elseif orientation == "x" then return math.random(hlow, hhigh + 1) / 100, math.random(y - r, r + r + 1) / 100, math.random(z - r, z + r + 1) / 100 end end function randomInRectPrism(xlow, xhigh, ylow, yhigh, zlow, zhigh) -- Increase precision xlow = math.floor(xlow * 100) xhigh = math.floor(xhigh * 100) ylow = math.floor(ylow * 100) yhigh = math.floor(yhigh * 100) zlow = math.floor(zlow * 100) zhigh = math.floor(zhigh * 100) -- Find random values inside of the rectangular prism. return math.random(xlow, xhigh + 1) / 100, math.random(ylow, yhigh + 1) / 100, math.random(zlow, zhigh) end function sphereintersect(sphere, pointA, pointB) local points = {} local a = (pointA.x - pointB.x) ^ 2 + (pointA.y - pointB.y) ^ 2 + (pointA.z - pointB.z) ^ 2 local c = (pointA.x - sphere.x) ^ 2 + (pointA.y - sphere.y) ^ 2 + (pointA.z - sphere.z) ^ 2 - sphere.r ^ 2 local b = (pointB.x - sphere.x) ^ 2 + (pointB.y - sphere.y) ^ 2 + (pointB.z - sphere.z) ^ 2 - c - a - sphere.r ^ 2 -- Make sure square root is not imaginary. local q = b ^ 2 - 4 * a * c if q > 0 then -- Quadratic Formula: local t1 = (-b + math.sqrt(q)) / (2 * a) local t2 = (-b - math.sqrt(q)) / (2 * a) local xt1 = pointA.x * (1 - t1) + t1 * pointB.x local yt1 = pointA.y * (1 - t1) + t1 * pointB.y local zt1 = pointA.z * (1 - t1) + t1 * pointB.z local xt2 = pointA.x * (1 - t2) + t2 * pointB.x local yt2 = pointA.y * (1 - t2) + t2 * pointB.y local zt2 = pointA.z * (1 - t2) + t2 * pointB.z -- Make sure the intersection is on this line. local ipoint1, ipoint2 if t1 >= 0 and t1 <= 1 then table.insert(points, {x = xt1, y = yt1, z = zt1}) end -- Make sure the intersection is on this line. if t2 >= 0 and t2 <= 1 then table.insert(points, {x = xt2, y = yt2, z = zt2}) end end return points end function cylinderintersect(cylinder, pointA, pointB) -- Change x, y and z depending on orientation. local x, y, z if cylinder.o == "z" then x, y, z = "x", "y", "z" elseif cylinder.o == "x" then x, y, z = "z", "y", "x" elseif cylinder.o == "y" then x, y, z = "x", "z", "y" end local points = {} -- Determine if line intersects cylinder's edges. local a = (pointA[x] - pointB[x]) ^ 2 + (pointA[y] - pointB[y]) ^ 2 local c = (pointA[x] - cylinder[x]) ^ 2 + (pointA[y] - cylinder[y]) ^ 2 - cylinder.r ^ 2 local b = (pointB[x] - cylinder[x]) ^ 2 + (pointB[y] - cylinder[y]) ^ 2 - a - c - cylinder.r ^ 2 local q = b ^ 2 - 4 * a * c if q > 0 then local t1 = (-b + math.sqrt(q)) / (2 * a) local t2 = (-b - math.sqrt(q)) / (2 * a) local xt1 = pointA[x] * (1 - t1) + t1 * pointB[x] local yt1 = pointA[y] * (1 - t1) + t1 * pointB[y] local zt1 = pointA[z] * (1 - t1) + t1 * pointB[z] local xt2 = pointA[x] * (1 - t2) + t2 * pointB[x] local yt2 = pointA[y] * (1 - t2) + t2 * pointB[y] local zt2 = pointA[z] * (1 - t2) + t2 * pointB[z] -- Make sure the intersection is on this line and within the cylinder's height. if t1 >= 0 and t1 <= 1 and zt1 >= cylinder.hlow and zt1 <= cylinder.hhigh then table.insert(points, {[x] = xt1, [y] = yt1, [z] = zt1}) end -- Make sure the intersection is on this line and within the cylinder's height. if t2 >= 0 and t2 <= 1 and zt2 >= cylinder.hlow and zt2 <= cylinder.hhigh then table.insert(points, {[x] = xt2, [y] = yt2, [z] = zt2}) end -- Check end caps -- If either point on the line is lower than or equal to the lowest point on the cylinder... if pointA[z] <= cylinder.hlow or pointB[z] <= cylinder.hlow then local tzlow = (cylinder.hlow - pointA[z]) / (pointA[z] + pointB[z]) local xtlow = pointA[x] * (1 - tzlow) + tzlow * pointB[x] local ytlow = pointA[y] * (1 - tzlow) + tzlow * pointB[y] local dist = math.sqrt((cylinder[x] - xtlow) ^ 2 + (cylinder[y] - ytlow) ^ 2) if dist < cylinder.r then table.insert(points, {[x] = xtlow, [y] = ytlow, [z] = cylinder.hlow}) end end -- If either point on the line is higher than or equal to the lowest point on the cylinder... if pointA[z] >= cylinder.hhigh or pointB[z] >= cylinder.hhigh then local tzhigh = (cylinder.hhigh - pointA[z]) / (pointA[z] + pointB[z]) local xthigh = pointA[x] * (1 - tzhigh) + tzhigh * pointB[x] local ythigh = pointA[y] * (1 - tzhigh) + tzhigh * pointB[y] local dist = math.sqrt((cylinder[x] - xthigh) ^ 2 + (cylinder[y] - ythigh) ^ 2) if dist < cylinder.r then table.insert(points, {[x] = xthigh, [y] = ythigh, [z] = cylinder.hhigh}) end end end return points end function rectprismintersect(rectprism, pointA, pointB) local points = {} -- Get the time "t" on the line where intersection with each coordinate's extreme occurs. local txlow = (rectprism.xlow - pointA.x) / (pointA.x + pointB.x) local txhigh = (rectprism.xhigh - pointA.x) / (pointA.x + pointB.x) local tylow = (rectprism.ylow - pointA.y) / (pointA.y + pointB.y) local tyhigh = (rectprism.yhigh - pointA.y) / (pointA.y + pointB.y) local tzlow = (rectprism.zlow - pointA.z) / (pointA.z + pointB.z) local tzhigh = (rectprism.zhigh - pointA.z) / (pointA.z + pointB.z) -- Find other coordinates given t. local xlowy = pointA.y * (1 - txlow) + txlow * pointB.y local xlowz = pointA.z * (1 - txlow) + txlow * pointB.z -- Ensure that this intersection is within the bounds of the rectangular prism. if xlowy <= rectprism.yhigh and xlowy >= rectprism.ylow and xlowz <= rectprism.zhigh and xlowz >= rectprism.zlow then table.insert(points, {x = rectprism.xlow, y = xlowy, z = xlowz}) end -- Find other coordinates given t. local xhighy = pointA.y * (1 - txhigh) + txhigh * pointB.y local xhighz = pointA.z * (1 - txhigh) + txhigh * pointB.z -- Ensure that this intersection is within the bounds of the rectangular prism. if xhighy <= rectprism.yhigh and xhighy >= rectprism.ylow and xhighz <= rectprism.zhigh and xhighz >= rectprism.zlow then table.insert(points, {x = rectprism.xhigh, y = xhighy, z = xhighz}) end -- Find other coordinates given t. local ylowx = pointA.x * (1 - tylow) + tylow * pointB.x local ylowz = pointA.z * (1 - tylow) + tylow * pointB.z -- Ensure that this intersection is within the bounds of the rectangular prism. if ylowx <= rectprism.xhigh and ylowx >= rectprism.xlow and ylowz <= rectprism.zhigh and ylowz >= rectprism.zlow then table.insert(points, {x = ylowx, y = rectprism.ylow, z = ylowz}) end -- Find other coordinates given t. local yhighx = pointA.x * (1 - tyhigh) + tyhigh * pointB.x local yhighz = pointA.z * (1 - tyhigh) + tyhigh * pointB.z -- Ensure that this intersection is within the bounds of the rectangular prism. if yhighx <= rectprism.xhigh and yhighx >= rectprism.xlow and yhighz <= rectprism.zhigh and yhighz >= rectprism.zlow then table.insert(points, {x = yhighx, y = rectprism.yhigh, z = yhighz}) end -- Find other coordinates given t. local zlowx = pointA.x * (1 - tzlow) + tzlow * pointB.x local zlowy = pointA.y * (1 - tzlow) + tzlow * pointB.y -- Ensure that this intersection is within the bounds of the rectangular prism. if zlowx <= rectprism.xhigh and zlowx >= rectprism.xlow and zlowy <= rectprism.yhigh and zlowy >= rectprism.ylow then table.insert(points, {x = zlowx, y = zlowy, z = rectprism.zlow}) end -- Find other coordinates given t. local zhighx = pointA.x * (1 - tzhigh) + tzhigh * pointB.x local zhighy = pointA.y * (1 - tzhigh) + tzhigh * pointB.y -- Ensure that this intersection is within the bounds of the rectangular prism. if zhighx <= rectprism.xhigh and zhighx >= rectprism.xlow and zhighy <= rectprism.yhigh and zhighy >= rectprism.ylow then table.insert(points, {x = zhighx, y = zhighy, z = rectprism.zhigh}) end -- Corner and edge check if #points > 2 then -- Remove entries from the table while we loop through it. local i = 0 while i <= #points do -- There can be a total of three copies of the same coordinates (if the intersection happens at a corner). local rem1, rem2 for k,v in ipairs(points) do if points[i].x == v.x and points[i].y == v.y and points[i].z == v.z then if rem1 then rem2 = i - 1 -- Subtract 1 from the key since rem1 will be removed first and this key will be lowered by 1 when that happens. else rem1 = i end end end -- Remove the two keys. if rem1 or rem2 then if rem1 then table.remove(points, rem1) elseif rem2 then table.remove(points, rem2) end else i = i + 1 -- Increment i only if an entry has not been deleted. end end end return points end function circleintersect(circle, pointA, pointB) -- Change x, y and z depending on orientation. local x, y, z if circle.o == "z" then x, y, z = "x", "y", "z" elseif circle.o == "x" then x, y, z = "z", "y", "x" elseif circle.o == "y" then x, y, z = "x", "z", "y" end local points = {} -- Find the time "t" when the line intersects the plane at which the circle is oriented. local tz = (circle[z] - pointA[z]) / (pointA[z] + pointB[z]) local xtz = pointA[x] * (1 - tz) + tz * pointB[x] local ytz = pointA[y] * (1 - tz) + tz * pointB[y] -- Find the distance from this intersection point to the center of the circle and compare it against the radius. local dist = math.sqrt((xtz - circle[x]) ^ 2 + (ytz - circle[y]) ^ 2) if dist <= circle.r then table.insert(points, {[x] = xtz, [y] = ytz, [z] = circle[z]}) end return points end function rectangleintersect(rectangle, pointA, pointB) -- Change x, y and z depending on orientation. local x, y, z if rectangle.o == "z" then x, y, z = "x", "y", "z" elseif rectangle.o == "x" then x, y, z = "z", "y", "x" elseif rectangle.o == "y" then x, y, z = "x", "z", "y" end local points = {} -- Find the time "t" when the line intersects the plane at which the rectangle is oriented. local tz = (rectangle[z] - pointA[z]) / (pointA[z] + pointB[z]) local xtz = pointA[x] * (1 - tz) + tz * pointB[x] local ytz = pointA[y] * (1 - tz) + tz * pointB[y] -- Find if the intersection point is within the bounds of the rectangle. if xtz >= rectangle[x .. "low"] and xtz <= rectangle[x .. "high"] and ytz >= rectangle[y .. "low"] and ytz <= rectangle[y .. "high"] then table.insert(points, {[x] = xtz, [y] = ytz, [z] = rectangle[z]}) end return points end -- Object Creation Comments (refer to this function for questions on how the other ones work) function GEO.newSphere(name, r, x, y, z) -- Check to see if there is already a GEO with this name. if not GEO[name] then -- Create new table GEO[name] = {} GEO[name].t = "sphere" -- type GEO[name].n = name -- name GEO[name].r = r or 1 -- radius (default value of 1) GEO[name].x = x or 0 -- x coordinate of center (default value of 0) GEO[name].y = y or 0 -- y coordinate of center (default value of 0) GEO[name].z = z or 0 -- z coordinate of center (default value of 0) -- Initialize monitor and contain tables GEO[name].m = {} GEO[name].c = {} -- Initialize list of antigeos GEO[name].anti = {} -- Notify the console that a sphere has been created. hprintf("Sphere \"" .. name .. "\" created.") setmetatable(GEO[name], GEO) -- Add this object to the GEO metatable to allow GEO-editing functions to work on it. return GEO[name] -- Return the object end -- If no object was returned, the name was invalid; notify the console. hprintf("Invalid name: \"" .. name .. "\"") end function GEO.newCircle(name, r, x, y, z, orientation) if not GEO[name] then GEO[name] = {} GEO[name].t = "circle" GEO[name].n = name GEO[name].o = orientation or "z" -- orientation GEO[name].r = r or 0 GEO[name].x = x or 0 GEO[name].y = y or 0 GEO[name].z = z or 0 -- Initialize monitor and contain tables GEO[name].m = {} GEO[name].c = {} -- Initialize list of antigeos GEO[name].anti = {} hprintf("Circle \"" .. name .. "\" created.") setmetatable(GEO[name], GEO) return GEO[name] end hprintf("Invalid name: \"" .. name .. "\"") end function GEO.newCylinder(name, r, h, x, y, z, orientation) if not GEO[name] then GEO[name] = {} GEO[name].t = "cylinder" GEO[name].n = name x = x or 0 y = y or 0 z = z or 0 r = r or 1 h = h or 1 orientation = orientation or "z" GEO[name].x = x GEO[name].y = y GEO[name].z = z GEO[name].r = r GEO[name].h = h -- height GEO[name].o = orientation -- orientation "x", "y", or "z" GEO[name].hlow = GEO[name][orientation] - h / 2 -- lowest orientation coordinate still within the cylinder GEO[name].hhigh = GEO[name][orientation] + h / 2 -- highest orientation coordinate still within the cylinder -- Initialize monitor and contain tables GEO[name].m = {} GEO[name].c = {} -- Initialize list of antigeos GEO[name].anti = {} hprintf("Cylinder \"" .. name .. "\" created.") setmetatable(GEO[name], GEO) return GEO[name] end end function GEO.newRectPrism(name, lx, ly, lz, x, y, z) if not GEO[name] then GEO[name] = {} GEO[name].t = "rectprism" GEO[name].n = name lx = lx or 1 ly = ly or 1 lz = lz or 1 x = x or 0 y = y or 0 z = z or 0 GEO[name].lx = lx -- x length GEO[name].ly = ly -- y length GEO[name].lz = lz -- z length GEO[name].x = x GEO[name].y = y GEO[name].z = z GEO[name].xlow = x - lx / 2 -- lowest x-coordinate still within the rectangular prism GEO[name].xhigh = lx / 2 + x -- highest x-coordinate still within in the rectangular prism GEO[name].ylow = y - ly / 2 -- lowest y-coordinate still within the rectangular prism GEO[name].yhigh = ly / 2 + y -- highest y-coordinate still within the rectangular prism GEO[name].zlow = z - lz / 2 -- lowest z-coordinate still within the rectangular prism GEO[name].zhigh = lz / 2 + z -- highest z-coordinate still within the rectangular prism -- Initialize monitor and contain tables GEO[name].m = {} GEO[name].c = {} -- Initialize list of antigeos GEO[name].anti = {} hprintf("Rectangular Prism \"" .. name .. "\" created.") setmetatable(GEO[name], GEO) return GEO[name] end hprintf("Invalid name: \"" .. name .. "\"") end function GEO.newRect(name, width, height, x, y, z, orientation) if not GEO[name] then GEO[name] = {} GEO[name].t = "rectangle" GEO[name].n = name width = width or 1 height = height or 1 x = x or 0 y = y or 0 z = z or 0 orientation = orientation or "z" GEO[name].width = width GEO[name].height = height GEO[name].x = x GEO[name].y = y GEO[name].z = z GEO[name].o = orientation -- Coordinates' highs and lows depend on orientation if orientation == "z" then GEO[name].xlow = x - width / 2 GEO[name].xhigh = x + width / 2 GEO[name].ylow = y - height / 2 GEO[name].yhigh = y + height / 2 GEO[name].zlow = z GEO[name].zhigh = z elseif orientation == "x" then GEO[name].xlow = x GEO[name].xhigh = x GEO[name].ylow = y - width / 2 GEO[name].yhigh = y + width / 2 GEO[name].zlow = z - height / 2 GEO[name].zhigh = z + height / 2 elseif orientation == "y" then GEO[name].xlow = x - width / 2 GEO[name].xhigh = x + width / 2 GEO[name].ylow = y GEO[name].yhigh = y GEO[name].zlow = z - height / 2 GEO[name].zhigh = z + height / 2 end -- Initialize monitor and contain tables GEO[name].m = {} GEO[name].c = {} -- Initialize list of antigeos GEO[name].anti = {} hprintf("Rectangle \"" .. name .. "\" created.") setmetatable(GEO[name], GEO) return GEO[name] end hprintf("Invalid name: \"" .. name .. "\"") end function GEO.get(name) return GEO[name] end function GEO.clear() for k,v in pairs(GEO) do if type(v) == "table" and k ~= "__index" then -- make sure we're actually getting a GEO object v:delete() -- Delete every GEO end end end function GEO:delete() -- Get rid of perimeter and surface objects self:hide() -- Make sure any GEO that this is an AntiGEO of is aware that this GEO no longer exists for k,v in pairs(GEO) do if type(v) == "table" and k ~= "__index" then for name,bool in pairs(v.anti) do if name == self.n then GEO[v.n].anti[name] = nil break end end end end -- Nullify GEO GEO[self.n] = nil hprintf("Geo \"" .. self.n .. "\" deleted.") end function GEO:move(x, y, z) -- Move the center of the object -- Default to GEO's current coordinates GEO[self.n].x = x or GEO[self.n].x GEO[self.n].y = y or GEO[self.n].y GEO[self.n].z = z or GEO[self.n].z -- If this is a rectangular prism... if self.t == "rectprism" then -- Change the x, y, and z lows and highs accordingly to adjust to the new center GEO[self.n].xlow = x - GEO[self.n].lx / 2 GEO[self.n].xhigh = GEO[self.n].lx / 2 + x GEO[self.n].ylow = y - GEO[self.n].ly / 2 GEO[self.n].yhigh = GEO[self.n].ly / 2 + y GEO[self.n].zlow = z - GEO[self.n].lz / 2 GEO[self.n].zhigh = GEO[self.n].lz / 2 + z -- If this is a rectangle... elseif self.t == "rectangle" then -- Change the x, y, and z lows and highs accordingly to adjust to the new center (depends on orientation) if self.o == "z" then GEO[self.n].xlow = self.x - self.width / 2 GEO[self.n].xhigh = self.x + self.width / 2 GEO[self.n].ylow = self.y - self.height / 2 GEO[self.n].yhigh = self.y + self.height / 2 GEO[self.n].zlow = self.z GEO[self.n].zhigh = self.z elseif self.o == "x" then GEO[self.n].xlow = self.x GEO[self.n].xhigh = self.x GEO[self.n].ylow = self.y - self.width / 2 GEO[self.n].yhigh = self.y + self.width / 2 GEO[self.n].zlow = self.z - self.height / 2 GEO[self.n].zhigh = self.z + self.height / 2 elseif self.o == "y" then GEO[self.n].xlow = self.x - self.width / 2 GEO[self.n].xhigh = self.x + self.width / 2 GEO[self.n].ylow = self.y GEO[self.n].yhigh = self.y GEO[self.n].zlow = self.z - self.height / 2 GEO[self.n].zhigh = self.z + self.height / 2 end -- If this is a cylinder... elseif self.t == "cylinder" then GEO[self.n].hlow = self[self.o] - self.h / 2 GEO[self.n].hhigh = self[self.o] + self.h / 2 end end function GEO:radius(new) if self.t == "sphere" or self.t == "circle" or self.t == "cylinder" then if new then -- If "new" is defined... GEO[self.n].r = new -- Change the radius to its value. else -- If not... return GEO[self.n].r -- Return its current radius. end end end function GEO:size(x, y, z) -- If this is a rectangular prism... if self.t == "rectprism" then if x or y or z then -- If any of these variables have been defined... -- Adjust lengths and x, y, and z highs and lows accordingly. GEO[self.n].lx = x or GEO[self.n].lx GEO[self.n].ly = y or GEO[self.n].ly GEO[self.n].lz = z or GEO[self.n].lz GEO[self.n].xlow = GEO[self.n].x - x / 2 GEO[self.n].xhigh = x / 2 + GEO[self.n].x GEO[self.n].ylow = GEO[self.n].y - y / 2 GEO[self.n].yhigh = y / 2 + GEO[self.n].y GEO[self.n].zlow = GEO[self.n].z - z / 2 GEO[self.n].zhigh = z / 2 + GEO[self.n].z else -- Otherwise... return GEO[self.n].lx, GEO[self.n].ly, GEO[self.n].lz -- Return the x, y, and z lengths. end -- If this is a rectangle... elseif self.t == "rectangle" then if x or y or z then -- If any of these variables are defined... -- Adjust width, height, and x, y, and z highs and lows accordingly (depends on orientation). if self.o == "z" then GEO[self.n].width = x GEO[self.n].height = y GEO[self.n].xlow = self.x - self.width / 2 GEO[self.n].xhigh = self.x + self.width / 2 GEO[self.n].ylow = self.y - self.height / 2 GEO[self.n].yhigh = self.y + self.height / 2 GEO[self.n].zlow = self.z GEO[self.n].zhigh = self.z elseif self.o == "x" then GEO[self.n].width = y GEO[self.n].height = z GEO[self.n].xlow = self.x GEO[self.n].xhigh = self.x GEO[self.n].ylow = self.y - self.width / 2 GEO[self.n].yhigh = self.y + self.width / 2 GEO[self.n].zlow = self.z - self.height / 2 GEO[self.n].zhigh = self.z + self.height / 2 elseif self.o == "y" then GEO[self.n].width = x GEO[self.n].height = z GEO[self.n].xlow = self.x - self.width / 2 GEO[self.n].xhigh = self.x + self.width / 2 GEO[self.n].ylow = self.y GEO[self.n].yhigh = self.y GEO[self.n].zlow = self.z - self.height / 2 GEO[self.n].zhigh = self.z + self.height / 2 end else -- Otherwise... return GEO[self.n].width, GEO[self.n].height -- Return the width and height of the rectangle. end -- If this is a cylinder... elseif self.t == "cylinder" then local h = x or y or z -- Whichever variable is defined, it is taken as the height. if h then -- If a height is specified... -- Adjust height and z high and low accordingly. GEO[self.n].h = h GEO[self.n].hlow = self[self.o] - h / 2 GEO[self.n].hhigh = self[self.o] + h / 2 else -- Otherwise... return GEO[self.n].h -- Return the height. end end end function GEO:extend(orientation, direction, amount) -- Change the direction from "+" or "-" to "high" or "low". local dir dir = string.gsub(direction, "-", "low") dir = string.gsub(direction, "+", "high") -- Get the face we're trying to extend (i.e. "xhigh") local face = string.lower(orientation) .. direction -- If this is a rectangular prism or a rectangle... if self.t == "rectprism" or self.t == "rectangle" then -- Make sure "face" is actually a valid face (and not something like "cheesederp") if self[face] then -- Use "GEO[self.n]" when you want to actually permanently change the value of something within the object; use "self" for reading information from the object. -- Change the length of the GEO in the orientation specified. GEO[self.n]["l" .. string.lower(orientation)] = self["l" .. string.lower(orientation)] + amount -- Figure out if the positive or negative face is being extended. if direction == "+" then GEO[self.n][face] = self[face] + amount GEO[self.n][string.lower(orientation)] = self[string.lower(orientation)] + amount / 2 else GEO[self.n][face] = self[face] - amount GEO[self.n][string.lower(orientation)] = self[string.lower(orientation)] - amount / 2 end end -- If this is a cylinder... elseif self.t == "cylinder" then -- The orientation must be the orientation of the cylinder if orientation == self.o then if self[face] then GEO[self.n].h = self.h + amount -- Figure out if the top or bottom face is being extended. if direction == "+" then GEO[self.n].hhigh = self.hhigh + amount GEO[self.n][self.o] = self[self.o] + amount / 2 else GEO[self.n].hhigh = self.hhigh - amount GEO[self.n][self.o] = self[self.o] - amount / 2 end end end end end function GEO:antigeo(boolean, ...) GEO[self.n].geolist = GEO[self.n].geolist or {} -- Get all GEOs from args. local geos = {...} if boolean == true then for _,geo in ipairs(geos) do local name = geo:name() -- Insert AntiGEO into the specified GEOs' AntiGEO table. GEO[name].anti[self.n] = true -- Insert GEO into list of AntiGEO's GEOs. GEO[self.n].geolist[name] = true end elseif boolean == false then for _,geo in ipairs(geos) do local name = geo:name() -- Remove AntiGEO from table. GEO[name].anti[self.n] = false -- Remove GEO from AntiGEO table. GEO[self.n].geolist[name] = false end elseif boolean == nil then if GEO[self.n].a == true then return true else return false end end local count = 0 for k,v in pairs(GEO[self.n].geolist) do count = count + 1 end if count > 0 then GEO[self.n].a = true else GEO[self.n].a = false end end function GEO:coords() return self.x, self.y, self.z end function GEO:high(orientation) if self.t == "sphere" or self.t == "circle" then return self[orientation] + self.r elseif self.t == "rectprism" or self.t == "rectangle" then return self[orientation .. "high"] elseif self.t == "cylinder" then if orientation == self.o then return self.hhigh else return self[orientation] + self.r end end end function GEO:low(orientation) if self.t == "sphere" or self.t == "circle" then return self[orientation] - self.r elseif self.t == "rectprism" or self.t == "rectangle" then return self[orientation .. "low"] elseif self.t == "cylinder" then if orientation == self.o then return self.hlow else return self[orientation] - self.r end end end function GEO:randomcoords() if self.t == "sphere" then return randomInSphere(self.x, self.y, self.z, self.r) elseif self.t == "circle" then return randomInCircle(self.x, self.y, self.z, self.r, self.o) elseif self.t == "cylinder" then return randomInCylinder(self.x, self.y, self.z, self.hlow, self.hhigh, self.r, self.o) elseif self.t == "rectprism" or self.t == "rectangle" then return randomInRectPrism(self.xlow, self.xhigh, self.ylow, self.yhigh, self.zlow, self.zhigh) end end function GEO:type() return self.t end function GEO:orientation() return self.o end function GEO:name() return self.n end function GEO:perimeter(density, mapId) -- Default density to 10 density = density or 10 -- Default tagtype and tagname to Full-Spectrum Visions mapId = mapId or gettagid("eqip", "powerups\\full-spectrum vision") tagname, tagtype = gettaginfo(mapId) -- Store all of the perimeter objects in a table GEO[self.n].p = GEO[self.n].p or {} -- Find the change in angle per point from 0 - 2pi (0° - 360°) local angle_increment = 2 * math.pi / density if self.t == "sphere" then for i = 1,density do -- Use trigonometry to find the outer edge of the circle (for a sphere, this will be at the z-center -- the widest part of the sphere). local x = self.r * math.cos(angle_increment * i) local y = self.r * math.sin(angle_increment * i) local z = self.z local objId = createobject(mapId, 0, nil, false, self.x + x, self.y + y, self.z) GEO[self.n].p[objId] = {self.x + x, self.y + y, self.z} end elseif self.t == "circle" or self.t == "cylinder" then if self.o == "z" then for i = 1,density do -- Use trigonometry to find the outer edge of the circle. local x = self.r * math.cos(angle_increment * i) local y = self.r * math.sin(angle_increment * i) local z = self.z local objId = createobject(mapId, 0, nil, false, self.x + x, self.y + y, self.z) GEO[self.n].p[objId] = {self.x + x, self.y + y, self.z} end elseif self.o == "x" then for i = 1,density do -- Use trigonometry to find the outer edge of the circle. local x = self.x local y = self.r * math.cos(angle_increment * i) local z = self.r * math.sin(angle_increment * i) local objId = createobject(mapId, 0, nil, false, self.x, self.y + y, self.z + z) GEO[self.n].p[objId] = {self.x, self.y + y, self.z} end elseif self.o == "y" then for i = 1,density do -- Use trigonometry to find the outer edge of the circle. local x = self.r * math.cos(angle_increment * i) local y = self.y local z = self.r * math.sin(angle_increment * i) hprintf("x: " .. (self.x + x) .. " y: " .. (self.y) .. " z: " .. (self.z + z)) local objId = createobject(mapId, 0, nil, false, self.x + x, self.y, self.z + z) GEO[self.n].p[objId] = {self.x + x, self.y, self.z + z} end end elseif self.t == "rectprism" or self.t == "rectangle" then if self.t == "rectangle" then if self.o ~= "z" then return end end -- Create points at four corners of the rectangle local o1 = createobject(mapId, 0, nil, false, self.xhigh, self.yhigh, self.z) local o2 = createobject(mapId, 0, nil, false, self.xhigh, self.ylow, self.z) local o3 = createobject(mapId, 0, nil, false, self.xlow, self.yhigh, self.z) local o4 = createobject(mapId, 0, nil, false, self.xlow, self.ylow, self.z) GEO[self.n].p[o1] = {self.xhigh, self.yhigh, self.z} GEO[self.n].p[o2] = {self.xhigh, self.yhigh, self.z} GEO[self.n].p[o3] = {self.xhigh, self.yhigh, self.z} GEO[self.n].p[o4] = {self.xhigh, self.yhigh, self.z} for i = 1,density do local herp = createobject(mapId, 0, nil, false, self.xhigh - (i * self.lx / density), self.yhigh, self.z) local derp = createobject(mapId, 0, nil, false, self.xhigh, self.yhigh - (i * self.ly / density), self.z) local weee = createobject(mapId, 0, nil, false, self.xhigh - (i * self.lx / density), self.ylow, self.z) local cheese = createobject(mapId, 0, nil, false, self.xlow, self.ylow + (i * self.ly / density), self.z) GEO[self.n].p[herp] = {self.xhigh - (i * self.lx / density), self.yhigh, self.z} GEO[self.n].p[derp] = {self.xhigh, self.yhigh - (i * self.ly / density), self.z} GEO[self.n].p[weee] = {self.xhigh - (i * self.lx / density), self.ylow, self.z} GEO[self.n].p[cheese] = {self.xlow, self.ylow + (i * self.ly / density), self.z} end end for objId,_ in pairs(GEO[self.n].p) do writebit(getobject(objId) + 0x10, 5, true) -- Ignore pyhsics end -- Also show the surface or perimeter of AntiGEOs with Overshield powerups for name,bool in pairs(GEO[self.n].anti) do if bool then local geo = GEO.get(name) if geo:type() == "sphere" or geo:type() == "cylinder" or geo:type() == "rectprism" then geo:surface(density, gettagid("eqip", "powerups\\over shield")) else geo:perimeter(density, gettagid("eqip", "powerups\\over shield")) end end end end function GEO:surface(density, mapId) -- Default density to 12 density = density or 12 -- Default tagtype and tagname to Full-Spectrum Visions mapId = mapId or gettagid("eqip", "powerups\\full-spectrum vision") -- Store all perimeter objects in a table GEO[self.n].p = GEO[self.n].p or {} -- Store all of the objects we will create local objects = {} if self.t == "sphere" then -- Use concentric rings based on the density given to simulate a sphere local laterals = density local latdist = self.r * 2 / laterals local curz = self.z + self.r local r = 0 for i = 1, laterals do if i <= math.floor(laterals / 2) then local d = i / math.floor(laterals / 2) * density -- Find the change in angle per point from 0 - 2pi (0° - 360°) local angle_increment = 2 * math.pi / density for j = 1, density do -- Use trigonometry to find the outer edge of the circle (for a sphere, this will be at the z-center -- the widest part of the sphere). local x = r * math.cos((angle_increment) * j) local y = r * math.sin((angle_increment) * j) local z = curz table.insert(objects, {self.x + x, self.y + y, z}) end elseif i >= math.ceil(laterals / 2) then local d = math.floor(laterals / 2) / i * density -- Find the change in angle per point from 0 - 2pi (0° - 360°) local angle_increment = 2 * math.pi / density for j = 1, density do -- Use trigonometry to find the outer edge of the circle (for a sphere, this will be at the z-center -- the widest part of the sphere). local x = r * math.cos((angle_increment) * j) local y = r * math.sin((angle_increment) * j) local z = curz table.insert(objects, {self.x + x, self.y + y, z}) end end -- Lower the lateral curz = curz - latdist local diff = curz - self.z local angle = math.acos(math.abs(diff) / self.r) -- Get the new radius at this sphere cap r = math.sin(angle) * self.r end elseif self.t == "cylinder" then -- Use multiple rings based on density given to simulate cylinder local laterals = math.ceil(density / 2) local latdist = self.h / laterals local curh = self[self.o] + (self.h / 2) for i = 0, laterals do if i == 0 or i == laterals then local rings = density / 2 local inc = self.r / rings local radius = self.r - inc for x = 1, rings - 1 do for j = 1, density do if self.o == "z" then local angle_increment = 2 * math.pi / density local x = radius * math.cos(angle_increment * j) local y = radius * math.sin(angle_increment * j) table.insert(objects, {self.x + x, self.y + y, curh}) elseif self.o == "x" then local y = radius * math.cos(angle_increment * j) local z = radius * math.sin(angle_increment * j) table.insert(objects, {curh, self.y + y, self.z + z}) elseif self.o == "y" then local x = radius * math.cos(angle_increment * j) local z = radius * math.sin(angle_increment * j) table.insert(objects, {self.x + x, curh, self.z + z}) end end radius = radius - inc end end for j = 1, density do -- Find the change in angle per point from 0 - 2pi (0° - 360°) local angle_increment = 2 * math.pi / density -- Use trigonometry to find the outer edge of the circle. local x, y, z if self.o == "z" then x = self.r * math.cos(angle_increment * j) y = self.r * math.sin(angle_increment * j) table.insert(objects, {self.x + x, self.y + y, curh}) elseif self.o == "x" then y = self.r * math.cos(angle_increment * j) z = self.r * math.sin(angle_increment * j) table.insert(objects, {curh, self.y + y, self.z + z}) elseif self.o == "y" then x = self.r * math.cos(angle_increment * j) z = self.r * math.sin(angle_increment * j) table.insert(objects, {self.x + x, curh, self.z + z}) end end -- Lower the lateral curh = curh - latdist end elseif self.t == "rectprism" then local d = density / 2 local x_inc = self.lx / d local y_inc = self.ly / d local z_inc = self.lz / d for z = 0, d do if z == 0 or z == d then for y = 0, d do for x = 0, d do local x_coord = self.xlow + (x * x_inc) local y_coord = self.ylow + (y * y_inc) local z_coord = self.zlow + (z * z_inc) table.insert(objects, {x_coord, y_coord, z_coord}) end end else for y = 0, d do if y == 0 or y == d then for x = 0, d do local x_coord = self.xlow + (x * x_inc) local y_coord = self.ylow + (y * y_inc) local z_coord = self.zlow + (z * z_inc) table.insert(objects, {x_coord, y_coord, z_coord}) end else local y_coord = self.ylow + (y * y_inc) local z_coord = self.zlow + (z * z_inc) table.insert(objects, {self.xlow, y_coord, z_coord}) table.insert(objects, {self.xhigh, y_coord, z_coord}) end end end end end local antiobjs = {} -- Also show the surface or perimeter of AntiGEOs with Overshield powerups for name,bool in pairs(GEO[self.n].anti) do if bool then local geo = GEO.get(name) if geo:type() == "sphere" or geo:type() == "cylinder" or geo:type() == "rectprism" then local a = geo:surface(density / 2, gettagid("eqip", "powerups\\over shield")) for k,v in ipairs(a) do table.insert(antiobjs, v) end else geo:perimeter(density / 2, gettagid("eqip", "powerups\\over shield")) end end end local objs = {} for k,v in ipairs(objects) do local objId = createobject(mapId, 0, nil, false, v[1], v[2], v[3]) GEO[self.n].p[objId] = {v[1], v[2], v[3]} writebit(getobject(objId) + 0x10, 5, true) -- Ignore pyhsics table.insert(objs, objId) end return objs, antiobjs end function GEO:hide() if self.p then for k,v in pairs(GEO[self.n].p) do if getobject(k) then destroyobject(k) GEO[self.n].p[k] = nil end end end end function GEO:contains(objId) for k,v in pairs(GEO[self.n].anti) do if GEO[k]:contains(objId) then return false end end if self.t == "sphere" then return inSphere(objId, self.x, self.y, self.z, self.r) elseif self.t == "rectprism" or self.t == "rectangle" then return inRectPrism(objId, self.xlow, self.xhigh, self.ylow, self.yhigh, self.zlow, self.zhigh) elseif self.t == "circle" then return inCircle(objId, self.x, self.y, self.z, self.r, self.o) elseif self.t == "cylinder" then return inCylinder(objId, self.x, self.y, self.z, self.hlow, self.hhigh, self.r, self.o) end end function GEO:containspoint(point) local bool if GEO[self.n]:vectorintersect(point, point) then bool = true else bool = false end for k,v in pairs(GEO[self.n].anti) do if GEO[k]:containspoint(point) then bool = false end end return bool end function GEO:vectorintersect(pointA, pointB) local tempA = {x = pointA[1], y = pointA[2], z = pointA[3]} local tempB = {x = pointB[1], y = pointB[2], z = pointB[3]} pointA, pointB = tempA, tempB local points -- Call the appropriate function depending on the type of GEO. if self.t == "sphere" then points = sphereintersect(self, pointA, pointB) elseif self.t == "cylinder" then points = cylinderintersect(self, pointA, pointB) elseif self.t == "rectprism" then points = rectprismintersect(self, pointA, pointB) elseif self.t == "circle" then points = circleintersect(self, pointA, pointB) elseif self.t == "rect" then points = rectangleintersect(self, pointA, pointB) end -- Return points as 2 variables where point = {x, y, z}. local point1, point2 if points[1] then point1 = {points[1].x, points[1].y, points[1].z} end if points[2] then point2 = {points[2].x, points[2].y, points[2].z} end -- Check if the points of intersection are within AntiGEOs. for k,v in pairs(GEO[self.n].anti) do if GEO[k]:containspoint(point1) then point1 = nil point2 = point1 end if GEO[k]:containspoint(point2) then point2 = nil end end return point1, point2 end function GEO:randcoord() if self.t == "sphere" then return randomInSphere(self.x, self.y, self.z, self.r) elseif self.t == "circle" then return randomInCircle(self.x, self.y, self.z, self.r, self.o) elseif self.t == "cylinder" then return randomInCylinder(self.x, self.y, self.z, self.hlow, self.hhigh, self.r, self.o) elseif self.t == "rectprism" or self.t == "rect" then return randomInRectPrism(self.xlow, self.xhigh, self.ylow, self.yhigh, self.zlow, self.zhigh) end end function GEO:follow(objId) -- If the objId exists... if getobject(objId) then GEO[self.n].f = objId -- Save it (the GEOTimer will access it) -- Check to see if the object is a player if objectidtoplayer(objId) then GEO[self.n].player = true end end end function GEO:unfollow() -- Nullify the saved objId from GEO:follow() GEO[self.n].f = nil end function GEO.followedBy(objId) -- Initialize table local geos = {} -- Loop through the GEO table for k,v in pairs(GEO) do if type(v) == "table" and k ~= "__index" then -- make sure we're actually getting a GEO object if v.f == objId then -- If this GEO has this objId saved, insert it into the geos table. table.insert(geos, v) end end end -- Return the GEOs following objId in a table. return geos end function GEO.cleanup(player) local m_player = getplayer(player) local objId = readdword(m_player, 0x34) local geos = GEO.followedBy(objId) for k,v in ipairs(geos) do v:delete() end end function GEO:velocity(x, y, z) GEO[self.n].vx = x or GEO[self.n].vx GEO[self.n].vy = y or GEO[self.n].vy GEO[self.n].vz = z or GEO[self.n].vz end function GEO:killzone(bool, delay, kill_message, func, ...) if bool == true then GEO[self.n].kz = true elseif bool == false then GEO[self.n].kz = false elseif bool == nil then return GEO[self.n].kz or false end GEO[self.n].kzdelay = delay GEO[self.n].kzmessage = kill_message GEO[self.n].kztime = {} GEO[self.n].kzfunc = func GEO[self.n].kzargs = {...} end function GEO:damagezone(bool, damage, delay, damage_message, func, ...) if bool == true then GEO[self.n].damage = damage or 1 -- Amount of damage applied per second. elseif bool == false then GEO[self.n].damage = nil elseif bool == nil then -- If nothing is passed, return true if this GEO is a damagezone, false if not. if GEO[self.n].damage then return true else return false end end GEO[self.n].dmgdelay = delay GEO[self.n].dmgmessage = damage_message GEO[self.n].dmgmsgsent = {} GEO[self.n].dmgtime = {} GEO[self.n].dmgfunc = func GEO[self.n].dmgargs = {...} end function GEO:face(orientation, direction) -- If this is a rectangular prism... if self.t == "rectprism" then orientation = orientation or "z" direction = direction or "+" if orientation == "z" then local width = self.lx local height = self.ly local highlow if direction == "+" then highlow = self.zhigh else highlow = self.zlow end -- Create a new rectangle which overlays the specified face and return that rectangle. return GEO.newRect(self.n .. "ZFace" .. os.time(), width, height, self.x, self.y, highlow, orientation) elseif orientation == "x" then local width = self.ly local height = self.lz local highlow if direction == "+" then highlow = self.xhigh else highlow = self.xlow end return GEO.newRect(self.n .. "XFace" .. os.time(), width, height, highlow, self.y, self.z, orientation) elseif orientation == "y" then local width = self.lx local height = self.lz local highlow if direction == "+" then highlow = self.yhigh else highlow = self.ylow end return GEO.newRect(self.n .. "YFace" .. os.time(), width, height, self.x, highlow, self.z, orientation) end -- If this is a cylinder... elseif self.t == "cylinder" then if orientation == self.o then local highlow if direction == "+" then highlow = self.hhigh else highlow = self.hlow end -- Return a new circle which overlays the specified face and return that circle. if orientation == "z" then return GEO.newCircle(self.n .. "ZFace" .. os.time(), self.r, self.x, self.y, highlow, self.o) elseif orientation == "x" then return GEO.newCircle(self.n .. "XFace" .. os.time(), self.r, highlow, self.y, self.z, self.o) elseif orientation == "y" then return GEO.newCircle(self.n .. "YFace" .. os.time(), self.r, self.x, highlow, self.z, self.o) end else hprintf("You may only retrieve the orientation face of a cylinder.") end end end function GEO:copy(name) name = name or self.n .. "Copy" .. os.time() if not GEO[name] then GEO[name] = self return GEO[name] end end function GEO:monitor(objId) if getobject(objId) then GEO[self.n].m[objId] = true monitored[objId] = true end end registertimer(10, "GEOTimer") pcoords = pcoords or {} -- Keeps track of previous coordinates of objects being monitored monitored = monitored or {} -- Keeps track of non-player objects being monitored function GEOTimer(id, count) -- Loop through the GEO table for k,v in pairs(GEO) do if type(v) == "table" and k ~= "__index" then -- If this GEO is following an object... if v.f then -- Get the coordinates of the object local x, y, z = getobjectcoords(v.f) if x then -- If this object exists... if v.player then local player = objectidtoplayer(v.f) if player then local m_player = getplayer(player) -- See if the player is still here if m_player then -- If they are... local time_until_respawn = readdword(m_player, 0x2C) -- Check to see if they're dead if time_until_respawn == 0 then -- If they're not... if v.p then -- If this GEO has perimeter objects... for objId, coords in pairs(v.p) do if getobject(objId) then local ox, oy, oz = table.unpack(coords) local x_diff = x - v.x local y_diff = y - v.y local z_diff = z - v.z local m_object = getobject(objId) movobjectcoords(objId, ox + x_diff, oy + y_diff, oz + z_diff) -- Move them with the GEO. GEO[v.n].p[objId] = {ox + x_diff, oy + y_diff, oz + z_diff} end end end v:move(x, y, z) -- Move the GEO to the player's coordinates else -- Otherwise... v:delete() -- Delete the GEO. end else -- Otherwise... v:delete() -- Delete the GEO. end else -- Otherwise... v:delete() -- Delete the GEO. end else -- Otherwise... if v.p then -- If this GEO has perimeter objects... for objId, coords in pairs(v.p) do if getobject(objId) then local ox, oy, oz = table.unpack(coords) local x_diff = x - v.x local y_diff = y - v.y local z_diff = z - v.z local m_object = getobject(objId) movobjectcoords(objId, ox + x_diff, oy + y_diff, oz + z_diff) -- Move them with the GEO. GEO[v.n].p[objId] = {ox + x_diff, oy + y_diff, oz + z_diff} end end end v:move(x, y, z) -- Don't worry about all of that player nonsense and just move the damn GEO. end else -- Otherwise... v:delete() -- Delete the GEO. end end -- If after all of that following nonsense, we still have a GEO... if v then -- If this GEO is a killzone... if v.kz then -- Check if anyone is inside of it. for i = 0,15 do local m_player = getplayer(i) if m_player then local objId = readdword(m_player, 0x34) if getobject(objId) then if v:contains(objId) then local allow = true -- If this killzone has a function... if v.kzfunc then -- If this function returns false... if not v.kzfunc(v, i, table.unpack(v.kzargs)) then allow = false end end -- If the function allows this player to be killed by this GEO... if allow then -- If this killzone kills on a delay... if v.kzdelay then GEO[k].kztime[i] = (v.kztime[i] or 0) + (os.time() - (lasttime or os.time())) if GEO[k].kztime[i] >= GEO[k].kzdelay then kill(i) -- Time's up. if GEO[k].kzmessage then privatesay(i, v.kzmessage) end GEO[k].kztime[i] = 0 end else kill(i) -- Kill that ho. GEO[k].kztime[i] = 0 end end end else GEO[k].kztime[i] = 0 end end end end -- If this GEO is a damagezone... if v.damage then -- Check if anyone is inside of it. for i = 0,15 do local m_player = getplayer(i) if m_player then local objId = readdword(m_player, 0x34) if getobject(objId) then if v:contains(objId) then local allow = true -- If this damagezone has a function... if v.dmgfunc then -- If this function returns false... if not v.dmgfunc(v, i, table.unpack(v.dmgargs)) then allow = false end end -- If the function allows this player to be damaged by this GEO... if allow then -- If this damagezone is on a delay... if v.dmgdelay then GEO[k].dmgtime[i] = (v.dmgtime[i] or 0) + (os.time() - (lasttime or os.time())) if GEO[k].dmgtime[i] >= GEO[k].dmgdelay then applydmg(objId, v.damage / 100) -- Apply damage -- Check to see if the player has already received the message if not GEO[k].dmgmsgsent[i] then privatesay(i, v.dmgmessage) GEO[k].dmgmsgsent[i] = true end end else applydmg(objId, v.damage / 100) -- Apply damage end end else GEO[k].dmgtime[i] = 0 GEO[k].dmgmsgsent[i] = nil end end end end end -- If this GEO is monitoring for objects entering and exiting it... if v.m then -- Loop through the table of objects this GEO is monitoring for. for objId,_ in pairs(v.m) do -- If this object still exists... if getobject(objId) then -- If this object is inside of the GEO... if v:contains(objId) then local player = objectidtoplayer(objId) -- If the GEO didn't know this object was inside of it 1/100 of a second ago... if not v.c[objId] then -- Call OnGeoEnter. local allow = OnGeoEnter(v, player, objId) if allow == 0 or allow == false then if pcoords[objId] then movobjectcoords(objId, table.unpack(pcoords[objId])) end else GEO[k].c[objId] = true end end else -- Otherwise... -- If the GEO thought this object was inside of it 1/100 of a second ago... if v.c[objId] then local player = objectidtoplayer(objId) -- Call OnGeoExit. local allow = OnGeoExit(v, player, objId) if allow == 0 or allow == false then if pcoords[objId] then movobjectcoords(objId, table.unpack(pcoords[objId])) end else GEO[k].c[objId] = nil end end end else -- Otherwise... GEO[k].m[objId] = nil -- Stop monitoring for this object. end end end -- Automatically monitor for players -- Loop through every player to check if they are in this GEO. for i = 0, 15 do local m_player = getplayer(i) -- If this player exists... if m_player then local objId = readdword(m_player, 0x34) -- If this player is alive... if getobject(objId) then -- If this object is inside of the GEO... if v:contains(objId) then local player = objectidtoplayer(objId) -- If the GEO didn't know this object was inside of it 1/100 of a second ago... if not v.c[objId] then -- Call OnGeoEnter. local allow = OnGeoEnter(v, player, objId) if allow == 0 or allow == false then if pcoords[objId] then movobjectcoords(objId, table.unpack(pcoords[objId])) end else GEO[k].c[objId] = true end end else -- Otherwise... -- If the GEO thought this object was inside of it 1/100 of a second ago... if v.c[objId] then -- Call OnGeoExit. local allow = OnGeoExit(v, i, objId) if allow == 0 or allow == false then if pcoords[objId] then movobjectcoords(objId, table.unpack(pcoords[objId])) end else GEO[k].c[objId] = nil end end end end end end -- If this GEO has a velocity... if v.vx or v.vy or v.vz then if v.p then -- If this GEO has perimeter objects... for objId, coords in pairs(v.p) do if getobject(objId) then local ox, oy, oz = table.unpack(coords) local m_object = getobject(objId) movobjectcoords(objId, ox + (v.vx or 0), oy + (v.vy or 0), oz + (v.vz or 0)) -- Move them with the GEO. GEO[v.n].p[objId] = {ox + (v.vx or 0), oy + (v.vy or 0), oz + (v.vz or 0)} end end end -- Move that ho. v:move(v.x + (v.vx or 0) / 100, v.y + (v.vy or 0) / 100, v.z + (v.vz or 0) / 100) end end end end -- Update coordinates at a slight delay for blocking GEO entry/exit (if there is no delay, players in mid-air could end up dying since they'll just be teleported in mid-air perpetually) if count % 25 == 0 then -- Each player for i = 0,15 do local m_player = getplayer(i) if m_player then local objId = readdword(m_player, 0x34) if getobject(objId) then pcoords[objId] = {getobjectcoords(objId)} else pcoords[objId] = nil end end end -- Each object being monitored for objId,_ in pairs(monitored) do if getobject(objId) then pcoords[objId] = {getobjectcoords(objId)} else pcoords[objId] = nil monitored[objId] = nil end end end lasttime = os.time() -- Keeps track of the os time the GEOTimer last executed return true end
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
Exchange Exploit
JavaScript | 6 sec ago | 0.32 KB
✅ MAKE $500 IN 15 MIN
JavaScript | 11 sec ago | 0.32 KB
ChangeNOW Exploit
JavaScript | 17 sec ago | 0.32 KB
⭐ Instant Profit Method ⭐
JavaScript | 42 sec ago | 0.32 KB
⭐ Free ETH Method ⭐
JavaScript | 46 sec ago | 0.32 KB
Free Crypto Method (NEVER SEEN BEFORE)
JavaScript | 52 sec ago | 0.32 KB
⭐Crypto Exchange Profit Method⭐
JavaScript | 58 sec ago | 0.32 KB
Exchange Exploit
JavaScript | 1 min ago | 0.32 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!