Advertisement
rockbandcheeseman

GEO

Jul 20th, 2013
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 50.62 KB | None | 0 0
  1. -- GEOs (Geometric Environment Objects) for Phasor 2.0
  2.  
  3. --[[
  4.     Documentation:
  5.    
  6.     This script allows the creation of environmental volumes in the shapes of spheres, rectangular prisms, cylinders, rectangles, or circles.
  7.     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.
  8.     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.
  9.    
  10.     Changes from GEOs for Phasor 058 and GEOs for 2.0:
  11.    
  12.         -- GEO:damagezone now has the following function header:  GEO:damagezone(boolean, damage).
  13.         -- GEO:freeze has been changed to GEO:unfollow.
  14.    
  15.     GEO Creation Functions:
  16.  
  17.     GEO.newSphere(name, radius, x_coord, y_coord, z_coord)
  18.    
  19.         -- name: <string> Name of this new GEO (must be unique).
  20.         -- radius: <float> Radius of this sphere.
  21.         -- x_coord: <float> X-coordinate of the center of this sphere.
  22.         -- y_coord: <float> Y-coordinate of the center of this sphere.
  23.         -- z_coord: <float> Z-coordinate of the center of this sphere.
  24.        
  25.         Example:
  26.            
  27.             local sphere = GEO.newSphere("Sphere1", 5, 0, 0, 0)
  28.            
  29.         Notes:
  30.        
  31.             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.
  32.  
  33.     GEO.newRectPrism(name, x_length, y_length, z_length, x_coord, y_coord, z_coord)
  34.    
  35.         -- name: <string> Name of this new GEO (must be unique).
  36.         -- x_length: <float> Length of this rectangular prism in the X direction.
  37.         -- y_length: <float> Length of this rectangular prism in the Y direction.
  38.         -- z_length: <float> Length of this rectangular prism in the Z direction.
  39.         -- x_coord: <float> X-coordinate of the center of this rectangular prism.
  40.         -- y_coord: <float> Y-coordinate of the center of this rectangular prism.
  41.         -- z_coord: <float> Z-coordinate of the center of this rectangular prism.
  42.    
  43.         Example:
  44.  
  45.             local rectprism = GEO.newRectPrism("RectPrism1", 3, 3, 10, 0, 0, 5)
  46.            
  47.         Notes:
  48.            
  49.             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.
  50.  
  51.     GEO.newCylinder(name, radius, height, x_coord, y_coord, z_coord)
  52.    
  53.         -- name: <string> Name of this new GEO (must be unique).
  54.         -- radius: <float> Radius of this cylinder.
  55.         -- height: <float> Height of this cylinder.
  56.         -- x_coord: <float> X-coordinate of the center of this cylinder.
  57.         -- y_coord: <float> Y-coordinate of the center of this cylinder.
  58.         -- z_coord: <float> Z-coordinate of the center of this cylinder.
  59.    
  60.         Example:
  61.        
  62.             local cylinder = GEO.newCylinder("Cylinder1", 3, 10, 0, 0, 0)
  63.    
  64.         Notes:
  65.            
  66.             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.
  67.  
  68.     GEO.newRect(name, width, height, x_coord, y_coord, z_coord, [orientation])
  69.    
  70.         -- name: <string> Name of this new GEO (must be unique).
  71.         -- width: <float> Width of this rectangle.
  72.         -- height: <float> Height of this rectangle.
  73.         -- x_coord: <float> X-coordinate of the center of this rectangle.
  74.         -- y_coord: <float> Y-coordinate of the center of this rectangle.
  75.         -- z_coord: <float> Z-coordinate of the center of this rectangle.
  76.         -- orientation: <string> Axis of orientation ("x", "y", or "z") (default = "z").
  77.        
  78.         Example:
  79.  
  80.             local rectangle = GEO.newRect("Rect1", 5, 10, 0, 0, 5, "x")
  81.            
  82.         Notes:
  83.        
  84.             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.
  85.  
  86.     GEO.newCircle(name, radius, x_coord, y_coord, z_coord, [orientation])
  87.    
  88.         -- name: <string> Name of this new GEO (must be unique).
  89.         -- radius: <float> Radius of this circle.
  90.         -- x_coord: <float> X-coordinate of the center of this circle.
  91.         -- y_coord: <float> Y-coordinate of the center of this circle.
  92.         -- z_coord: <float> Z-coordinate of the center of this circle.
  93.         -- orientation: <string> Axis of orientation ("x", "y", or "z") (default = "z")
  94.        
  95.         Example:
  96.  
  97.             local circle = GEO.newCircle("Circle1", 10, 0, 0, 5, "x")
  98.  
  99.         Notes:
  100.        
  101.             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 orienation 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.
  102.  
  103.  
  104.     Once you've created your GEO, you want to make it do something. The following are GEO-editing functions.
  105.     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.
  106.    
  107.     GEO Editing Functions:
  108.  
  109.     GEO:delete()
  110.    
  111.         Example:
  112.  
  113.             local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0)
  114.             sphere:delete()
  115.  
  116.         Notes:
  117.            
  118.             Deletes the specified GEO.
  119.    
  120.     GEO:move(x_coord, y_coord, z_coord)
  121.    
  122.         -- x_coord: <float> New x-coordinate of the center of this GEO.
  123.         -- y_coord: <float> New y-coordinate of the center of this GEO.
  124.         -- z_coord: <float> New z-coordinate of the center of this GEO.
  125.    
  126.         Example:
  127.  
  128.             local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0)
  129.             sphere:move(0, 0, 10)
  130.        
  131.         Notes:
  132.    
  133.             Moves the center of the specified GEO to the specified x, y, and z-coordinates.
  134.  
  135.     GEO:radius([new_radius])
  136.    
  137.         -- new_radius: <float> New radius of specified GEO (if no radius is specified, the radius of the GEO is returned).
  138.    
  139.         Example:
  140.  
  141.             local cylinder = GEO.newCylinder("Cylinder", 10, 20, 0, 0, 0)
  142.             local cyl_radius = cylinder:radius()
  143.             if cyl_radius < 20 then
  144.                 cylinder:radius(20)
  145.             end
  146.            
  147.         Notes:
  148.  
  149.             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.
  150.  
  151.     GEO:size([x_length], [y_length], [z_length])
  152.    
  153.         -- x_length: <float> New length of GEO in the x direction.
  154.         -- y_length: <float> New length of GEO in the y direction.
  155.         -- z_length: <float> New length of GEO in the z direction.
  156.         -- Read the notes for descriptions about how the optional parameters work in this function.
  157.    
  158.         Example:
  159.  
  160.             -- Create three GEOs
  161.             local rectprism = GEO.newRectPrism("RectPrism", 5, 5, 10, 0, 0, 5)
  162.             local rectangle = GEO.newRect("Rect", 5, 10, 0, 0, 5, "y")
  163.             local cylinder = GEO.newCylinder("Cylinder", 5, 20, 0, 0, 10)
  164.  
  165.             -- Get sizes of all three shapes
  166.             local rpx, rpy, rpz = rectprism:size()
  167.             local rw, rh = rectangle:size()
  168.             local cyl_height = cylinder:size()
  169.  
  170.             -- Double their sizes
  171.             rectprism:size(rpx * 2, rpy * 2, rpz * 2)
  172.             rectangle:size(rw * 2, 0, rh * 2)
  173.             cylinder:size(cyl_height * 2)
  174.  
  175.         Notes:
  176.    
  177.             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).
  178.    
  179.     GEO:contains(objId)
  180.    
  181.         objId: <object id> Object being tested to see if it is inside of the specfied GEO.
  182.    
  183.         Example:
  184.  
  185.             local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0)
  186.  
  187.             function OnPlayerSpawn(player)
  188.            
  189.                 local m_player = getplayer(player)
  190.                 local objId = readdword(m_player, 0x34)
  191.  
  192.                 if sphere:contains(objId) then
  193.                     say(getname(player) .. " has spawned inside of the sphere")
  194.                 end
  195.             end
  196.            
  197.         Notes:
  198.    
  199.             Checks if the specified objId is within the specified GEO. Returns true or false.
  200.  
  201.     GEO:follow(objId)
  202.    
  203.         objId: <object id> Object this GEO should follow.
  204.    
  205.         Example:
  206.  
  207.             function OnPlayerSpawn(player)
  208.  
  209.                 local m_player = getplayer(player)
  210.                 local objId = readdword(m_player, 0x34)
  211.                
  212.                 -- Create a sphere with the objId in the name so you know it is unique
  213.                 local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0)
  214.                 sphere:follow(objId)
  215.             end
  216.            
  217.         Notes:
  218.        
  219.             Sets a GEO to follow the specified objId. The GEO will be automatically deleted if the object it is following has also been deleted.
  220.  
  221.  
  222.     GEO:unfollow()
  223.    
  224.         Example:
  225.  
  226.             function OnPlayerSpawn(player)
  227.            
  228.                 local m_player = getplayer(player)
  229.                 local objId = readdword(m_player, 0x34)
  230.  
  231.                 -- Create a sphere with the objId in the name so you know it is unique
  232.                 local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0)
  233.                 sphere:follow(objId)
  234.                 sphere:unfollow()
  235.             end
  236.  
  237.         Notes:
  238.        
  239.             Tells the specified GEO to stop following the objId it is currently following.
  240.  
  241.     GEO:velocity(x_velocity, y_velocity, z_velocity)
  242.    
  243.         x_velocity: <float> GEO's velocity in the x direction.
  244.         y_velocity: <float> GEO's velocity in the y direction.
  245.         z_velocity: <float> GEO's velocity in the z direction.
  246.    
  247.         Example:
  248.  
  249.             local rectangle = GEO.newRectPrism("RectPrism", math.inf, math.inf, 100, 0, 0, -50)
  250.             rectangle:velocity(0, 0, 0.1)
  251.  
  252.         Notes:
  253.    
  254.             Sets the velocity of the specified GEO in the x, y, and z directions.
  255.    
  256.     GEO:killzone([boolean])
  257.    
  258.         boolean: <boolean> The ability of this GEO to be a killzone (if no boolean is specified, the current killzone boolean is returned).
  259.    
  260.         Example:
  261.  
  262.             local killsphere = GEO.newSphere("Sphere", 10, 0, 0, 0)
  263.             killsphere:killzone(true)
  264.  
  265.         Notes:
  266.    
  267.             Toggles the ability for a GEO to be a killzone. If a GEO is a killzone, any player to enter the GEO will automatically die.
  268.    
  269.     GEO:damagezone(boolean, damage)
  270.    
  271.         boolean: <boolean> Indicates whether or not this GEO is a damagezone (if no boolean is specified, the current damagezone boolean is returned).
  272.         damage: <float> Amount of damage per second this GEO does to a player within it.
  273.            
  274.         Example:
  275.  
  276.             local damagesphere = GEO.newSphere("Sphere", 10, 0, 0, 0)
  277.             damagesphere:damagezone(true, 10)
  278.  
  279.         Notes:
  280.            
  281.             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.
  282.  
  283.     GEO:face(orientation, direction)
  284.    
  285.         orientation: <string> The axis on which the face will be created ("x", "y", or "z").
  286.         direction: <string> The specification of the "top" or "bottom" face in the specified orientation ("+" or "-").
  287.    
  288.         Example:
  289.  
  290.             local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 5)
  291.             local topcircle = cylinder:face("z", "+")
  292.             local bottomcircle = cylinder:face("z", "-")
  293.  
  294.         Notes:
  295.    
  296.             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.
  297.    
  298.     GEO:extend(orientation, direction, amount)
  299.    
  300.         orientation: <string> The axis on which the face will be extended ("x", "y", or "z").
  301.         direction: <string> The specification of the "top" or "bottom" face in the specified orientation ("+" or "-").
  302.         amount: <float> Distance the specified face will be extended.
  303.    
  304.         Example:
  305.  
  306.             local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 5)
  307.             cylinder:extend("z", "+", 10)
  308.  
  309.         Notes:
  310.    
  311.             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.
  312.    
  313.     GEO:copy([name])
  314.    
  315.         name: <string> Name given to the copy of the specified GEO (if no name is specified, a default name is given).
  316.        
  317.         Example:
  318.  
  319.             local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0)
  320.             local sphere2 = sphere:copy()
  321.  
  322.         Notes:
  323.        
  324.             Returns a copy of the specified GEO with the specified name. If no name is specified, a default name will be given.
  325.    
  326.     GEO:monitor(objId)
  327.    
  328.         objId: <object id> The object this GEO should monitor for entering/exiting.
  329.    
  330.         Example:
  331.  
  332.             local rectprism = GEO.newRectPrism("RectPrism", math.inf, math.inf, 100, 0, 0, -50)
  333.  
  334.             function OnPlayerSpawn(player)
  335.            
  336.                 local m_player = getplayer(player)
  337.                 local objId = readdword(m_player, 0x34)
  338.  
  339.                 -- Tells rectprism to monitor this newly-created objId for entering and exiting.
  340.                 rectprism:monitor(objId)
  341.             end
  342.        
  343.         Notes:
  344.    
  345.             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.
  346.  
  347.     GEO:coords()
  348.    
  349.         Example:
  350.  
  351.             local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0)
  352.             local x, y, z = sphere:coords()
  353.  
  354.         Notes:
  355.    
  356.             Returns the x, y, and z coordinates of the center of the specified GEO.
  357.    
  358.  
  359.     GEO:high(orientation)
  360.    
  361.         orientation: <string> Axis of which you're attempting to find the highest point ("x", "y", or "z").
  362.        
  363.         Example:
  364.  
  365.             local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0)
  366.             local zhigh = sphere:high("z")
  367.  
  368.         Notes:
  369.    
  370.             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).
  371.  
  372.     GEO:low(orientation)
  373.    
  374.         orientation: <string> Axis of which you're attempting to find the lowest point ("x", "y", or "z")
  375.    
  376.         Example:
  377.  
  378.             local sphere = GEO.newSphere("Sphere", 10, 0, 0, 0)
  379.             local zlow = sphere:low("z")
  380.  
  381.         Notes:
  382.    
  383.             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).
  384.  
  385.     GEO:randcoords()
  386.    
  387.         Example:
  388.  
  389.             local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0)
  390.             local x, y, z = cylinder:randcoords()
  391.  
  392.         Notes:
  393.    
  394.             Returns random x, y, and z coordinates within the specified GEO.
  395.  
  396.     GEO:type()
  397.    
  398.         Example:
  399.  
  400.             local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0)
  401.             local type = cylinder:type()
  402.            
  403.         Notes:
  404.    
  405.             Returns the type of the specified GEO as a string.
  406.  
  407.     GEO:orientation()
  408.    
  409.         Example:
  410.  
  411.             local cylinder = GEO.newCylinder("Cylinder", 5, 10, 0, 0, 0)
  412.             local circle = cylinder:face("z", "+")
  413.             local orientation = circle:orientation()
  414.            
  415.         Notes:
  416.    
  417.             Returns the orientation of a 2-dimensional GEO. Note that this can only be used on rectangles and circles.
  418.  
  419.     GEO:name()
  420.    
  421.         Example:
  422.  
  423.             local sphere = GEO.newSphere("Sphere", 5, 0, 0, 0)
  424.             local name = sphere:name()
  425.  
  426.         Notes:
  427.    
  428.             Returns the name of the specified GEO.
  429.  
  430.  
  431.     GEO:perimeter(density, [mapId])
  432.    
  433.         density: <int> Amount of objects that should spawn around the perimeter of the GEO.
  434.         mapId: <tag id> The tag of the objects that should spawn around the GEO's perimeter (default = Full-Spectrum Vision)
  435.    
  436.         Example:
  437.  
  438.             local sphere = GEO.newSphere("sphere", 5, 0, 0, 0.5)
  439.             sphere:perimeter(20)
  440.             local rectprism = GEO.newRectPrism("rectprism", 3, 4, 5, 0, 0, 0.5)
  441.             rectprism:perimeter(7, "weap", "weapons\\flag\\flag")
  442.            
  443.         Notes:
  444.    
  445.             Spawns the specified object (given via mapId) with the specified density 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 objects. I believe some Phasor functions (such as OnNewGame) screw up when you try to spawn objects in them.
  446.  
  447.  
  448.     OnGeoEnter and OnGeoExit Event Functions:
  449.  
  450.     OnGeoEnter(geo, player, objId)
  451.        
  452.         geo: <GEO object> The GEO the player or object is entering.
  453.         player: <player memory id> The player entering the GEO.
  454.         objId: <object id> The objId entering the GEO.
  455.    
  456.         Example:
  457.  
  458.             sphere = GEO.newSphere("sphere", 5, 0, 0, 0)
  459.  
  460.             function OnPlayerSpawn(player, objId)
  461.  
  462.                 sphere:monitor(objId)
  463.             end
  464.  
  465.             function OnGeoEnter(geo, player, objId)
  466.  
  467.                 if geo == sphere then
  468.                     privatesay(player, "You may not enter this GEO.")
  469.                     return false
  470.                 end
  471.                
  472.                 return true
  473.             end
  474.        
  475.         Notes:
  476.    
  477.             Called when an object that is being monitored by a GEO enters that GEO. Return 1 to allow players to enter, return 0 to disallow this.
  478.  
  479.     OnGeoExit(geo, player, objId)
  480.    
  481.         geo: <GEO object> The GEO the player or object is exiting.
  482.         player: <player memory id> The player exiting the GEO.
  483.         objId: <object id> The objId exiting the GEO.
  484.    
  485.         Example:
  486.  
  487.             sphere = GEO.newSphere("sphere", 5, 0, 0, 0)
  488.  
  489.             function OnPlayerSpawn(player, objId)
  490.  
  491.                 sphere:monitor(objId)
  492.             end
  493.  
  494.             function OnGeoExit(geo, player, objId)
  495.  
  496.                 if geo == sphere then
  497.                     privatesay(player, "You may not exit this GEO.")
  498.                     return false
  499.                 end
  500.                
  501.                 return true
  502.             end
  503.  
  504.         Notes:
  505.    
  506.             Called when an object that is being monitored by a GEO exits that GEO. Return 1 to allow players to exit, return 0 to disallow this.
  507.  
  508.  
  509.     Miscellaneous GEO functions:
  510.  
  511.     GEO.get(name)
  512.    
  513.         name: <string> Name of the GEO you're trying to access.
  514.    
  515.         Example:
  516.  
  517.             function OnPlayerSpawn(player)
  518.            
  519.                 local m_player = getplayer(player)
  520.                 local objId = readdword(m_player, 0x34)
  521.                 local sphere = GEO.newSphere("Sphere" .. objId, 5, 0, 0, 0)
  522.                 sphere:follow(objId)
  523.             end
  524.  
  525.             function OnPlayerKill(killer, victim, mode)
  526.  
  527.                 local m_victim = getplayer(victim)
  528.                 local v_objectId = readdword(m_victim, 0x34)
  529.                 local victim_sphere = GEO.get("Sphere" .. v_objectId)
  530.                 victim_sphere:freeze()
  531.             end
  532.  
  533.         Notes:
  534.    
  535.             Returns a GEO given the specified name.
  536.  
  537.     GEO.followedBy(objId)
  538.    
  539.         objId: <object id> Object being followed by GEOs.
  540.    
  541.         Example:
  542.  
  543.             function OnPlayerKill(killer, victim, mode)
  544.  
  545.                 local geos = GEO.followedBy(victim)
  546.                 for k,v in ipairs(geos) do
  547.                     v:freeze()
  548.                 end
  549.             end
  550.  
  551.         Notes:
  552.    
  553.             Returns a list of GEOs following the specified objId.
  554.    
  555.     GEO.cleanup(player)
  556.    
  557.         player: <player memory id> Player whose following of GEOs you want to delete.
  558.    
  559.         Example:
  560.  
  561.             -- Note that this is here only for the sake of example; this is not necessary, as the GEOTimer takes care of this automatically.
  562.             function OnPlayerKill(killer, victim, mode)
  563.  
  564.                 GEO.cleanup(victim)
  565.             end
  566.  
  567.         Notes:
  568.    
  569.             Deletes all of the GEOs currently following the specified player.
  570.  
  571.    
  572.     If you have any questions about how GEOs work, PM me (Nuggets) at phasor.proboards.com.
  573. --]]
  574.  
  575. -- Create Metatable
  576. GEO = {}
  577. GEO.__index = GEO
  578.  
  579. -- Set random seed and define infinity
  580. math.randomseed(os.time())
  581. math.inf = 1 / 0
  582.  
  583. function inSphere(objId, x, y, z, r)
  584.  
  585.     local ox, oy, oz = getobjectcoords(objId)
  586.     if ox then
  587.         -- Pythagorean
  588.         local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2 + (z - oz) ^ 2)
  589.         if dist <= r then
  590.             return true
  591.         end
  592.     end
  593.    
  594.     return false
  595. end
  596.  
  597. function inCircle(objId, x, y, z, r, orientation)
  598.  
  599.     local ox, oy, oz = getobjectcoords(objId)
  600.     if ox then
  601.         -- Default orientation to "z"
  602.         orientation = orientation or "z"
  603.         -- Pythagorean based on circle's orientation
  604.         if orientation == "z" then
  605.             local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2)
  606.             if dist <= r and oz == z then
  607.                 return true
  608.             end
  609.         elseif orientation == "y" then
  610.             local dist = math.sqrt((x - ox) ^ 2 + (z - oz) ^ 2)
  611.             if dist <= r and oy == y then
  612.                 return true
  613.             end
  614.         elseif orientation == "x" then
  615.             local dist = math.sqrt((y - oy) ^ 2 + (z - oz) ^ 2)
  616.             if dist <= r and ox == x then
  617.                 return true
  618.             end
  619.         end
  620.     end
  621.    
  622.     return false
  623. end
  624.  
  625. function inCylinder(objId, x, y, zlow, zhigh, r)
  626.  
  627.     local ox, oy, oz = getobjectcoords(objId)
  628.     if ox then
  629.         -- Pythagorean to see if object is within radius of circle
  630.         local dist = math.sqrt((x - ox) ^ 2 + (y - oy) ^ 2)
  631.         -- Make sure the object is also within the height of the cylinder
  632.         if dist <= r and z >= zlow and z <= zhigh then
  633.             return true
  634.         end
  635.     end
  636.    
  637.     return false
  638. end
  639.  
  640. function inRectangle(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh)
  641.  
  642.     -- These functions are essentially the same
  643.     return inRectPrism(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh)
  644. end
  645.  
  646. function inRectPrism(objId, xlow, xhigh, ylow, yhigh, zlow, zhigh)
  647.  
  648.     local x, y, z = getobjectcoords(objId)
  649.     if x then
  650.         -- Make sure the coordinates are inside of each extreme of the rectangular prism
  651.         if x <= xhigh and x >= xlow and y <= yhigh and y >= ylow and z <= zhigh and z >= zlow then
  652.             return true
  653.         end
  654.     end
  655.    
  656.     return false
  657. end
  658.  
  659. function randomInSphere(x, y, z, r)
  660.  
  661.     -- Increase precision
  662.     x = math.floor(x * 100)
  663.     y = math.floor(y * 100)
  664.     z = math.floor(z * 100)
  665.     r = math.floor(r * 100)
  666.    
  667.     -- Find random values inside of the sphere.
  668.     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
  669. end
  670.  
  671. function randomInCircle(x, y, z, r, orientation)
  672.  
  673.     -- Increase precision
  674.     r = math.floor(r * 100)
  675.    
  676.     -- Possible values depend on circle's orientation.
  677.     if orientation == "z" then
  678.         x = math.floor(x * 100)
  679.         y = math.floor(y * 100)
  680.         return math.random(x - r, x + r + 1) / 100, math.random(y - r, y + r + 1) / 100,
  681.     elseif orientation == "x" then
  682.         y = math.floor(y * 100)
  683.         z = math.floor(z * 100)
  684.         return x, math.random(y - r, y + r + 1) / 100, math.random(z - r, z + r + 1) / 100
  685.     elseif orientation == "y" then
  686.         x = math.floor(x * 100)
  687.         z = math.floor(z * 100)
  688.         return math.random(x - r, x + r + 1) / 100, y, math.random(z - r, z + r + 1) / 100
  689.     end
  690. end
  691.  
  692. function randomInCylinder(x, y, zlow, zhigh, r)
  693.  
  694.     -- Increase precision
  695.     x = math.floor(x * 100)
  696.     y = math.floor(y * 100)
  697.     zlow = math.floor(zlow * 100)
  698.     zhigh = math.floor(zhigh * 100)
  699.     r = math.floor(r * 100)
  700.    
  701.     -- Find random values inside of the cylinder.
  702.     return math.random(x - r, x + r + 1) / 100, math.random(y - r, y + r + 1) / 100, math.random(zlow, zhigh + 1) / 100
  703. end
  704.  
  705. function randomInRectPrism(xlow, xhigh, ylow, yhigh, zlow, zhigh)
  706.  
  707.     -- Increase precision
  708.     xlow = math.floor(xlow * 100)
  709.     xhigh = math.floor(xhigh * 100)
  710.     ylow = math.floor(ylow * 100)
  711.     yhigh = math.floor(yhigh * 100)
  712.     zlow = math.floor(zlow * 100)
  713.     zhigh = math.floor(zhigh * 100)
  714.    
  715.     -- Find random values inside of the rectangular prism.
  716.     return math.random(xlow, xhigh + 1) / 100, math.random(ylow, yhigh + 1) / 100, math.random(zlow, zhigh)
  717. end
  718.  
  719. -- Object Creation Comments (refer to this function for questions on how the other ones work)
  720. function GEO.newSphere(name, r, x, y, z)
  721.  
  722.     -- Check to see if there is already a GEO with this name.
  723.     if not GEO[name] then
  724.         -- Create new table
  725.         GEO[name] = {}
  726.         GEO[name].t = "sphere"  -- type
  727.         GEO[name].n = name  -- name
  728.         GEO[name].r = r or 1  -- radius (default value of 1)
  729.         GEO[name].x = x or 0  -- x coordinate of center (default value of 0)
  730.         GEO[name].y = y or 0  -- y coordinate of center (default value of 0)
  731.         GEO[name].z = z or 0  -- z coordinate of center (default value of 0)
  732.        
  733.         -- Notify the console that a sphere has been created.
  734.         hprintf("Sphere \"" .. name .. "\" created.")
  735.         setmetatable(GEO[name], GEO)  -- Add this object to the GEO metatable to allow GEO-editing functions to work on it.
  736.         return GEO[name]  -- Return the object
  737.     end
  738.    
  739.     -- If no object was returned, the name was invalid; notify the console.
  740.     hprintf("Invalid name: \"" .. name .. "\"")
  741. end
  742.  
  743. function GEO.newCircle(name, r, x, y, z, orientation)
  744.  
  745.     if not GEO[name] then
  746.         GEO[name] = {}
  747.         GEO[name].t = "circle"
  748.         GEO[name].n = name
  749.         GEO[name].o = orientation or "z"  -- orientation
  750.         GEO[name].r = r or 0
  751.         GEO[name].x = x or 0
  752.         GEO[name].y = y or 0
  753.         GEO[name].z = z or 0
  754.        
  755.         hprintf("Circle \"" .. name .. "\" created.")
  756.         setmetatable(GEO[name], GEO)
  757.         return GEO[name]
  758.     end
  759.    
  760.     hprintf("Invalid name: \"" .. name .. "\"")
  761. end
  762.  
  763. function GEO.newCylinder(name, r, h, x, y, z)
  764.  
  765.     if not GEO[name] then
  766.         GEO[name] = {}
  767.         GEO[name].t = "cylinder"
  768.         GEO[name].n = name
  769.         x = x or 0
  770.         y = y or 0
  771.         z = z or 0
  772.         r = r or 1
  773.         h = h or 1
  774.         GEO[name].x = x
  775.         GEO[name].y = y
  776.         GEO[name].z = z
  777.         GEO[name].r = r
  778.         GEO[name].h = h  -- height
  779.         GEO[name].zlow = z - h / 2  -- lowest z-coordinate still within the cylinder
  780.         GEO[name].zhigh = z + h / 2  -- highest z-coordinate still within the cylinder
  781.        
  782.         hprintf("Cylinder \"" .. name .. "\" created.")
  783.         setmetatable(GEO[name], GEO)
  784.         return GEO[name]
  785.     end
  786. end
  787.  
  788. function GEO.newRectPrism(name, lx, ly, lz, x, y, z)
  789.  
  790.     if not GEO[name] then
  791.         GEO[name] = {}
  792.         GEO[name].t = "rectprism"
  793.         GEO[name].n = name
  794.         lx = lx or 1
  795.         ly = ly or 1
  796.         lz = lz or 1
  797.         x = x or 0
  798.         y = y or 0
  799.         z = z or 0
  800.         GEO[name].lx = lx  -- x length
  801.         GEO[name].ly = ly  -- y length
  802.         GEO[name].lz = lz  -- z length
  803.         GEO[name].x = x
  804.         GEO[name].y = y
  805.         GEO[name].z = z
  806.         GEO[name].xlow = x - lx / 2  -- lowest x-coordinate still within the rectangular prism
  807.         GEO[name].xhigh = lx / 2 + x  -- highest x-coordinate still within in the rectangular prism
  808.         GEO[name].ylow = y - ly / 2  -- lowest y-coordinate still within the rectangular prism
  809.         GEO[name].yhigh = ly / 2 + y  -- highest y-coordinate still within the rectangular prism
  810.         GEO[name].zlow = z - lz / 2  -- lowest z-coordinate still within the rectangular prism
  811.         GEO[name].zhigh = lz / 2 + z  -- highest z-coordinate still within the rectangular prism
  812.        
  813.         hprintf("Rectangular Prism \"" .. name .. "\" created.")
  814.         setmetatable(GEO[name], GEO)
  815.         return GEO[name]
  816.     end
  817.    
  818.     hprintf("Invalid name: \"" .. name .. "\"")
  819. end
  820.  
  821. function GEO.newRect(name, width, height, x, y, z, orientation)
  822.  
  823.     if not GEO[name] then
  824.         GEO[name] = {}
  825.         GEO[name].t = "rectangle"
  826.         GEO[name].n = name
  827.         width = width or 1
  828.         height = height or 1
  829.         x = x or 0
  830.         y = y or 0
  831.         z = z or 0
  832.         orientation = orientation or "z"
  833.         GEO[name].width = width
  834.         GEO[name].height = height
  835.         GEO[name].x = x
  836.         GEO[name].y = y
  837.         GEO[name].z = z
  838.         GEO[name].o = orientation
  839.        
  840.         -- Coordinates' highs and lows depend on orientation
  841.         if orientation == "z" then
  842.             GEO[name].xlow = x - width / 2
  843.             GEO[name].xhigh = x + width / 2
  844.             GEO[name].ylow = y - height / 2
  845.             GEO[name].yhigh = y + height / 2
  846.             GEO[name].zlow = z
  847.             GEO[name].zhigh = z
  848.         elseif orientation == "x" then
  849.             GEO[name].xlow = x
  850.             GEO[name].xhigh = x
  851.             GEO[name].ylow = y - width / 2
  852.             GEO[name].yhigh = y + width / 2
  853.             GEO[name].zlow = z - height / 2
  854.             GEO[name].zhigh = z + height / 2
  855.         elseif orientation == "y" then
  856.             GEO[name].xlow = x - width / 2
  857.             GEO[name].xhigh = x + width / 2
  858.             GEO[name].ylow = y
  859.             GEO[name].yhigh = y
  860.             GEO[name].zlow = z - height / 2
  861.             GEO[name].zhigh = z + height / 2
  862.         end
  863.        
  864.         hprintf("Rectangle \"" .. name .. "\" created.")
  865.         setmetatable(GEO[name], GEO)
  866.         return GEO[name]
  867.     end
  868.    
  869.     hprintf("Invalid name: \""  .. name .. "\"")
  870. end
  871.  
  872. function GEO.get(name)
  873.  
  874.     return GEO[name]
  875. end
  876.  
  877. function GEO:delete()
  878.  
  879.     self:hide()
  880.     GEO[self.n] = nil
  881.     hprintf("Geo \"" .. self.n .. "\" deleted.")
  882. end
  883.  
  884. function GEO:move(x, y, z)
  885.  
  886.     -- Move the center of the object
  887.     -- Default to GEO's current coordinates
  888.     GEO[self.n].x = x or GEO[self.n].x
  889.     GEO[self.n].y = y or GEO[self.n].y
  890.     GEO[self.n].z = z or GEO[self.n].z
  891.    
  892.     -- If this is a rectangular prism...
  893.     if self.t == "rectprism" then
  894.         -- Change the x, y, and z lows and highs accordingly to adjust to the new center
  895.         GEO[self.n].xlow = x - GEO[self.n].lx / 2  
  896.         GEO[self.n].xhigh = GEO[self.n].lx / 2 + x
  897.         GEO[self.n].ylow = y - GEO[self.n].ly / 2
  898.         GEO[self.n].yhigh = GEO[self.n].ly / 2 + y
  899.         GEO[self.n].zlow = z - GEO[self.n].lz / 2
  900.         GEO[self.n].zhigh = GEO[self.n].lz / 2 + z
  901.    
  902.     -- If this is a rectangle...
  903.     elseif self.t == "rectangle" then
  904.         -- Change the x, y, and z lows and highs accordingly to adjust to the new center (depends on orientation)
  905.         if self.o == "z" then
  906.             GEO[self.n].xlow = self.x - self.width / 2
  907.             GEO[self.n].xhigh = self.x + self.width / 2
  908.             GEO[self.n].ylow = self.y - self.height / 2
  909.             GEO[self.n].yhigh = self.y + self.height / 2
  910.             GEO[self.n].zlow = self.z
  911.             GEO[self.n].zhigh = self.z
  912.         elseif self.o == "x" then
  913.             GEO[self.n].xlow = self.x
  914.             GEO[self.n].xhigh = self.x
  915.             GEO[self.n].ylow = self.y - self.width / 2
  916.             GEO[self.n].yhigh = self.y + self.width / 2
  917.             GEO[self.n].zlow = self.z - self.height / 2
  918.             GEO[self.n].zhigh = self.z + self.height / 2
  919.         elseif self.o == "y" then
  920.             GEO[self.n].xlow = self.x - self.width / 2
  921.             GEO[self.n].xhigh = self.x + self.width / 2
  922.             GEO[self.n].ylow = self.y
  923.             GEO[self.n].yhigh = self.y
  924.             GEO[self.n].zlow = self.z - self.height / 2
  925.             GEO[self.n].zhigh = self.z + self.height / 2
  926.         end
  927.    
  928.     -- If this is a cylinder...
  929.     elseif self.t == "cylinder" then
  930.         GEO[self.n].zlow = self.z - self.h / 2
  931.         GEO[self.n].zhigh = self.z + self.h / 2
  932.     end
  933. end
  934.  
  935. function GEO:radius(new)
  936.  
  937.     if self.t == "sphere" or self.t == "circle" or self.t == "cylinder" then
  938.         if new then  -- If "new" is defined...
  939.             GEO[self.n].r = new  -- Change the radius to its value.
  940.         else  -- If not...
  941.             return GEO[self.n].r  -- Return its current radius.
  942.         end
  943.     end
  944. end
  945.  
  946. function GEO:size(x, y, z)
  947.  
  948.     -- If this is a rectangular prism...
  949.     if self.t == "rectprism" then
  950.         if x or y or z then  -- If any of these variables have been defined...
  951.             -- Adjust lengths and x, y, and z highs and lows accordingly.
  952.             GEO[self.n].lx = x or GEO[self.n].lx
  953.             GEO[self.n].ly = y or GEO[self.n].ly
  954.             GEO[self.n].lz = z or GEO[self.n].lz
  955.             GEO[self.n].xlow = GEO[self.n].x - x / 2
  956.             GEO[self.n].xhigh = x / 2 + GEO[self.n].x
  957.             GEO[self.n].ylow = GEO[self.n].y - y / 2
  958.             GEO[self.n].yhigh = y / 2 + GEO[self.n].y
  959.             GEO[self.n].zlow = GEO[self.n].z - z / 2
  960.             GEO[self.n].zhigh = z / 2 + GEO[self.n].z
  961.         else  -- Otherwise...
  962.             return GEO[self.n].lx, GEO[self.n].ly, GEO[self.n].lz  -- Return the x, y, and z lengths.
  963.         end
  964.    
  965.     -- If this is a rectangle...
  966.     elseif self.t == "rectangle" then
  967.         if x or y or z then  -- If any of these variables are defined...
  968.             -- Adjust width, height, and x, y, and z highs and lows accordingly (depends on orientation).
  969.             if self.o == "z" then
  970.                 GEO[self.n].width = x
  971.                 GEO[self.n].height = y
  972.                 GEO[self.n].xlow = self.x - self.width / 2
  973.                 GEO[self.n].xhigh = self.x + self.width / 2
  974.                 GEO[self.n].ylow = self.y - self.height / 2
  975.                 GEO[self.n].yhigh = self.y + self.height / 2
  976.                 GEO[self.n].zlow = self.z
  977.                 GEO[self.n].zhigh = self.z
  978.             elseif self.o == "x" then
  979.                 GEO[self.n].width = y
  980.                 GEO[self.n].height = z
  981.                 GEO[self.n].xlow = self.x
  982.                 GEO[self.n].xhigh = self.x
  983.                 GEO[self.n].ylow = self.y - self.width / 2
  984.                 GEO[self.n].yhigh = self.y + self.width / 2
  985.                 GEO[self.n].zlow = self.z - self.height / 2
  986.                 GEO[self.n].zhigh = self.z + self.height / 2
  987.             elseif self.o == "y" then
  988.                 GEO[self.n].width = x
  989.                 GEO[self.n].height = z
  990.                 GEO[self.n].xlow = self.x - self.width / 2
  991.                 GEO[self.n].xhigh = self.x + self.width / 2
  992.                 GEO[self.n].ylow = self.y
  993.                 GEO[self.n].yhigh = self.y
  994.                 GEO[self.n].zlow = self.z - self.height / 2
  995.                 GEO[self.n].zhigh = self.z + self.height / 2
  996.             end
  997.         else  -- Otherwise...
  998.             return GEO[self.n].width, GEO[self.n].height  -- Return the width and height of the rectangle.
  999.         end
  1000.    
  1001.     -- If this is a cylinder...
  1002.     elseif self.t == "cylinder" then
  1003.         local h = x or y or z  -- Whichever variable is defined, it is taken as the height.
  1004.         if h then  -- If a height is specified...
  1005.             -- Adjust height and z high and low accordingly.
  1006.             GEO[self.n].h = h
  1007.             GEO[self.n].zlow = self.z - h / 2
  1008.             GEO[self.n].zhigh = self.z + h / 2
  1009.         else  -- Otherwise...
  1010.             return GEO[self.n].h  -- Return the height.
  1011.         end
  1012.     end
  1013. end
  1014.  
  1015. function GEO:extend(orienation, direction, amount)
  1016.  
  1017.     -- Change the direction from "+" or "-" to "high" or "low".
  1018.     local dir
  1019.     dir = string.gsub(direction, "-", "low")
  1020.     dir = string.gsub(direction, "+", "high")
  1021.    
  1022.     -- Get the face we're trying to extend (i.e. "xhigh")
  1023.     local face = string.lower(orientation) .. direction
  1024.    
  1025.     -- If this is a rectangular prism or a rectangle...
  1026.     if self.t == "rectprism" or self.t == "rectangle" then
  1027.         -- Make sure "face" is actually a valid face (and not something like "cheesederp")
  1028.         if self[face] then
  1029.             -- 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.
  1030.             -- Change the length of the GEO in the orientation specified.
  1031.             GEO[self.n]["l" .. string.lower(orientation)] = self["l" .. string.lower(orientation)] + amount
  1032.            
  1033.             -- Figure out if the positive or negative face is being extended.
  1034.             if direction == "+" then
  1035.                 GEO[self.n][face] = self[face] + amount
  1036.                 GEO[self.n][string.lower(orientation)] = self[string.lower(orientation)] + amount / 2
  1037.             else
  1038.                 GEO[self.n][face] = self[face] - amount
  1039.                 GEO[self.n][string.lower(orientation)] = self[string.lower(orientation)] - amount / 2
  1040.             end
  1041.         end
  1042.    
  1043.     -- If this is a cylinder...
  1044.     elseif self.t == "cylinder" then
  1045.         -- The orientation must be "z"
  1046.         if orientation == "z" then
  1047.             if self[face] then
  1048.                 GEO[self.n].h = self.h + amount
  1049.                
  1050.                 -- Figure out if the top or bottom face is being extended.
  1051.                 if direction == "+" then
  1052.                     GEO[self.n][face] = self[face] + amount
  1053.                     GEO[self.n].z = self.z + amount / 2
  1054.                 else
  1055.                     GEO[self.n][face] = self[face] - amount
  1056.                     GEO[self.n].z = self.z - amount / 2
  1057.                 end
  1058.             end
  1059.         end
  1060.     end
  1061. end
  1062.  
  1063. function GEO:coords()
  1064.  
  1065.     return self.x, self.y, self.z
  1066. end
  1067.  
  1068. function GEO:high(orientation)
  1069.  
  1070.     if self.t == "sphere" or self.t == "circle" then
  1071.         return self[orientation] + self.r
  1072.     elseif self.t == "rectprism" or self.t == "rectangle" then
  1073.         return self[orientation .. "high"]
  1074.     elseif self.t == "cylinder" then
  1075.         if orientation == "z" then
  1076.             return self.zhigh
  1077.         else
  1078.             return self[orientation] + self.r
  1079.         end
  1080.     end    
  1081. end
  1082.  
  1083. function GEO:low(orientation)
  1084.  
  1085.     if self.t == "sphere" or self.t == "circle" then
  1086.         return self[orientation] - self.r
  1087.     elseif self.t == "rectprism" or self.t == "rectangle" then
  1088.         return self[orientation .. "low"]
  1089.     elseif self.t == "cylinder" then
  1090.         if orientation == "z" then
  1091.             return self.zlow
  1092.         else
  1093.             return self[orientation] - self.r
  1094.         end
  1095.     end    
  1096. end
  1097.  
  1098. function GEO:randcoords()
  1099.  
  1100.     if self.t == "sphere" then
  1101.         return randomInSphere(self.x, self.y, self.z, self.r)
  1102.     elseif self.t == "circle" then
  1103.         return randomInCircle(self.x, self.y, self.z, self.r, self.o)
  1104.     elseif self.t == "cylinder" then
  1105.         return randomInCylinder(self.x, self.y, self.zlow, self.zhigh, self.r)
  1106.     elseif self.t == "rectprism" or self.t == "rectangle" then
  1107.         return randomInRectPrism(self.xlow, self.xhigh, self.ylow, self.yhigh, self.zlow, self.zhigh)
  1108.     end
  1109. end
  1110.  
  1111. function GEO:type()
  1112.  
  1113.     return self.t
  1114. end
  1115.  
  1116. function GEO:orientation()
  1117.  
  1118.     return self.o
  1119. end
  1120.  
  1121. function GEO:name()
  1122.  
  1123.     return self.n
  1124. end
  1125.  
  1126. function GEO:perimeter(density, mapId)
  1127.    
  1128.     -- Default density to 10
  1129.     density = density or 10
  1130.    
  1131.     -- Default tagtype and tagname to Full-Spectrum Visions
  1132.     mapId = mapId or gettagid("eqip", "powerups\\full-spectrum vision")
  1133.    
  1134.     tagname, tagtype = gettaginfo(mapId)
  1135.    
  1136.     -- Store all of the perimeter objects in a table
  1137.     GEO[self.n].p = GEO[self.n].p or {}
  1138.    
  1139.     -- Find the change in angle per point from 0 - 2pi (0° - 360°)
  1140.     local angle_increment = 2 * math.pi / density
  1141.     if self.t == "sphere" or self.t == "cylinder" then
  1142.         for i = 1,density do
  1143.             -- 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).
  1144.             local x = self.r * math.cos(angle_increment * i)
  1145.             local y = self.r * math.sin(angle_increment * i)
  1146.             local z = self.z
  1147.             local objId = createobject(mapId, 0, 0, false, self.x + x, self.y + y, self.z + z)
  1148.             GEO[self.n].p[objId] = {self.x + x, self.y + y, self.z + z}
  1149.         end
  1150.     elseif self.t == "circle" then
  1151.         if self.o == "z" then
  1152.             for i = 1,density do
  1153.                 -- 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).
  1154.                 local x = self.r * math.cos(angle_increment * i)
  1155.                 local y = self.r * math.sin(angle_increment * i)
  1156.                 local z = self.z
  1157.                 local objId = createobject(mapId, 0, 0, false, self.x + x, self.y + y, self.z + z)
  1158.                 GEO[self.n].p[objId] = {self.x + x, self.y + y, self.z + z}
  1159.             end
  1160.         end
  1161.     elseif self.t == "rectprism" or self.t == "rectangle" then
  1162.         if self.t == "rectangle" then
  1163.             if self.o ~= "z" then return end
  1164.         end
  1165.         -- Create points at four corners of the rectangle
  1166.         local o1 = createobject(mapId, 0, 0, false, self.xhigh, self.yhigh, self.z)
  1167.         local o2 = createobject(mapId, 0, 0, false, self.xhigh, self.ylow, self.z)
  1168.         local o3 = createobject(mapId, 0, 0, false, self.xlow, self.yhigh, self.z)
  1169.         local o4 = createobject(mapId, 0, 0, false, self.xlow, self.ylow, self.z)
  1170.         GEO[self.n].p[o1] = {self.xhigh, self.yhigh, self.z}
  1171.         GEO[self.n].p[o2] = {self.xhigh, self.yhigh, self.z}
  1172.         GEO[self.n].p[o3] = {self.xhigh, self.yhigh, self.z}
  1173.         GEO[self.n].p[o4] = {self.xhigh, self.yhigh, self.z}
  1174.        
  1175.         for i = 1,density do
  1176.             local herp = createobject(mapId, 0, 0, false, self.xhigh - (i * self.lx / density), self.yhigh, self.z)
  1177.             local derp = createobject(mapId, 0, 0, false, self.xhigh, self.yhigh - (i * self.ly / density), self.z)
  1178.             local weee = createobject(mapId, 0, 0, false, self.xhigh - (i * self.lx / density), self.ylow, self.z)
  1179.             local cheese = createobject(mapId, 0, 0, false, self.xlow, self.ylow + (i * self.ly / density), self.z)
  1180.             GEO[self.n].p[herp] = {self.xhigh - (i * self.lx / density), self.yhigh, self.z}
  1181.             GEO[self.n].p[derp] = {self.xhigh, self.yhigh - (i * self.ly / density), self.z}
  1182.             GEO[self.n].p[weee] = {self.xhigh - (i * self.lx / density), self.ylow, self.z}
  1183.             GEO[self.n].p[cheese] = {self.xlow, self.ylow + (i * self.ly / density), self.z}
  1184.         end
  1185.     end
  1186. end
  1187.  
  1188. function GEO:hide()
  1189.  
  1190.     if self.p then
  1191.         for k,v in pairs(GEO[self.n].p) do
  1192.             if getobject(k) then
  1193.                 destroyobject(k)
  1194.                 GEO[self.n].p[k] = nil
  1195.             end
  1196.         end
  1197.     end
  1198. end
  1199.  
  1200. -- Never quite got this to work right, but I'm saving it for the sake of the formula.
  1201. --[[function GEO:surface(density)
  1202.  
  1203.     GEO[self.n].p = GEO[self.n].p or {}
  1204.     if self.t == "sphere" then
  1205.         local inc = math.pi * (3 - math.sqrt(5))
  1206.         local off = 2 / density
  1207.         for i = 1,density do
  1208.             local y = self.r * i * off - 1 + (off / 2)
  1209.             local r = self.r * math.sqrt(1 - y ^ 2)
  1210.             local phi = i * inc
  1211.             local x = r * math.cos(phi)
  1212.             local z = r * math.sin(phi)
  1213.             local objId = createobject(mapId, 0, 0, false, x, y, z)
  1214.             GEO[self.n].p[objId] = {x, y, z}
  1215.         end
  1216.     end
  1217. end--]]
  1218.  
  1219. function GEO:contains(objId)
  1220.  
  1221.     if self.t == "sphere" then
  1222.         return inSphere(objId, self.x, self.y, self.z, self.r)
  1223.     elseif self.t == "rectprism" or self.t == "rectangle" then
  1224.         return inRectPrism(objId, self.xlow, self.xhigh, self.ylow, self.yhigh, self.zlow, self.zhigh)
  1225.     elseif self.t == "circle" then
  1226.         return inCircle(objId, self.x, self.y, self.z, self.r, self.o)
  1227.     elseif self.t == "cylinder" then
  1228.         return inCylinder(objId, self.x, self.y, self.zlow, self.zhigh, self.r)
  1229.     end
  1230. end
  1231.  
  1232. function GEO:follow(objId)
  1233.  
  1234.     -- If the objId exists...
  1235.     if getobject(objId) then
  1236.         GEO[self.n].f = objId  -- Save it (the GEOTimer will access it)
  1237.         -- Check to see if the object is a player
  1238.         if objectidtoplayer(objId) then
  1239.             GEO[self.n].player = true
  1240.         end
  1241.     end
  1242. end
  1243.  
  1244. function GEO:unfollow()
  1245.  
  1246.     -- Nullify the saved objId from GEO:follow()
  1247.     GEO[self.n].f = nil
  1248. end
  1249.  
  1250. function GEO.followedBy(objId)
  1251.  
  1252.     -- Initialize table
  1253.     local geos = {}
  1254.    
  1255.     -- Loop through the GEO table
  1256.     for k,v in pairs(GEO) do
  1257.         if type(v) == "table" and k ~= "__index" then  -- make sure we're actually getting a GEO object
  1258.             if v.f == objId then
  1259.                 -- If this GEO has this objId saved, insert it into the geos table.
  1260.                 table.insert(geos, v)
  1261.             end
  1262.         end
  1263.     end
  1264.    
  1265.     -- Return the GEOs following objId in a table.
  1266.     return geos
  1267. end
  1268.  
  1269. function GEO.cleanup(player)
  1270.  
  1271.     local m_player = getplayer(player)
  1272.     local objId = readdword(m_player, 0x34)
  1273.     local geos = GEO.followedBy(objId)
  1274.     for k,v in ipairs(geos) do
  1275.         v:delete()
  1276.     end
  1277. end
  1278.  
  1279. function GEO:velocity(x, y, z)
  1280.  
  1281.     GEO[self.n].vx = x or GEO[self.n].vx
  1282.     GEO[self.n].vy = y or GEO[self.n].vy
  1283.     GEO[self.n].vz = z or GEO[self.n].vz
  1284. end
  1285.  
  1286. function GEO:killzone(bool)
  1287.  
  1288.     if bool == true then
  1289.         GEO[self.n].kz = true
  1290.     elseif bool == false then
  1291.         GEO[self.n].kz = false
  1292.     elseif bool == nil then
  1293.         return GEO[self.n].kz or false
  1294.     end
  1295. end
  1296.  
  1297. function GEO:damagezone(bool, damage)
  1298.  
  1299.     if bool == true then
  1300.         GEO[self.n].damage = damage or 1  -- Amount of damage applied per second.
  1301.     elseif bool == false then
  1302.         GEO[self.n].damage = nil
  1303.     elseif bool == nil then  -- If nothing is passed, return true if this GEO is a damagezone, false if not.
  1304.         if GEO[self.n].damage then
  1305.             return true
  1306.         else
  1307.             return false
  1308.         end
  1309.     end
  1310. end
  1311.  
  1312. function GEO:face(orientation, direction)
  1313.  
  1314.     -- If this is a rectangular prism...
  1315.     if self.t == "rectprism" then
  1316.         orientation = orientation or "z"
  1317.         direction = direction or "+"
  1318.         if orientation == "z" then
  1319.             local width = self.lx
  1320.             local height = self.ly
  1321.             local highlow
  1322.             if direction == "+" then
  1323.                 highlow = self.zhigh
  1324.             else
  1325.                 highlow = self.zlow
  1326.             end
  1327.            
  1328.             -- Create a new rectangle which overlays the specified face and return that rectangle.
  1329.             return GEO.newRect(self.n .. "ZFace" .. os.time(), width, height, self.x, self.y, highlow, orientation)
  1330.            
  1331.         elseif orientation == "x" then
  1332.             local width = self.ly
  1333.             local height = self.lz
  1334.             local highlow
  1335.             if direction == "+" then
  1336.                 highlow = self.xhigh
  1337.             else
  1338.                 highlow = self.xlow
  1339.             end
  1340.            
  1341.             return GEO.newRect(self.n .. "XFace" .. os.time(), width, height, highlow, self.y, self.z, orientation)
  1342.        
  1343.         elseif orientation == "y" then
  1344.             local width = self.lx
  1345.             local height = self.lz
  1346.             local highlow
  1347.             if direction == "+" then
  1348.                 highlow = self.yhigh
  1349.             else
  1350.                 highlow = self.ylow
  1351.             end
  1352.            
  1353.             return GEO.newRect(self.n .. "YFace" .. os.time(), width, height, self.x, highlow, self.z, orientation)
  1354.         end
  1355.    
  1356.     -- If this is a cylinder...
  1357.     elseif self.t == "cylinder" then
  1358.         if orientation == "z" then
  1359.             local highlow
  1360.             if direction == "+" then
  1361.                 highlow = self.zhigh
  1362.             else
  1363.                 highlow = self.zlow
  1364.             end
  1365.            
  1366.             -- Return a new circle which overlays the specified face and return that circle.
  1367.             return GEO.newCircle(self.n .. "ZFace" .. os.time(), self.r, self.x, self.y, highlow, "z")
  1368.         else
  1369.             hprintf("You may only retrieve the Z face of a cylinder.")
  1370.         end
  1371.     end
  1372. end
  1373.  
  1374. function GEO:copy(name)
  1375.  
  1376.     name = name or self.n .. "Copy" .. os.time()
  1377.     if not GEO[name] then
  1378.         GEO[name] = self
  1379.         return GEO[name]
  1380.     end
  1381. end
  1382.  
  1383. function GEO:monitor(objId)
  1384.  
  1385.     if getobject(objId) then
  1386.         GEO[self.n].m = GEO[self.n].m or {}
  1387.         GEO[self.n].c = GEO[self.n].c or {}
  1388.         GEO[self.n].m[objId] = true
  1389.     end
  1390. end
  1391.  
  1392. registertimer(10, "GEOTimer")
  1393.  
  1394. function GEOTimer(id, count)
  1395.  
  1396.     -- Create a coordinates table for players if it hasn't already been created
  1397.     pcoords = pcoords or {}
  1398.    
  1399.     -- Loop through the GEO table
  1400.     for k,v in pairs(GEO) do
  1401.         if type(v) == "table" and k ~= "__index" then
  1402.             -- If this GEO is following an object...
  1403.             if v.f then
  1404.                 -- Get the coordinates of the object
  1405.                 local x, y, z = getobjectcoords(v.f)
  1406.                 if x then  -- If this object exists...
  1407.                     if v.player then
  1408.                         local player = objectidtoplayer(v.f)
  1409.                         if player then
  1410.                             local m_player = getplayer(player)  -- See if the player is still here
  1411.                             if m_player then  -- If they are...
  1412.                                 local time_until_respawn = readdword(m_player, 0x2C)  -- Check to see if they're dead
  1413.                                 if time_until_respawn == 0 then  -- If they're not...
  1414.                                     if v.p then  -- If this GEO has perimeter objects...
  1415.                                         for objId, coords in pairs(v.p) do
  1416.                                             if getobject(objId) then
  1417.                                                 local ox, oy, oz = table.unpack(coords)
  1418.                                                 local x_diff = x - v.x
  1419.                                                 local y_diff = y - v.y
  1420.                                                 local z_diff = z - v.z
  1421.                                                 local m_object = getobject(objId)
  1422.                                                 movobjcoords(objId, ox + x_diff, oy + y_diff, oz + z_diff)  -- Move them with the GEO.
  1423.                                                 GEO[v.n].p[objId] = {ox + x_diff, oy + y_diff, oz + z_diff}
  1424.                                             end
  1425.                                         end
  1426.                                     end
  1427.                                     v:move(x, y, z)  -- Move the GEO to the player's coordinates
  1428.                                 else  -- Otherwise...
  1429.                                     v:delete()  -- Delete the GEO.
  1430.                                 end
  1431.                             else  -- Otherwise...
  1432.                                 v:delete()  -- Delete the GEO.
  1433.                             end
  1434.                         else  -- Otherwise...
  1435.                             v:delete()  -- Delete the GEO.
  1436.                         end
  1437.                     else  -- Otherwise...
  1438.                         if v.p then  -- If this GEO has perimeter objects...
  1439.                             for objId, coords in pairs(v.p) do
  1440.                                 if getobject(objId) then
  1441.                                     local ox, oy, oz = table.unpack(coords)
  1442.                                     local x_diff = x - v.x
  1443.                                     local y_diff = y - v.y
  1444.                                     local z_diff = z - v.z
  1445.                                     local m_object = getobject(objId)
  1446.                                     movobjcoords(objId, ox + x_diff, oy + y_diff, oz + z_diff)  -- Move them with the GEO.
  1447.                                     GEO[v.n].p[objId] = {ox + x_diff, oy + y_diff, oz + z_diff}
  1448.                                 end
  1449.                             end
  1450.                         end
  1451.                         v:move(x, y, z)  -- Don't worry about all of that player nonsense and just move the damn GEO.
  1452.                     end
  1453.                 else  -- Otherwise...
  1454.                     v:delete()  -- Delete the GEO.
  1455.                 end
  1456.             end
  1457.            
  1458.             -- If after all of that following nonsense, we still have a GEO...
  1459.             if v then
  1460.                 -- If this GEO is a killzone...
  1461.                 if v.kz then
  1462.                     -- Check if anyone is inside of it.
  1463.                     for i = 0,15 do
  1464.                         if getplayer(i) then
  1465.                             local m_player = getplayer(i)
  1466.                             local objId = readdword(m_player, 0x34)
  1467.                             if v:contains(objId) then
  1468.                                 kill(i)  -- Kill that ho.
  1469.                             end
  1470.                         end
  1471.                     end
  1472.                 end
  1473.                
  1474.                 -- If this GEO is a damagezone...
  1475.                 if v.damage then
  1476.                     -- Check if anyone is inside of it.
  1477.                     for i = 0,15 do
  1478.                         local m_player = getplayer(i)
  1479.                         if m_player then
  1480.                             local objId = readdword(m_player, 0x34)
  1481.                             if v:contains(objId) then
  1482.                                 applydmg(objId, v.damage / 100)  -- Apply damage
  1483.                             end
  1484.                         end
  1485.                     end
  1486.                 end
  1487.                
  1488.                 -- If this GEO is monitoring for objects entering and exiting it...
  1489.                 if v.m then
  1490.                     -- Loop through the table of objects this GEO is monitoring for.
  1491.                     for objId,_ in pairs(v.m) do
  1492.                         -- If this object still exists...
  1493.                         if getobject(objId) then
  1494.                             -- If this object is inside of the GEO...
  1495.                             if v:contains(objId) then
  1496.                                 -- If the GEO didn't know this object was inside of it 1/100 of a second ago...
  1497.                                 if not v.c[objId] then
  1498.                                     local player = objectidtoplayer(objId)
  1499.                                     -- Call OnGeoEnter.
  1500.                                     local allow = OnGeoEnter(v, player, objId)
  1501.                                     if allow == 0 or allow == false then
  1502.                                         local hash = gethash(player)
  1503.                                         if pcoords[hash] then
  1504.                                             movobjcoords(objId, table.unpack(pcoords[hash]))
  1505.                                         end
  1506.                                     else
  1507.                                         GEO[k].c[objId] = true
  1508.                                     end
  1509.                                 end
  1510.                             else  -- Otherwise...
  1511.                                 -- If the GEO thought this object was inside of it 1/100 of a second ago...
  1512.                                 if v.c[objId] then
  1513.                                     local player = objectidtoplayer(objId)
  1514.                                     -- Call OnGeoExit.
  1515.                                     local allow = OnGeoExit(v, player, objId)
  1516.                                     if allow == 0 or allow == false then
  1517.                                         local hash = gethash(player)
  1518.                                         if pcoords[hash] then
  1519.                                             movobjcoords(objId, table.unpack(pcoords[hash]))
  1520.                                         end
  1521.                                     else
  1522.                                         GEO[k].c[objId] = nil
  1523.                                     end
  1524.                                 end
  1525.                             end
  1526.                         else  -- Otherwise...
  1527.                             GEO[k].m[objId] = nil  -- Stop monitoring for this object.
  1528.                         end
  1529.                     end
  1530.                 end
  1531.                
  1532.                 -- If this GEO has a velocity...
  1533.                 if v.vx or v.vy or v.vz then
  1534.                     if v.p then  -- If this GEO has perimeter objects...
  1535.                         for objId, coords in pairs(v.p) do
  1536.                             if getobject(objId) then
  1537.                                 local ox, oy, oz = table.unpack(coords)
  1538.                                 local m_object = getobject(objId)
  1539.                                 movobjcoords(objId, ox + (v.vx or 0), oy + (v.vy or 0), oz + (v.vz or 0))  -- Move them with the GEO.
  1540.                                 GEO[v.n].p[objId] = {ox + (v.vx or 0), oy + (v.vy or 0), oz + (v.vz or 0)}
  1541.                             end
  1542.                         end
  1543.                     end
  1544.                     -- Move that ho.
  1545.                     v:move(v.x + (v.vx or 0) / 100, v.y + (v.vy or 0) / 100, v.z + (v.vz or 0) / 100)
  1546.                 end
  1547.             end
  1548.         end
  1549.     end
  1550.    
  1551.     -- 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)
  1552.     if count % 25 == 0 then
  1553.         for i = 0,15 do
  1554.             local m_player = getplayer(i)
  1555.             if m_player then
  1556.                 local hash = gethash(i)
  1557.                 local objId = readdword(m_player, 0x34)
  1558.                 if getobject(objId) then
  1559.                     pcoords[hash] = {getobjectcoords(objId)}
  1560.                 else
  1561.                     pcoords[hash] = nil
  1562.                 end
  1563.             end
  1564.         end
  1565.     end
  1566.    
  1567.     return true
  1568. end
  1569.  
  1570. function OnGeoEnter(geo, player, objId)
  1571.  
  1572.     return true
  1573. end
  1574.  
  1575. function OnGeoExit(geo, player, objId)
  1576.  
  1577.     return true
  1578. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement