-- Utilities module for GameGuru -- Written by Chris Stapleton local U = {_G = _G} -- import section: modules local rad = math.rad local deg = math.deg local cos = math.cos local sin = math.sin local asin = math.asin local abs = math.abs local atan = math.atan2 local sqrt = math.sqrt local pi = math.pi local rand = math.random local sort = table.sort local pairs = pairs -- GG functions/Tables local ducked = GetGamePlayerStatePlayerDucking local gEnt = g_Entity local RayCast = IntersectAll -- include these for debugging local Prompt = Prompt local PromptE = PromptLocal -- If using any of the functions generating random positions -- make sure random number generator is seeded by putting the -- following lines in your main script initialisation: -- math.randomseed(os.time()) ---math.random(); math.random(); math.random() _ENV = U local function getPosX() return _G.g_PlayerPosX end local function getPosZ() return _G.g_PlayerPosZ end local function getPos2() return _G.g_PlayerPosX, _G.g_PlayerPosZ end local function getPos3() return _G.g_PlayerPosX, _G.g_PlayerPosY, _G.g_PlayerPosZ end local function getAngX() return _G.g_PlayerAngX end local function getAngY() return _G.g_PlayerAngY end local function getAng3() return _G.g_PlayerAngX, _G.g_PlayerAngY, _G.g_PlayerAngZ end local function huge() return _G.math.huge end ------------------------------------------------ -- Function to rotate a point by Euler angles -- -- Useful for positioning one entity or decal -- -- with respect to another. -- -- -- -- angles are in radians! -- -- -- -- example of use; say you have a head model -- -- and a glowing eye decal. Calculate the x, -- -- y,z offsets from the heads origin to the -- -- eye position, pass these into the function -- -- along with the rotation angles of the head -- -- model and the returned values can then be -- -- added to the head origin to give the -- -- placement position for the decal. -- ------------------------------------------------ function U.Rotate3D( x, y, z, xrot, yrot, zrot ) local function RotatePoint2D( x, y, Ang ) -- Ang in radians local Sa, Ca = sin( Ang ), cos( Ang ) return x*Ca - y*Sa, x*Sa + y*Ca end local NX, NY, NZ = x, y, z -- X NZ, NY = RotatePoint2D( NZ, NY, -xrot ) -- Y NX, NZ = RotatePoint2D( NX, NZ, -yrot ) -- Z NY, NX = RotatePoint2D( NY, NX, -zrot ) return NX, NY, NZ end ------------------------------------------- -- Functions used to aid foraging system -- ------------------------------------------- local collectablesList = nil function SetList( list ) collectablesList = list end function ChangeAmount( name, by, list) list = list or collectablesList if list == nil then return end local itemToSet = list[ name ] if itemToSet == nil then list[ name ] = { amount = by } else itemToSet.amount = itemToSet.amount + by end end function SetAmount( name, to, list) list = list or collectablesList if list == nil then return end list[ name ] = { amount = to } end function HaveAmount( name, list ) list = list or collectablesList if list == nil then return 0 end if list[ name ] ~= nil then return list[ name ].amount else return 0 end end function HaveEnough( name, amount, list ) list = list or collectablesList if amount == 0 then return true elseif list[ name ] ~= nil then return list[ name ].amount >= amount else return false end end -------------------------------------------------- -- Function to return Object in players eyeline -- -- -- -- Uses GG's ray casting command. -- -- parameters: -- -- dist : (optional) length of ray in game -- -- units -- -- ignore : (optional) object id to ignore -- -- -- -- returns object id or 0 if none found -- -------------------------------------------------- function U.ObjectPlayerLookingAt( dist, ignore ) local dist = dist or 2000 local ignore = ignore or 0 local pxp, pyp, pzp = getPos3() local pxa, pya, pza = getAng3() if ducked == nil or ducked() == 0 then pyp = pyp + 31 else pyp = pyp + 10 end local rayX, rayY, rayZ = Rotate3D ( 0, 0, dist, rad( pxa ), rad( pya ), rad( pza ) ) return RayCast( pxp, pyp, pzp, pxp + rayX, pyp + rayY, pzp + rayZ, ignore ) end ------------------------------------------------------ -- Function to detect if players eyeline intersects -- -- a given object. -- -- parameters: -- -- obj : object id -- -- dist : (optional) length of ray in game -- -- units -- -- ignore : (optional) object id to ignore -- -- -- -- Returns true or false -- ------------------------------------------------------ function U.PlayerLookingAtObj( obj, dist, ignore ) local vobj = ObjectPlayerLookingAt( dist, ignore ) return vobj and vobj == obj end ------------------------------------------------------ -- Function to detect if players eyeline intercects -- -- a given entity. -- -- parameters: -- -- e : entity id -- -- dist : (optional) length of ray in game -- -- units -- -- ignore : (optional) object id to ignore -- -- -- -- Returns true or false -- ------------------------------------------------------ function U.PlayerLookingAt( e, dist, ignore ) local Ent = gEnt[ e ] if Ent == nil then return false end return PlayerLookingAtObj( Ent.obj, dist, ignore ) end ------------------------------------------------------ -- Function to test whether two specified positions -- -- are within a given distance of each other -- -- -- -- Returns true or false -- ------------------------------------------------------ function U.CloserThan( x1, y1, z1, x2, y2, z2, dist ) local dx, dy, dz = x1 - x2, y1 - y2, z1 - z2 return ( dx*dx+dy*dy+dz*dz ) < dist*dist end ------------------------------------------------------------ -- Function to detect if player is looking in the general -- -- direction with a certain angle of a specified entity. -- -- note: that entity might not actually be visible -- -- parameters: -- -- e : entity id -- -- dist : (optional) distance to check, game units -- -- fov : (optional) angle to check -- -- -- -- Returns true or false -- ------------------------------------------------------------ function U.PlayerLookingNear( e, dist, fov ) local Ent = gEnt[ e ] if Ent == nil then return false end local dist = dist or 2000 local fov = fov or 20 local pxp, pyp, pzp = getPos3() if not CloserThan( pxp, pyp, pzp, Ent.x, Ent.y, Ent.z, dist ) then return false end local function limitAngle ( Angle ) while Angle < 0 do Angle = 360 + Angle end while Angle > 360 do Angle = Angle - 360 end return Angle end local angle = limitAngle( atan( Ent.x - pxp, Ent.z - pzp ) * ( 180.0 / pi ) ) local pAng = limitAngle( getAngY() ) local L = limitAngle( angle - fov / 2 ) local R = limitAngle( angle + fov / 2 ) if ( L < R and ( pAng > L and pAng < R ) ) or ( L > R and ( pAng > L or pAng < R ) ) then local PlayerVertAngle = getAngX() if PlayerVertAngle < 280 then PlayerVertAngle = -PlayerVertAngle else PlayerVertAngle = 2 * ( 360 - PlayerVertAngle ) end if ducked == nil or ducked() == 0 then pyp = pyp + 31 else pyp = pyp + 10 end local dx, dy, dz = Ent.x - pxp, Ent.y - pyp, Ent.z - pzp local sqrDist = dx*dx + dy*dy + dz*dz local EntAng = deg( asin( dy / sqrt( sqrDist ) ) ) return abs( EntAng - PlayerVertAngle ) < fov / 2 else return false end end ---------------------------------------------------- -- Function to test if player is within specified -- -- distance of a position. -- -- Returns true or false -- ---------------------------------------------------- function U.PlayerCloserThanPos( x, y, z, dist ) local pxp, pyp, pzp = getPos3() return CloserThan( pxp, pyp, pzp, x, y, z, dist ) end ----------------------------------------------------- -- Function to test if player is within specified -- -- distance of a given entity. -- -- Returns true or false -- ----------------------------------------------------- function U.PlayerCloserThan( e, dist ) local Ent = gEnt[ e ] return Ent ~= nil and PlayerCloserThanPos( Ent.x, Ent.y, Ent.z, dist ) end ------------------------------------------------------------- -- Function to return a random position within a specified -- -- distance of a given position. -- -- defaults to using player position -- -- returns x and z coordinates -- ------------------------------------------------------------- function U.RandomPos( dist, x, z ) local dist = dist or 200 local x = x or getPosX() local z = z or getPosZ() local angle = rand() * 2 * pi return x + sin( angle ) * dist, z + cos( angle ) * dist end ---------------------------------------------------------- -- Function to return a random position specified as an -- -- offset position wrt to a given entity. -- -- offset is fraction of entity distance from the point -- -- specified. -- -- e.g. 2 is half way, 3 a third etc = defaults to 2 -- -- returns x and z coordinates -- ---------------------------------------------------------- function U.RandomOffsetPos( e, dist, offset, x, z ) local dist = dist or 200 local offset = offset or 2 local x = x or getPosX() local z = z or getPosZ() local Ent = gEnt[ e ] if Ent == nil then return 0, 0 end return RandomPos( x + ( Ent.x - x)/offset, z + (Ent.z - z)/offset, dist ) end -- function returns squared distance between two points local function sqrd( x1, z1, x2, z2 ) local dx, dz = x1 - x2, z1 - z2 return dx*dx+dz*dz end ---------------------------------------------------- -- Function to return entity id of closest active -- -- entity to specified point withing a certain -- -- distance. -- -- Further tests would be needed to used to test -- -- whether the entity is a soldier for example. -- -- -- -- returns entity id or nil if none found -- ---------------------------------------------------- function U.ClosestEntToPos( x, z, dist ) local dist = dist or 2000 local eClosest = nil local sdClosest = nil dist = dist * dist for k, v in pairs( gEnt ) do if eClosest == nil then local d = sqrd( x, z, v.x, v.z ) if d < dist then eClosest = k sdClosest = sqrd( x, z, v.x, v.z ) end else local d = sqrd( x, z, v.x, v.z ) if d < dist and d < sdClosest then eClosest = k sdClosest = d end end end return eClosest end ---------------------------------------------------- -- Function to return entity id of closest active -- -- entity to player within a specified distance. -- -- -- returns entity id or nil if none found -- ---------------------------------------------------- function U.ClosestEntToPlayer( dist ) local pxp, pzp = getPos2() return ClosestEntToPos( pxp, pzp ) end -- iterates a list in order defined by sort function or by key order if none given -- not really something you can use directly but see ClosestEntities function below -- for example of use function U.SortPairs( list, order_given ) -- collect the keys local keys = {} for k in pairs(list) do keys[ #keys + 1 ] = k end if order_given then sort( keys, function( a, b ) return order_given( list, a, b) end ) else sort( keys ) end -- return the iterator function local i = 0 return function() i = i + 1 if keys[ i ] then return keys[ i ], list[ keys[ i ] ] end end end ------------------------------------------------------------ -- Function to return a list of the entities in distance -- -- order (i.e. closest first) from a specified point. -- -- parameters: -- -- dist : (optional) max distance to use -- -- num : (optional) max number of entities to return -- -- x, z : (optional) position, defaults to player -- -- -- -- -- returns list of entity ids or empty list if none -- -- note only adds entity to list if health > 0 -- ------------------------------------------------------------ function U.ClosestEntities( dist, num, x, z ) local dist = dist or huge() local num = num or huge() local x = x or getPosX() local z = z or getPosZ() local entityList = {} -- first build a list of ranges of healthy entities within -- 'dist' from specified position or player for k, v in pairs( gEnt ) do if v ~= nil and v.health > 0 then if CloserThan( v.x, v.y, v.z, x, v.y, z, dist ) then entityList[ k ] = sqrd( x, z, v.x, v.z ) end end end local sortedList = {} -- next sort and place in new list until 'num' entities found for k, _ in SortPairs( entityList, function( list, a, b ) return list[ a ] < list[ b ] end ) do sortedList[ #sortedList + 1 ] = k if #sortedList == num then break end end return sortedList end return U