This commit is contained in:
Dan
2019-11-07 18:44:24 +00:00
parent 24ede1917f
commit c85098a207
12 changed files with 2866 additions and 0 deletions

24
__resource.lua Normal file
View File

@@ -0,0 +1,24 @@
--[[-----------------------------------------------------------------------
Wraith Radar System - v2.0.0
Created by WolfKnight
-----------------------------------------------------------------------]]--
resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937'
name 'WraithRS 2'
description 'An advanced radar system for FiveM'
author 'WolfKnight'
version '2.0.0'
ui_page "nui/radar.html"
files {
"nui/*"
}
client_script 'config.lua'
client_script 'cl_utils.lua'
client_script 'cl_radar.lua'
-- client_script 'cl_radar - sphere test.lua'

View File

@@ -0,0 +1,13 @@
Vector points for bounding box:
All points are assuming the view is facing the rear of the vehicle
All points have been manually tested
Bottom back left: min.x min.y min.z
Bottom back right: max.x min.y min.z
Bottom front left: min.x max.y min.z
Bottom front right: max.x max.y min.z
Top back left: min.x min.y max.z
Top back right: max.x min.y max.z
Top front left: min.x max.y max.z
Top front right: max.x max.y max.z

633
cl_radar - sphere test.lua Normal file
View File

@@ -0,0 +1,633 @@
--[[------------------------------------------------------------------------
Wraith Radar System - v1.0.3
Created by WolfKnight
------------------------------------------------------------------------]]--
--[[------------------------------------------------------------------------
Resource Rename Fix
------------------------------------------------------------------------]]--
Citizen.CreateThread( function()
-- Wait for a short period of time to give the resource time to load
Citizen.Wait( 5000 )
-- Get the name of the resource, for example the default name is 'wk_wrs'
local resourceName = GetCurrentResourceName()
-- Send a message through the NUI system to the JavaScript file to
-- give the name of the resource
SendNUIMessage( { resourcename = resourceName } )
end )
--[[------------------------------------------------------------------------
Radar variables
------------------------------------------------------------------------]]--
RADAR.vars =
{
-- Player's vehicle speed
patrolSpeed = 0,
-- The speed type
speedType = "mph",
-- Table to store entity IDs of captured vehicles
capturedVehicles = {},
captureOffsets = {},
-- Antennas
antennas = {
front = {
},
back = {
}
}
}
--[[------------------------------------------------------------------------
Radar setters and getters
------------------------------------------------------------------------]]--
function RADAR:SetPatrolSpeed( speed )
if ( type( speed ) == "number" ) then
self.vars.patrolSpeed = speed
end
end
function RADAR:GetPatrolSpeed()
return self.vars.patrolSpeed
end
--[[------------------------------------------------------------------------
Radar functions
------------------------------------------------------------------------]]--
function RADAR:GetVehSpeed( veh )
if ( self.vars.speedType == "mph" ) then
return GetEntitySpeed( veh ) * 2.236936
else
return GetEntitySpeed( veh ) * 3.6
end
end
function RADAR:ResetCapturedVehicles()
self.vars.capturedVehicles = {}
end
local entityEnumerator = {
__gc = function(enum)
if enum.destructor and enum.handle then
enum.destructor(enum.handle)
end
enum.destructor = nil
enum.handle = nil
end
}
local function EnumerateEntities(initFunc, moveFunc, disposeFunc)
return coroutine.wrap(function()
local iter, id = initFunc()
if not id or id == 0 then
disposeFunc(iter)
return
end
local enum = {handle = iter, destructor = disposeFunc}
setmetatable(enum, entityEnumerator)
local next = true
repeat
coroutine.yield(id)
next, id = moveFunc(iter)
until not next
enum.destructor, enum.handle = nil, nil
disposeFunc(iter)
end)
end
function EnumeratePeds()
return EnumerateEntities(FindFirstPed, FindNextPed, EndFindPed)
end
function EnumerateVehicles()
return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
end
local traces =
{
{ startVec = { x = 0.0, y = 5.0 }, endVec = { x = 0.0, y = 150.0 } },
-- "Forward cone"
{ startVec = { x = -5.0, y = 15.0 }, endVec = { x = -5.0, y = 150.0 } },
{ startVec = { x = 5.0, y = 15.0 }, endVec = { x = 5.0, y = 150.0 } },
{ startVec = { x = -10.0, y = 25.0 }, endVec = { x = -10.0, y = 150.0 } },
{ startVec = { x = 10.0, y = 25.0 }, endVec = { x = 10.0, y = 150.0 } },
{ startVec = { x = -15.0, y = 35.0 }, endVec = { x = -15.0, y = 150.0 } },
{ startVec = { x = 15.0, y = 35.0 }, endVec = { x = 15.0, y = 150.0 } },
-- "Rear cone"
--[[{ startVec = { x = -2.5, y = 135.0 }, endVec = { x = -2.5, y = 15.0 } },
{ startVec = { x = 2.5, y = 135.0 }, endVec = { x = 2.5, y = 15.0 } },
{ startVec = { x = -7.5, y = 125.0 }, endVec = { x = -7.5, y = 25.0 } },
{ startVec = { x = 7.5, y = 125.0 }, endVec = { x = 7.5, y = 25.0 } },
{ startVec = { x = -12.5, y = 115.0 }, endVec = { x = -12.5, y = 35.0 } },
{ startVec = { x = 12.5, y = 115.0 }, endVec = { x = 12.5, y = 35.0 } }]]
}
function RADAR:RayTraceFromVeh( playerVeh )
local playerVehPos = GetEntityCoords( playerVeh, true )
local forwardVector = GetEntityForwardVector( playerVeh )
-- Vector3 source = playerVehPos + forwardVector * Start.Y (15.0) + Game.Player.Character.CurrentVehicle.RightVector * Start.X (-5.0)
--local rayStart1 = playerVehPos + ( forwardVector * vector3( -5.0, 15.0, 0.0 ) ) + GetEntityRotation( playerVeh, false )
--local rayEnd1 = playerVehPos + ( forwardVector * vector3( -5.0, 300.0, 0.0 ) ) + GetEntityRotation( playerVeh, false )
local offset = GetOffsetFromEntityInWorldCoords( playerVeh, 0.0, 60.0, 0.0 )
-- for veh in EnumerateVehicles() do
-- local pos = GetEntityCoords( veh, true )
-- local dist = GetDistanceBetweenCoords( pos.x, pos.y, pos.z, offset.x, offset.y, offset.z, true )
-- UTIL:DrawDebugText( 0.50, 0.50, 0.60, true, "Dist: " .. tostring( dist ), 255, 255, 255, 255 )
-- end
for k, v in pairs( traces ) do
local rayStart1 = GetOffsetFromEntityInWorldCoords( playerVeh, v.startVec.x, v.startVec.y, 0.0 )
local rayEnd1 = GetOffsetFromEntityInWorldCoords( playerVeh, v.endVec.x, v.endVec.y, 0.0 )
DrawLine( rayStart1.x, rayStart1.y, rayStart1.z, rayEnd1.x, rayEnd1.y, rayEnd1.z, 255, 255, 255, 255 )
local rayHandle = StartShapeTestCapsule( rayStart1.x, rayStart1.y, rayStart1.z, rayEnd1.x, rayEnd1.y, rayEnd1.z, 20.0, 10, playerVeh )
local _, hitEntity, endCoords, surfaceNormal, vehicle = GetShapeTestResult( rayHandle )
-- SetEntityAsMissionEntity( vehicle )
UTIL:DrawDebugText( 0.50, ( k * 0.040 ) + 0.6, 0.60, true, "Found entity: " .. tostring( vehicle ), 255, 255, 255, 255 )
local hitEntPos = GetEntityCoords( vehicle, true )
DrawMarker( 28, hitEntPos.x, hitEntPos.y, hitEntPos.z + 6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.5, 0, 250, 0, 200, false, true, 2, false, false, false, false )
end
end
function RADAR:DoesLineIntersectSphere( centre, radiusSqr, rayStart, rayEnd )
-- First we get the normalised ray, this way we then know the direction the ray is going
local rayNorm = norm( rayEnd - rayStart )
-- Then we calculate the ray to the centre position of the sphere
local rayToCentre = vehPos - startPoint
-- Now that we have the ray to the centre of the sphere, and the normalised ray direction, we
-- can calculate the shortest point from the centre of the sphere onto the ray itself. This
-- would then give us the opposite side of the right angled triangle. All of the resulting
-- values are also in squared form, as performing sqrt functions is slower.
local tProj = dot( rayToCentre, rayNorm )
local oppLenSqr = dot( rayToCentre, rayToCentre ) - ( tProj * tProj )
-- Now all we have to do is compare the squared opposite length and the radius squared, this
-- will then tell us if the ray intersects with the sphere.
if ( oppLenSqr < radiusSqr ) then
return true
end
return false
end
--[[------------------------------------------------------------------------
Test time
------------------------------------------------------------------------]]--
function GetBoundingBox( ent )
local mdl = GetEntityModel( ent )
local min, max = GetModelDimensions( mdl )
-- local radius = 5.0
-- min = min + -radius
-- max = max + radius
local points = {
vector3( min.x, min.y, min.z ), -- Bottom back left
vector3( max.x, min.y, min.z ), -- Bottom back right
vector3( min.x, max.y, min.z ), -- Bottom front left
vector3( max.x, max.y, min.z ), -- Bottom front right
vector3( min.x, min.y, max.z ), -- Top back left
vector3( max.x, min.y, max.z ), -- Top back right
vector3( min.x, max.y, max.z ), -- Top front left
vector3( max.x, max.y, max.z ) -- Top front right
}
return points
end
function GetDrawableFromBoundingBox( box )
local points = {
{ box[1], box[3] },
{ box[3], box[4] },
{ box[4], box[2] },
{ box[2], box[1] },
{ box[1], box[5] },
{ box[3], box[7] },
{ box[4], box[8] },
{ box[2], box[6] },
{ box[5], box[7] },
{ box[7], box[8] },
{ box[8], box[6] },
{ box[6], box[5] }
}
return points
end
function DrawBoundingBox( ent, box )
for _, v in pairs( box ) do
local a = GetOffsetFromEntityInWorldCoords( ent, v[1] )
local b = GetOffsetFromEntityInWorldCoords( ent, v[2] )
DrawLine( a.x, a.y, a.z, b.x, b.y, b.z, 255, 255, 255, 255 )
end
end
function GetAllVehicleEnts()
local ents = {}
for v in EnumerateVehicles() do
table.insert( ents, v )
end
return ents
end
function CustomShapeTest( startPos, endPos, entToIgnore )
local flags = 1 | 2 | 4 | 16 | 256
local trace = StartShapeTestRay( startPos, endPos, flags, entToIgnore, 7 )
local _, didHit, hitPos, _, hitEnt = GetShapeTestResult( trace )
UTIL:DrawDebugText( 0.500, 0.850, 0.55, true, "Hit?: " .. tostring( didHit ) .. "\nHit pos: " .. tostring( hitPos ) .. "\nHit ent: " .. tostring( hitEnt ) )
if ( hitPos ) then
DrawMarker( 28, hitPos.x, hitPos.y, hitPos.z + 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.25, 0, 250, 120, 200, false, true, 2, false, false, false, false )
end
end
function values(xs)
local i = 0
return function()
i = i + 1;
return xs[i]
end
end
function map(xs, fn)
local t = {}
for i,v in ipairs(xs) do
local r = fn(v, i, xs)
table.insert(t, r)
end
return t
end
function filter(xs, fn)
local t = {}
for i,v in ipairs(xs) do
if fn(v, i, xs) then
table.insert(t, v)
end
end
return t
end
function DoesLineIntersectAABB( p1, p2, min, max )
-- I know this probably isn't the best way to check if a line with a 'radius' intersects with
-- a bounding box, but it's a lot less resource intensive so...
--local min = min + -3.0
--local max = max + 3.0
-- This checks to make sure the origin of the line doesn't start inside the box
-- Also known as "IsPointInsideAABB"
if ( ( p1.x > min.x and p1.x < max.x and p1.y > min.y and p1.y < max.y and p1.z > min.z and p1.z < max.z ) or
( p2.x > min.x and p2.x < max.x and p2.y > min.y and p2.y < max.y and p2.z > min.z and p2.z < max.z ) ) then
return true
end
-- This checks to make sure the line itself is not even near the box
for a in values( { 'x', 'y', 'z' } ) do
-- The first half of this statement checks to see if the axis origin and end line points
-- are less than the minimum of the bounding box, the second half checks the start and
-- end line points are beyond the maximum of the bounding box
if ( ( p1[a] < min[a] and p2[a] < min[a] ) or ( p1[a] > max[a] and p2[a] > max[a] ) ) then
return false
end
end
-- Still trying to work out how this one works
for p in values( { min, max } ) do
for a, o in pairs( { x = { 'y', 'z' }, y = { 'x', 'z' }, z = { 'x', 'y' } } ) do
-- p = min or max as vector
-- a = x, y or z
-- o = 'y''z', 'x''z' or 'x''y' respectively
-- eg h = l1 + ( l1[x] - min[x] ) / ( l1[x] - l2[x] ) * ( l2 - l1 )
-- eg o1, o2 = [o1], o[2] = 'y', 'z'
-- The below variable h appears to calculate the values that allow for x1, x2, y1, and y2
-- This way the intersection point can be found
local h = p1 + ( p1[a] - p[a] ) / ( p1[a] - p2[a] ) * ( p2 - p1 )
local o1, o2 = o[1], o[2]
if ( h[o1] >= min[o1] and h[o1] <= max[o1] and h[o2] >= min[o2] and h[o2] <= max[o2] ) then
return true
end
end
end
return false
end
function DoesLineIntersectSphere()
end
function DoesLineIntersectEntityBoundingBox(p1, p2, entity)
local model = GetEntityModel(entity)
local min, max = GetModelDimensions(model)
local l1 = GetOffsetFromEntityGivenWorldCoords( entity, p1 )
local l2 = GetOffsetFromEntityGivenWorldCoords( entity, p2 )
-- Citizen.Trace( "\np1: " .. tostring( p1 ) .. "\tp2: " .. tostring( p2 ) .. "\tl1: " .. tostring( l1 ) .. "\tl2: " .. tostring( l2 ) )
return DoesLineIntersectAABB(l1, l2, min, max)
end
function RaytraceBoundingBox(p1, p2, ignoredEntity)
local entities = GetAllVehicleEnts()
local matches = filter(entities, function (entity)
if entity == ignoredEntity then return false end
if not IsEntityOnScreen(entity) then return false end
-- if not IsEntityTargetable(entity) then return false end
return DoesLineIntersectEntityBoundingBox(p1, p2, entity)
end)
table.sort(matches, function (a, b)
local h1 = GetEntityCoords(a)
local h2 = GetEntityCoords(b)
return #(p1 - h1) < #(p1 - h2)
end)
if matches[1] then
local pos = GetEntityCoords(matches[1])
return pos, matches[1]
end
return nil, nil
end
function RADAR:Test()
-- Get the player's ped
local ped = GetPlayerPed( -1 )
-- Make sure the player is sitting in a vehicle
if ( IsPedSittingInAnyVehicle( ped ) ) then
-- Get the vehicle the player is in
local plyVeh = GetVehiclePedIsIn( ped, false )
local plyVehPos = GetEntityCoords( plyVeh )
-- Check the vehicle actually exists and that the player is in the driver's seat
if ( DoesEntityExist( plyVeh ) and GetPedInVehicleSeat( plyVeh, -1 ) ) then
local startPoint = GetOffsetFromEntityInWorldCoords( plyVeh, 0.0, 5.0, 0.0 )
local endPoint = GetOffsetFromEntityInWorldCoords( plyVeh, 0.0, 50.0, 1.0 )
DrawLine( startPoint, endPoint, 0, 255, 0, 255 )
--for veh in EnumerateVehicles() do
local veh = UTIL:GetVehicleInDirection( plyVeh, startPoint, endPoint )
if ( DoesEntityExist( veh ) ) then
local vehPos = GetEntityCoords( veh )
local vehPosRel = GetOffsetFromEntityGivenWorldCoords( plyVeh, vehPos )
--[[local vehBox = GetBoundingBox( veh )
local drawableBox = GetDrawableFromBoundingBox( vehBox )
DrawBoundingBox( veh, drawableBox )]]
if ( veh ~= plyVeh ) then
DrawMarker( 28, vehPos.x, vehPos.y, vehPos.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, 10.0, 10.0, 255, 120, 80, 40, false, true, 2, false, false, false, false )
-- First attempt, didn't really work
-- local r = 5.0
-- local ro = startPoint
-- local s = vehPos
-- local rd = norm( startPoint )
-- local t = dot( s - ro, rd )
-- local p = ro + ( rd * t )
-- UTIL:DrawDebugSphere( ro.x, ro.y, ro.z, 0.5 )
-- UTIL:DrawDebugSphere( s.x, s.y, s.z, 0.5 )
-- UTIL:DrawDebugSphere( p.x, p.y, p.z, 0.5 )
-- local y = #( s - p )
-- if ( y < r ) then
-- local x = math.sqrt( ( r * r ) - ( y * y ) )
-- local t1 = t - x
-- local t2 = t + x
-- UTIL:DrawDebugText( 0.500, 0.700, 0.50, true, "t1: " .. tostring( t1 ) .. "\nt2: " .. tostring( t2 ) )
-- end
-- Second attempt
-- local ra = 20.0
-- local ce = vehPos
-- local ro = startPoint
-- local rd = norm( startPoint )
-- local oc = ro - ce
-- local b = dot( oc, rd )
-- local c = dot( oc, oc ) - ( ra * ra )
-- local h = ( b * b ) - c
-- if ( h > 0.0 ) then
-- h = math.sqrt( h )
-- local result = vector2( -b-h, -b+h )
-- UTIL:DrawDebugText( 0.500, 0.700, 0.50, true, "Result: " .. tostring( result ) )
-- end
-- Third bloody attempt
-- local center = vehPos
-- local radius = 5.0
-- local ro = startPoint
-- local rd = norm( startPoint )
-- local oc = startPoint - center
-- local a = dot( rd, rd )
-- local b = 2.0 * dot( oc, rd )
-- local c = dot( oc, oc ) - radius * radius
-- local dis = b * b - 4 * a * c
-- if ( dis < 0 ) then
-- UTIL:DrawDebugText( 0.500, 0.650, 0.50, true, "-1" )
-- else
-- local val = ( -b - math.sqrt( dis ) ) / ( 2.0 * a )
-- UTIL:DrawDebugText( 0.500, 0.650, 0.50, true, "yes" )
-- end
-- Fourth attempt
local radius = 10.0
local radiusSqr = radius * radius
local rayNorm = norm( endPoint - startPoint )
UTIL:DrawDebugText( 0.500, 0.600, 0.50, true, "rayNorm: " .. tostring( rayNorm ) )
local rayToCenter = vehPos - startPoint
DrawLine( startPoint, vehPos, 255, 255, 255, 255 )
local tProj = dot( rayToCenter, rayNorm )
UTIL:DrawDebugText( 0.500, 0.625, 0.50, true, "tProj: " .. tostring( tProj ) )
UTIL:DrawDebugText( 0.500, 0.100, 0.60, true, "Veh in front? = " .. tostring( ( tProj > 0 ) ) )
local iPos = ( rayNorm * tProj ) + startPoint
DrawLine( vehPos, iPos, 255, 255, 255, 255 ) -- draw the smallest point
DrawLine( startPoint, iPos, 255, 255, 255, 255 ) -- draw a line on the opposite
local oppLenSqr = dot( rayToCenter, rayToCenter ) - ( tProj * tProj )
UTIL:DrawDebugText( 0.500, 0.650, 0.50, true, "radiusSqr: " .. tostring( radiusSqr ) )
UTIL:DrawDebugText( 0.500, 0.675, 0.50, true, "oppLenSqr: " .. tostring( oppLenSqr ) )
if ( oppLenSqr > radiusSqr ) then
UTIL:DrawDebugText( 0.500, 0.800, 0.50, true, "Projection point outside radius" )
elseif ( oppLenSqr == radiusSqr ) then
UTIL:DrawDebugText( 0.500, 0.825, 0.50, true, "Single point intersection" )
end
local oLen = math.sqrt( radiusSqr - oppLenSqr )
UTIL:DrawDebugText( 0.500, 0.700, 0.50, true, "oLen: " .. tostring( oLen ) )
local t0 = tProj - oLen
local t1 = tProj + oLen
if ( t1 < t0 ) then
local tmp = t0
t0 = t1
t1 = tmp
end
UTIL:DrawDebugText( 0.500, 0.725, 0.50, true, "t0: " .. tostring( t0 ) .. "\nt1: " .. tostring( t1 ) )
local t0p = ( rayNorm * t0 ) + startPoint
local t1p = ( rayNorm * t1 ) + startPoint
UTIL:DrawDebugSphere( t0p.x, t0p.y, t0p.z, 0.25 )
UTIL:DrawDebugSphere( t1p.x, t1p.y, t1p.z, 0.25 )
DrawLine( vehPos, t0p, 255, 255, 0, 255 )
DrawLine( vehPos, t1p, 255, 255, 0, 255 )
if ( oppLenSqr < radiusSqr ) then
UTIL:DrawDebugText( 0.500, 0.875, 0.55, true, "Intersects sphere" )
else
UTIL:DrawDebugText( 0.500, 0.925, 0.55, true, "Doesn't intersect sphere" )
end
end
end
end
end
end
function RADAR:Main()
-- Get the local player's ped and store it in a variable
local ped = GetPlayerPed( -1 )
-- As we only want the radar to work when a player is sitting in a
-- vehicle, we run that check first
if ( IsPedSittingInAnyVehicle( ped ) ) then
-- Get the vehicle the player is sitting in
local vehicle = GetVehiclePedIsIn( ped, false )
UTIL:DrawDebugText( 0.50, 0.020, 0.60, true, "Found player vehicle: " .. tostring( vehicle ), 255, 255, 255, 255 )
-- Check to make sure the player is in the driver's seat, and also
-- that the vehicle has a class of VC_EMERGENCY (18)
if ( GetPedInVehicleSeat( vehicle, -1 ) == ped --[[ and GetVehicleClass( vehicle ) == 18 ]] ) then
local vehicleSpeed = UTIL:Round( self:GetVehSpeed( vehicle ), 0 )
local vehicleHeading = UTIL:Round( GetEntityHeading( vehicle ), 0 )
UTIL:DrawDebugText( 0.50, 0.060, 0.60, true, "Self speed: " .. tostring( vehicleSpeed ), 255, 255, 255, 255 )
local vehiclePos = GetEntityCoords( vehicle, true )
-- local edge = GetOffsetFromEntityInWorldCoords( vehicle, 20.0, 50.0, 0.0 )
local newX = UTIL:Round( vehiclePos.x, 0 )
local newY = UTIL:Round( vehiclePos.y, 0 )
local newZ = UTIL:Round( vehiclePos.z, 0 )
UTIL:DrawDebugText( 0.50, 0.100, 0.60, true, "Vehicle X: " .. tostring( newX ) .. " Vehicle Y: " .. tostring( newY ) .. " Vehicle Z: " .. tostring( newZ ), 255, 255, 255, 255 )
local model = GetEntityModel( vehicle )
local min, max = GetModelDimensions( model )
local format = "Min X: " .. tostring( min.x ) .. " Min Y: " .. tostring( min.y ) .. " Min Z: " .. tostring( min.z )
local format2 = "Max X: " .. tostring( max.x ) .. " Max Y: " .. tostring( max.y ) .. " Max Z: " .. tostring( max.z )
UTIL:DrawDebugText( 0.50, 0.180, 0.60, true, "Model: " .. tostring( model ), 255, 255, 255, 255 )
UTIL:DrawDebugText( 0.50, 0.220, 0.60, true, format, 255, 255, 255, 255 )
UTIL:DrawDebugText( 0.50, 0.260, 0.60, true, format2, 255, 255, 255, 255 )
for veh in EnumerateVehicles() do
if ( GetEntitySpeed( veh ) > 1.0 and veh ~= vehicle ) then
local aiVehHeading = UTIL:Round( GetEntityHeading( veh ), 0 )
local sameHeading = UTIL:IsEntityInMyHeading( vehicleHeading, aiVehHeading, 45 )
if ( sameHeading ) then
local mdl = GetEntityModel( veh )
if ( IsThisModelACar( mdl ) or IsThisModelABike( mdl ) or IsThisModelAQuadbike( mdl ) ) then
local bounds = getBoundingBox( veh )
local boundsDrawable = getBoundingBoxDrawable( bounds )
drawBoundingBox( veh, boundsDrawable )
end
end
end
end
-- self:RayTraceFromVeh( vehicle )
-- local newPos = GetOffsetFromEntityInWorldCoords( vehicle, 0.0, 10.0, 0.0 )
-- UTIL:DrawSphere( newPos.x, newPos.y, newPos.z, 6.0, 128, 255, 0, 0.15 )
-- local ranVeh = GetRandomVehicleInSphere( newPos.x, newPos.y, newPos.z, 6.0, 0, 23 )
-- UTIL:DrawDebugText( 0.50, 0.140, 0.60, true, "Found random vehicle: " .. tostring( ranVeh ), 255, 255, 255, 255 )
-- if ( DoesEntityExist( ranVeh ) and IsEntityAVehicle( ranVeh ) ) then
-- local targetPos = GetEntityCoords( ranVeh, true )
-- DrawMarker(2, targetPos.x, targetPos.y, targetPos.z + 6, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 2.0, 2.0, 2.0, 255, 128, 0, 50, false, true, 2, nil, nil, false)
-- end
-- begin bubble test
-- for i = 1, 5 do
-- local newPos = GetOffsetFromEntityInWorldCoords( vehicle, 0.0, i * 10.0, 0.0 )
-- -- UTIL:DrawSphere( newPos1.x, newPos1.y, newPos1.z, 2.0, 128, 255, 20, 0.4 )
-- DrawMarker( 28, newPos.x, newPos.y, newPos.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, i * 2.0, i * 2.0, 0.5, 0, 250, 0, 200, false, true, 2, false, false, false, false )
-- end
end
end
end
Citizen.CreateThread( function()
while ( true ) do
-- RADAR:Main()
RADAR:Test()
Citizen.Wait( 0 )
end
end )

553
cl_radar.lua Normal file
View File

@@ -0,0 +1,553 @@
--[[------------------------------------------------------------------------
Wraith Radar System - v2.0.0
Created by WolfKnight
------------------------------------------------------------------------]]--
local next = next
local dot = dot
local table = table
local type = type
--[[------------------------------------------------------------------------
Resource Rename Fix
------------------------------------------------------------------------]]--
Citizen.CreateThread( function()
-- Wait for a short period of time to give the resource time to load
Citizen.Wait( 5000 )
-- Get the name of the resource, for example the default name is 'wk_wrs2'
local resourceName = GetCurrentResourceName()
-- Send a message through the NUI system to the JavaScript file to
-- give the name of the resource
SendNUIMessage( { resourcename = resourceName } )
end )
--[[------------------------------------------------------------------------
Radar variables
------------------------------------------------------------------------]]--
RADAR.vars =
{
-- Player's vehicle speed
patrolSpeed = 0,
-- The speed type
speedType = "mph",
-- Antennas
antennas = {
front = {
},
back = {
}
},
sortMode = 1,
maxCheckDist = 300.0,
-- Cached dynamic sphere sizes
sphereSizes = {},
-- Vehicle pool
vehiclePool = {},
-- Radar stage, this is used to tell the system what it should currently be doing, the stages are:
-- - 0 = gathering vehicles hit by the radar
-- - 1 = Filtering the vehicles caught
-- - 3 = Calculating what vehicle speed to show based on modes
radarStage = 0,
-- Ray stage
rayTraceState = 0,
-- Number of rays
numberOfRays = 0
}
-- Table to store entity IDs of captured vehicles
RADAR.capturedVehicles = {}
RADAR.caughtEnt = 0
RADAR.rayTraces = {
{ startVec = { x = 0.0, y = 5.0 }, endVec = { x = 0.0, y = 150.0 } },
{ startVec = { x = -5.0, y = 15.0 }, endVec = { x = -5.0, y = 150.0 } },
{ startVec = { x = 5.0, y = 15.0 }, endVec = { x = 5.0, y = 150.0 } },
--{ startVec = { x = -12.0, y = 25.0 }, endVec = { x = -12.0, y = 150.0 } },
--{ startVec = { x = 12.0, y = 25.0 }, endVec = { x = 12.0, y = 150.0 } }
}
RADAR.sorting = {
[1] = { name = "CLOSEST", func = function( a, b ) return a.dist < b.dist end },
[2] = { name = "FASTEST", func = function( a, b ) return a.speed > b.speed end },
--[3] = { name = "FASTEST & CLOSEST", func = function( a, b ) return math.ceil( a.speed ) > math.ceil( b.speed ) and a.dist < b.dist end },
[3] = { name = "LARGEST", func = function( a, b ) return a.size > b.size end }
}
--[[------------------------------------------------------------------------
Radar variable functions
------------------------------------------------------------------------]]--
function RADAR:SetPatrolSpeed( speed )
if ( type( speed ) == "number" ) then
self.vars.patrolSpeed = speed
end
end
function RADAR:GetPatrolSpeed()
return self.vars.patrolSpeed
end
function RADAR:SetVehiclePool( pool )
if ( type( pool ) == "table" ) then
self.vars.vehiclePool = pool
end
end
function RADAR:GetVehiclePool()
return self.vars.vehiclePool
end
function RADAR:GetMaxCheckDist()
return self.vars.maxCheckDist
end
function RADAR:GetRayTraceState()
return self.vars.rayTraceState
end
function RADAR:IncreaseRayTraceState()
self.vars.rayTraceState = self.vars.rayTraceState + 1
end
function RADAR:ResetRayTraceState()
self.vars.rayTraceState = 0
end
function RADAR:GetRadarStage()
return self.vars.radarStage
end
function RADAR:IncreaseRadarStage()
self.vars.radarStage = self.vars.radarStage + 1
end
function RADAR:ResetRadarStage()
self.vars.radarStage = 0
end
function RADAR:GetNumOfRays()
return self.vars.numberOfRays
end
function RADAR:CacheNumOfRays()
self.vars.numberOfRays = #self.rayTraces
end
function RADAR:ToggleSortMode()
if ( self.vars.sortMode < #self.sorting ) then
self.vars.sortMode = self.vars.sortMode + 1
else
self.vars.sortMode = 1
end
UTIL:Notify( "Radar mode set to " .. self.sorting[self.vars.sortMode].name )
end
--[[------------------------------------------------------------------------
Radar functions
------------------------------------------------------------------------]]--
function RADAR:GetVehSpeedFormatted( speed )
if ( self.vars.speedType == "mph" ) then
-- return GetEntitySpeed( veh ) * 2.236936
return math.ceil( speed * 2.236936 )
else
return GetEntitySpeed( veh ) * 3.6
end
end
function RADAR:ResetCapturedVehicles()
self.capturedVehicles = {}
end
function RADAR:InsertCapturedVehicleData( t )
if ( type( t ) == "table" and not UTIL:IsTableEmpty( t ) ) then
for _, v in pairs( t ) do
table.insert( self.capturedVehicles, v )
end
end
end
function RADAR:GetCapturedVehicles()
return self.capturedVehicles
end
function RADAR:FilterCapturedVehicles()
for k, vehTable in pairs( self.capturedVehicles ) do
local veh = vehTable.veh
for b, v in pairs( self.capturedVehicles ) do
if ( v.veh == veh and k ~= b ) then table.remove( self.capturedVehicles, b ) end
end
end
end
function RADAR:GetAllVehicles()
local t = {}
for v in UTIL:EnumerateVehicles() do
table.insert( t, v )
end
return t
end
function RADAR:DoesDynamicRadiusDataExist( key )
return self.vars.sphereSizes[key] ~= nil
end
function RADAR:InsertDynamicRadiusData( key, radius, actualSize )
if ( self.vars.sphereSizes[key] == nil ) then
self.vars.sphereSizes[key] = {}
self.vars.sphereSizes[key].radius = radius
self.vars.sphereSizes[key].actualSize = actualSize
end
end
function RADAR:GetRadiusData( key )
return self.vars.sphereSizes[key].radius or 5.0, self.vars.sphereSizes[key].actualSize
end
function RADAR:GetDynamicRadius( veh )
local mdl = GetEntityModel( veh )
local key = tostring( mdl )
local dataExists = self:DoesDynamicRadiusDataExist( key )
if ( not dataExists ) then
local min, max = GetModelDimensions( mdl )
local size = max - min
local numericSize = size.x + size.y + size.z
local dynamicRadius = UTIL:Clamp( ( numericSize * numericSize ) / 10, 4.0, 10.0 )
self:InsertDynamicRadiusData( key, dynamicRadius, numericSize )
return dynamicRadius, numericSize
end
return self:GetRadiusData( key )
end
function RADAR:GetIntersectedVehIsFrontOrRear( t )
if ( t > 10.0 ) then
return 1 -- vehicle is in front
elseif ( t < -10.0 ) then
return -1 -- vehicle is behind
end
return 0 -- vehicle is next to self
end
function RADAR:GetLineHitsSphereAndDir( centre, radius, rayStart, rayEnd )
-- First we get the normalised ray, this way we then know the direction the ray is going
local rayNorm = norm( rayEnd - rayStart )
-- Then we calculate the ray from the start point to the centre position of the sphere
local rayToCentre = centre - rayStart
-- Now that we have the ray to the centre of the sphere, and the normalised ray direction, we
-- can calculate the shortest point from the centre of the sphere onto the ray itself. This
-- would then give us the opposite side of the right angled triangle. All of the resulting
-- values are also in squared form, as performing square root functions is slower.
local tProj = dot( rayToCentre, rayNorm )
local oppLenSqr = dot( rayToCentre, rayToCentre ) - ( tProj * tProj )
-- Square the radius
local radiusSqr = radius * radius
local rayDist = #( rayEnd - rayStart )
local distToCentre = #( rayStart - centre ) - ( radius * 2 )
-- Now all we have to do is compare the squared opposite length and the radius squared, this
-- will then tell us if the ray intersects with the sphere.
-- if ( oppLenSqr < radiusSqr and ( t0 < ( dist + radius ) ) ) then
if ( oppLenSqr < radiusSqr and not ( distToCentre > rayDist ) ) then
return true, self:GetIntersectedVehIsFrontOrRear( tProj )
end
return false, nil
end
function RADAR:ShootCustomRay( localVeh, veh, s, e )
local pos = GetEntityCoords( veh )
local dist = #( pos - s )
if ( DoesEntityExist( veh ) and veh ~= localVeh and dist < self:GetMaxCheckDist() ) then
local entSpeed = GetEntitySpeed( veh )
local visible = HasEntityClearLosToEntity( localVeh, veh, 15 ) -- 13 seems okay, 15 too (doesn't grab ents through ents)
if ( entSpeed > 0.1 and visible ) then
local radius, size = self:GetDynamicRadius( veh )
local hit, relPos = self:GetLineHitsSphereAndDir( pos, radius, s, e )
if ( hit ) then
UTIL:DrawDebugSphere( pos.x, pos.y, pos.z, radius, { 255, 0, 0, 40 } )
return true, relPos, dist, entSpeed, size
end
end
end
return false, nil, nil, nil, nil
end
function RADAR:GetVehsHitByRay( ownVeh, vehs, s, e )
local t = {}
local hasData = false
for _, veh in pairs( vehs ) do
local hit, relativePos, distance, speed, size = self:ShootCustomRay( ownVeh, veh, s, e )
if ( hit ) then
local d = {}
d.veh = veh
d.relPos = relativePos
d.dist = UTIL:Round( distance, 2 )
d.speed = UTIL:Round( speed, 3 )
d.size = math.ceil( size )
table.insert( t, d )
hasData = true
end
end
if ( hasData ) then return t end
end
function RADAR:CreateRayThread( vehs, from, startX, endX, endY )
--Citizen.CreateThread( function()
local startP = GetOffsetFromEntityInWorldCoords( from, startX, 0.0, 0.0 )
local endP = GetOffsetFromEntityInWorldCoords( from, endX, endY, 0.0 )
UTIL:DrawDebugLine( startP, endP )
local hitVehs = self:GetVehsHitByRay( from, vehs, startP, endP )
self:InsertCapturedVehicleData( hitVehs )
print( "Ray thread: increasing ray state from " .. tostring( self:GetRayTraceState() ) .. " to " .. tostring( self:GetRayTraceState() + 1 ) )
self:IncreaseRayTraceState()
--end )
end
function RADAR:RunControlManager()
-- 'Z' key, toggles debug mode
if ( IsDisabledControlJustPressed( 1, 20 ) ) then
self.config.debug_mode = not self.config.debug_mode
end
-- Change the sort mode
if ( IsDisabledControlJustPressed( 1, 105 ) ) then
self:ToggleSortMode()
end
end
--[[------------------------------------------------------------------------
Test time
------------------------------------------------------------------------]]--
function RADAR:Main()
-- Get the local player's ped and store it in a variable
local ped = PlayerPedId()
-- Get the vehicle the player is sitting in
local plyVeh = GetVehiclePedIsIn( ped, false )
-- Check to make sure the player is in the driver's seat, and also that the vehicle has a class of VC_EMERGENCY (18)
if ( DoesEntityExist( plyVeh ) and GetPedInVehicleSeat( plyVeh, -1 ) == ped and GetVehicleClass( plyVeh ) == 18 ) then
local plyVehPos = GetEntityCoords( plyVeh )
-- First stage of the radar - get all of the vehicles hit by the radar
if ( self:GetRadarStage() == 0 ) then
if ( self:GetRayTraceState() == 0 ) then
print( "Radar stage at 0, starting ray trace." )
local vehs = self:GetVehiclePool()
print( "Resetting captured vehicles and ray trace state." )
self:ResetCapturedVehicles()
self:ResetRayTraceState()
print( "Creating ray threads." )
for _, v in pairs( self.rayTraces ) do
self:CreateRayThread( vehs, plyVeh, v.startVec.x, v.endVec.x, v.endVec.y )
end
print( "Reached end of stage 0." )
print( "Stage = " .. tostring( self:GetRadarStage() ) .. "\tTrace state = " .. tostring( self:GetRayTraceState() ) )
elseif ( self:GetRayTraceState() == self:GetNumOfRays() ) then
print( "Ray traces finished, increasing radar stage." )
self:IncreaseRadarStage()
end
elseif ( self:GetRadarStage() == 1 ) then
print( "Radar stage now 1." )
self:FilterCapturedVehicles()
local caughtVehs = self:GetCapturedVehicles()
if ( not UTIL:IsTableEmpty( caughtVehs ) ) then
-- table.sort( caughtVehs, RADAR.sorting.fastest )
table.sort( caughtVehs, self.sorting[self.vars.sortMode].func )
print( "Printing table for sort mode " .. self.sorting[self.vars.sortMode].name )
for k, v in pairs( caughtVehs ) do
print( tostring( k ) .. " - " .. tostring( v.veh ) .. " - " .. tostring( v.relPos ) .. " - " .. tostring( v.dist ) .. " - " .. tostring( v.speed ) .. " - " .. tostring( v.size ) )
end
self.caughtEnt = caughtVehs[1].veh
else
self.caughtEnt = 0
end
self:ResetRadarStage()
self:ResetRayTraceState()
end
--Wait( 1000 )
end
end
function RADAR:Mainold()
-- Get the local player's ped and store it in a variable
local ped = GetPlayerPed( -1 )
-- As we only want the radar to work when a player is sitting in a
-- vehicle, we run that check first
if ( IsPedSittingInAnyVehicle( ped ) ) then
-- Get the vehicle the player is sitting in
local vehicle = GetVehiclePedIsIn( ped, false )
UTIL:DrawDebugText( 0.50, 0.020, 0.60, true, "Found player vehicle: " .. tostring( vehicle ), 255, 255, 255, 255 )
-- Check to make sure the player is in the driver's seat, and also
-- that the vehicle has a class of VC_EMERGENCY (18)
if ( GetPedInVehicleSeat( vehicle, -1 ) == ped --[[ and GetVehicleClass( vehicle ) == 18 ]] ) then
local vehicleSpeed = UTIL:Round( self:GetVehSpeed( vehicle ), 0 )
local vehicleHeading = UTIL:Round( GetEntityHeading( vehicle ), 0 )
UTIL:DrawDebugText( 0.50, 0.060, 0.60, true, "Self speed: " .. tostring( vehicleSpeed ), 255, 255, 255, 255 )
local vehiclePos = GetEntityCoords( vehicle, true )
-- local edge = GetOffsetFromEntityInWorldCoords( vehicle, 20.0, 50.0, 0.0 )
local newX = UTIL:Round( vehiclePos.x, 0 )
local newY = UTIL:Round( vehiclePos.y, 0 )
local newZ = UTIL:Round( vehiclePos.z, 0 )
UTIL:DrawDebugText( 0.50, 0.100, 0.60, true, "Vehicle X: " .. tostring( newX ) .. " Vehicle Y: " .. tostring( newY ) .. " Vehicle Z: " .. tostring( newZ ), 255, 255, 255, 255 )
local model = GetEntityModel( vehicle )
local min, max = GetModelDimensions( model )
local format = "Min X: " .. tostring( min.x ) .. " Min Y: " .. tostring( min.y ) .. " Min Z: " .. tostring( min.z )
local format2 = "Max X: " .. tostring( max.x ) .. " Max Y: " .. tostring( max.y ) .. " Max Z: " .. tostring( max.z )
UTIL:DrawDebugText( 0.50, 0.180, 0.60, true, "Model: " .. tostring( model ), 255, 255, 255, 255 )
UTIL:DrawDebugText( 0.50, 0.220, 0.60, true, format, 255, 255, 255, 255 )
UTIL:DrawDebugText( 0.50, 0.260, 0.60, true, format2, 255, 255, 255, 255 )
for veh in EnumerateVehicles() do
if ( GetEntitySpeed( veh ) > 1.0 and veh ~= vehicle ) then
local aiVehHeading = UTIL:Round( GetEntityHeading( veh ), 0 )
local sameHeading = UTIL:IsEntityInMyHeading( vehicleHeading, aiVehHeading, 45 )
if ( sameHeading ) then
local mdl = GetEntityModel( veh )
if ( IsThisModelACar( mdl ) or IsThisModelABike( mdl ) or IsThisModelAQuadbike( mdl ) ) then
local bounds = getBoundingBox( veh )
local boundsDrawable = getBoundingBoxDrawable( bounds )
drawBoundingBox( veh, boundsDrawable )
end
end
end
end
-- self:RayTraceFromVeh( vehicle )
-- local newPos = GetOffsetFromEntityInWorldCoords( vehicle, 0.0, 10.0, 0.0 )
-- UTIL:DrawSphere( newPos.x, newPos.y, newPos.z, 6.0, 128, 255, 0, 0.15 )
-- local ranVeh = GetRandomVehicleInSphere( newPos.x, newPos.y, newPos.z, 6.0, 0, 23 )
-- UTIL:DrawDebugText( 0.50, 0.140, 0.60, true, "Found random vehicle: " .. tostring( ranVeh ), 255, 255, 255, 255 )
-- if ( DoesEntityExist( ranVeh ) and IsEntityAVehicle( ranVeh ) ) then
-- local targetPos = GetEntityCoords( ranVeh, true )
-- DrawMarker(2, targetPos.x, targetPos.y, targetPos.z + 6, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 2.0, 2.0, 2.0, 255, 128, 0, 50, false, true, 2, nil, nil, false)
-- end
-- begin bubble test
-- for i = 1, 5 do
-- local newPos = GetOffsetFromEntityInWorldCoords( vehicle, 0.0, i * 10.0, 0.0 )
-- -- UTIL:DrawSphere( newPos1.x, newPos1.y, newPos1.z, 2.0, 128, 255, 20, 0.4 )
-- DrawMarker( 28, newPos.x, newPos.y, newPos.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, i * 2.0, i * 2.0, 0.5, 0, 250, 0, 200, false, true, 2, false, false, false, false )
-- end
end
end
end
-- Update the vehicle pool every 3 seconds
Citizen.CreateThread( function()
while ( true ) do
local vehs = RADAR:GetAllVehicles()
RADAR:SetVehiclePool( vehs )
Citizen.Wait( 3000 )
end
end )
-- Citizen.SetTimeout( 3000, function()
-- local vehs = RADAR:GetAllVehicles()
-- RADAR:SetVehiclePool( vehs )
-- end)
-- Main thread
Citizen.CreateThread( function()
RADAR:CacheNumOfRays()
while ( true ) do
RADAR:Main()
-- RADAR:Test()
Citizen.Wait( 50 )
end
end )
-- Control manager
Citizen.CreateThread( function()
while ( true ) do
RADAR:RunControlManager()
Citizen.Wait( 0 )
end
end )
Citizen.CreateThread( function()
while ( true ) do
local pos = GetEntityCoords( RADAR.caughtEnt )
local speed = GetEntitySpeed( RADAR.caughtEnt )
DrawMarker( 28, pos.x, pos.y, pos.z + 6, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 0.5, 0.5, 3.0, 255, 255, 255, 255, false, true, 2, nil, nil, false )
UTIL:DrawDebugText( 0.500, 0.700, 0.80, true, "Ent: " .. tostring( RADAR.caughtEnt ) .. "\nSpeed: " .. RADAR:GetVehSpeedFormatted( speed ) .. "mph" )
Citizen.Wait( 0 )
end
end)

324
cl_utils.lua Normal file
View File

@@ -0,0 +1,324 @@
--[[-----------------------------------------------------------------------
Wraith Radar System - v2.0.0
Created by WolfKnight
-----------------------------------------------------------------------]]--
UTIL = {}
function UTIL:Round( num, numDecimalPlaces )
-- return tonumber( string.format( "%.0f", num ) )
return tonumber( string.format( "%." .. ( numDecimalPlaces or 0 ) .. "f", num ) )
end
function UTIL:OppositeAngle( ang )
return ( ang + 180 ) % 360
end
function UTIL:FormatSpeed( speed )
return string.format( "%03d", speed )
end
function UTIL:Clamp( val, min, max )
if ( val < min ) then
return min
elseif ( val > max ) then
return max
end
return val
end
function UTIL:IsTableEmpty( t )
local c = 0
for _ in pairs( t ) do c = c + 1 end
return c == 0
end
function UTIL:GetVehicleInDirection( entFrom, coordFrom, coordTo )
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 20.0, 10, entFrom, 7 )
local _, hitEntity, endCoords, surfaceNormal, vehicle = GetShapeTestResult( rayHandle )
return vehicle
end
function UTIL:IsEntityInMyHeading( myAng, tarAng, angToCheck )
local rangeStartFront = myAng - ( angToCheck / 2 )
local rangeEndFront = myAng + ( angToCheck / 2 )
local opp = self:OppositeAngle( myAng )
local rangeStartBack = opp - ( angToCheck / 2 )
local rangeEndBack = opp + ( angToCheck / 2 )
if ( ( tarAng > rangeStartFront ) and ( tarAng < rangeEndFront ) ) then
return true
elseif ( ( tarAng > rangeStartBack ) and ( tarAng < rangeEndBack ) ) then
return false
else
return nil
end
end
function UTIL:Notify( text )
SetNotificationTextEntry( "STRING" )
AddTextComponentSubstringPlayerName( text )
DrawNotification( false, true )
end
function UTIL:DrawDebugText( x, y, scale, centre, text )
SetTextFont( 4 )
SetTextProportional( 0 )
SetTextScale( scale, scale )
SetTextColour( 255, 255, 255, 255 )
SetTextDropShadow( 0, 0, 0, 0, 255 )
SetTextEdge( 2, 0, 0, 0, 255 )
SetTextCentre( centre )
SetTextDropShadow()
SetTextOutline()
SetTextEntry( "STRING" )
AddTextComponentString( text )
DrawText( x, y )
end
function UTIL:DrawDebugSphere( x, y, z, r, col )
if ( RADAR.config.debug_mode ) then
local col = col or { 255, 255, 255, 255 }
DrawMarker( 28, x, y, z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, r, r, r, col[1], col[2], col[3], col[4], false, true, 2, false, false, false, false )
end
end
function UTIL:DrawDebugLine( startP, endP, col )
if ( RADAR.config.debug_mode ) then
local col = col or { 255, 255, 255, 255 }
DrawLine( startP, endP, col[1], col[2], col[3], col[4] )
end
end
UTIL.car_colours = {
[ "0" ] = "Metallic Black",
[ "1" ] = "Metallic Graphite Black",
[ "2" ] = "Metallic Black Steal",
[ "3" ] = "Metallic Dark Silver",
[ "4" ] = "Metallic Silver",
[ "5" ] = "Metallic Blue Silver",
[ "6" ] = "Metallic Steel Gray",
[ "7" ] = "Metallic Shadow Silver",
[ "8" ] = "Metallic Stone Silver",
[ "9" ] = "Metallic Midnight Silver",
[ "10" ] = "Metallic Gun Metal",
[ "11" ] = "Metallic Anthracite Grey",
[ "12" ] = "Matte Black",
[ "13" ] = "Matte Gray",
[ "14" ] = "Matte Light Grey",
[ "15" ] = "Util Black",
[ "16" ] = "Util Black Poly",
[ "17" ] = "Util Dark Silver",
[ "18" ] = "Util Silver",
[ "19" ] = "Util Gun Metal",
[ "20" ] = "Util Shadow Silver",
[ "21" ] = "Worn Black",
[ "22" ] = "Worn Graphite",
[ "23" ] = "Worn Silver Grey",
[ "24" ] = "Worn Silver",
[ "25" ] = "Worn Blue Silver",
[ "26" ] = "Worn Shadow Silver",
[ "27" ] = "Metallic Red",
[ "28" ] = "Metallic Torino Red",
[ "29" ] = "Metallic Formula Red",
[ "30" ] = "Metallic Blaze Red",
[ "31" ] = "Metallic Graceful Red",
[ "32" ] = "Metallic Garnet Red",
[ "33" ] = "Metallic Desert Red",
[ "34" ] = "Metallic Cabernet Red",
[ "35" ] = "Metallic Candy Red",
[ "36" ] = "Metallic Sunrise Orange",
[ "37" ] = "Metallic Classic Gold",
[ "38" ] = "Metallic Orange",
[ "39" ] = "Matte Red",
[ "40" ] = "Matte Dark Red",
[ "41" ] = "Matte Orange",
[ "42" ] = "Matte Yellow",
[ "43" ] = "Util Red",
[ "44" ] = "Util Bright Red",
[ "45" ] = "Util Garnet Red",
[ "46" ] = "Worn Red",
[ "47" ] = "Worn Golden Red",
[ "48" ] = "Worn Dark Red",
[ "49" ] = "Metallic Dark Green",
[ "50" ] = "Metallic Racing Green",
[ "51" ] = "Metallic Sea Green",
[ "52" ] = "Metallic Olive Green",
[ "53" ] = "Metallic Green",
[ "54" ] = "Metallic Gasoline Blue Green",
[ "55" ] = "Matte Lime Green",
[ "56" ] = "Util Dark Green",
[ "57" ] = "Util Green",
[ "58" ] = "Worn Dark Green",
[ "59" ] = "Worn Green",
[ "60" ] = "Worn Sea Wash",
[ "61" ] = "Metallic Midnight Blue",
[ "62" ] = "Metallic Dark Blue",
[ "63" ] = "Metallic Saxony Blue",
[ "64" ] = "Metallic Blue",
[ "65" ] = "Metallic Mariner Blue",
[ "66" ] = "Metallic Harbor Blue",
[ "67" ] = "Metallic Diamond Blue",
[ "68" ] = "Metallic Surf Blue",
[ "69" ] = "Metallic Nautical Blue",
[ "70" ] = "Metallic Bright Blue",
[ "71" ] = "Metallic Purple Blue",
[ "72" ] = "Metallic Spinnaker Blue",
[ "73" ] = "Metallic Ultra Blue",
[ "74" ] = "Metallic Bright Blue",
[ "75" ] = "Util Dark Blue",
[ "76" ] = "Util Midnight Blue",
[ "77" ] = "Util Blue",
[ "78" ] = "Util Sea Foam Blue",
[ "79" ] = "Uil Lightning Blue",
[ "80" ] = "Util Maui Blue Poly",
[ "81" ] = "Util Bright Blue",
[ "82" ] = "Matte Dark Blue",
[ "83" ] = "Matte Blue",
[ "84" ] = "Matte Midnight Blue",
[ "85" ] = "Worn Dark Blue",
[ "86" ] = "Worn Blue",
[ "87" ] = "Worn Light Blue",
[ "88" ] = "Metallic Taxi Yellow",
[ "89" ] = "Metallic Race Yellow",
[ "90" ] = "Metallic Bronze",
[ "91" ] = "Metallic Yellow Bird",
[ "92" ] = "Metallic Lime",
[ "93" ] = "Metallic Champagne",
[ "94" ] = "Metallic Pueblo Beige",
[ "95" ] = "Metallic Dark Ivory",
[ "96" ] = "Metallic Choco Brown",
[ "97" ] = "Metallic Golden Brown",
[ "98" ] = "Metallic Light Brown",
[ "99" ] = "Metallic Straw Beige",
[ "100" ] = "Metallic Moss Brown",
[ "101" ] = "Metallic Biston Brown",
[ "102" ] = "Metallic Beechwood",
[ "103" ] = "Metallic Dark Beechwood",
[ "104" ] = "Metallic Choco Orange",
[ "105" ] = "Metallic Beach Sand",
[ "106" ] = "Metallic Sun Bleeched Sand",
[ "107" ] = "Metallic Cream",
[ "108" ] = "Util Brown",
[ "109" ] = "Util Medium Brown",
[ "110" ] = "Util Light Brown",
[ "111" ] = "Metallic White",
[ "112" ] = "Metallic Frost White",
[ "113" ] = "Worn Honey Beige",
[ "114" ] = "Worn Brown",
[ "115" ] = "Worn Dark Brown",
[ "116" ] = "Worn Straw Beige",
[ "117" ] = "Brushed Steel",
[ "118" ] = "Brushed Black Steel",
[ "119" ] = "Brushed Aluminium",
[ "120" ] = "Chrome",
[ "121" ] = "Worn Off White",
[ "122" ] = "Util Off White",
[ "123" ] = "Worn Orange",
[ "124" ] = "Worn Light Orange",
[ "125" ] = "Metallic Securicor Green",
[ "126" ] = "Worn Taxi Yellow",
[ "127" ] = "Police Car Blue",
[ "128" ] = "Matte Green",
[ "129" ] = "Matte Brown",
[ "130" ] = "Worn Orange",
[ "131" ] = "Matte White",
[ "132" ] = "Worn White",
[ "133" ] = "Worn Olive Army Green",
[ "134" ] = "Pure White",
[ "135" ] = "Hot Pink",
[ "136" ] = "Salmon Pink",
[ "137" ] = "Metallic Vermillion Pink",
[ "138" ] = "Orange",
[ "139" ] = "Green",
[ "140" ] = "Blue",
[ "141" ] = "Mettalic Black Blue",
[ "142" ] = "Metallic Black Purple",
[ "143" ] = "Metallic Black Red",
[ "144" ] = "Hunter Green",
[ "145" ] = "Metallic Purple",
[ "146" ] = "Metaillic V Dark Blue",
[ "147" ] = "MODSHOP BLACK1",
[ "148" ] = "Matte Purple",
[ "149" ] = "Matte Dark Purple",
[ "150" ] = "Metallic Lava Red",
[ "151" ] = "Matte Forest Green",
[ "152" ] = "Matte Olive Drab",
[ "153" ] = "Matte Desert Brown",
[ "154" ] = "Matte Desert Tan",
[ "155" ] = "Matte Foilage Green",
[ "156" ] = "DEFAULT ALLOY COLOR",
[ "157" ] = "Epsilon Blue"
}
--[[The MIT License (MIT)
Copyright (c) 2017 IllidanS4
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
The below code can be found at: https://gist.github.com/IllidanS4/9865ed17f60576425369fc1da70259b2
]]
local entityEnumerator = {
__gc = function(enum)
if enum.destructor and enum.handle then
enum.destructor(enum.handle)
end
enum.destructor = nil
enum.handle = nil
end
}
local function EnumerateEntities(initFunc, moveFunc, disposeFunc)
return coroutine.wrap(function()
local iter, id = initFunc()
if not id or id == 0 then
disposeFunc(iter)
return
end
local enum = {handle = iter, destructor = disposeFunc}
setmetatable(enum, entityEnumerator)
local next = true
repeat
coroutine.yield(id)
next, id = moveFunc(iter)
until not next
enum.destructor, enum.handle = nil, nil
disposeFunc(iter)
end)
end
function UTIL:EnumerateVehicles()
return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
end

26
config.lua Normal file
View File

@@ -0,0 +1,26 @@
--[[------------------------------------------------------------------------
Wraith Radar System - v2.0.0
Created by WolfKnight
------------------------------------------------------------------------]]--
-- Do not touch this
RADAR = {}
RADAR.config = {}
-- Radar Control Panel key
-- The default key to open the radar control panel is 166 (F5 - INPUT_SELECT_CHARACTER_MICHAEL)
RADAR.config.control_panel_key = 166
-- Radar Unlock/Reset Key
-- The default key to unlock/reset the radar is 244 (M - INPUT_INTERACTION_MENU)
RADAR.config.reset_key = 244
-- Fast Lock Blip
-- true = vehicles that go over the fast limit will have a blip added to the minimap for a short period of time
-- false = no blips
RADAR.config.fast_lock_blips = true
-- Debug mode
RADAR.config.debug_mode = true

BIN
nui/digital-7.regular.ttf Normal file

Binary file not shown.

302
nui/radar.css Normal file
View File

@@ -0,0 +1,302 @@
/*-------------------------------------------------------------------------
Wraith Radar System - v1.0.3
Created by WolfKnight
Just a word of warning, I'm not the best at CSS structure, so this
could probably be 10x better, but fuck it.
-------------------------------------------------------------------------*/
@font-face {
font-family: "Digital-7";
src: url( "digital-7.regular.ttf" );
}
/* Police Radar */
#policeradar {
/* To change the scale of the radar, change the value in the 'scale' function below.
Examples:
- 1.0 = default size
- 2.0 = twice the original size
- 0.5 = half the original size */
transform: scale( 2.0 );
width: 495px;
height: 202px;
position: absolute;
margin: auto;
bottom: 10px;
/* Below is the configuration for whether you want the radar in the bottom right
hand corner, or the bottom middle. */
/* Bottom right */
right: 10px;
/* Bottom middle */
/*right: 0;
left: 0; */
color: white;
background: rgba( 20, 20, 20, 0.97 );
background: linear-gradient( to bottom, rgb( 50, 50, 50 ), rgb( 25, 25, 25 ) );
border-radius: 10px;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
#policeradar .antennalabel {
font-family: Verdana;
font-size: 14px;
font-weight: bold;
text-align: center;
width: 100%;
position: absolute;
}
#policeradar .antennalabeltop {
top: 0;
left: 0;
padding-top: 5px;
}
#policeradar .antennalabelbottom {
bottom: 0;
left: 0;
padding-bottom: 5px;
}
#policeradar .logo {
font-family: Verdana;
font-size: 17px;
font-weight: bold;
bottom: 15px;
right: 20px;
position: absolute;
}
#policeradar .main {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
width: 100%;
height: 100%;
}
#policeradar .patrolcontainer {
background-color: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
#policeradar .typecontainer {
background-color: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
width: 0;
}
#policeradar .typecontainer .text {
font-family: Verdana;
font-size: 10px;
line-height: 27px;
margin-left: 13px;
color: black;
}
#policeradar .typecontainer .active {
color: white;
}
#policeradar .container {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
justify-content: space-around;
}
#policeradar .container .label {
font-family: Verdana;
font-weight: bold;
font-size: 10px;
text-align: center;
}
#policeradar .container .speedsourcecontainer {
width: 135px;
height: 58px;
display: flex;
justify-content: space-around;
}
#policeradar .container .speedsourcecontainer .speednumber {
width: 100%;
}
#policeradar .container .speedsourcecontainer .text {
font-family: "Digital-7";
font-size: 58px;
line-height: 58px;
width: 100%;
text-align: center;
}
#policeradar .container .target {
background: rgb( 200, 0, 0 );
background: linear-gradient( to bottom, rgb( 220, 0, 40 ), rgb( 90, 0, 0 ) );
}
#policeradar .container .patrol {
background: rgb( 0, 125, 0 );
background: linear-gradient( to bottom, rgb( 0, 150, 0 ), rgb( 0, 75, 0 ) );
}
#policeradar .container .locked {
color: rgb( 50, 0, 0 );
}
#policeradar .container .speedfastcontainer {
width: 99px;
height: 50px;
display: flex;
flex-direction: row;
justify-content: space-around;
}
#policeradar .container .speedfastcontainer .speednumber {
width: 100%;
}
#policeradar .container .speedfastcontainer .text {
font-family: "Digital-7";
font-size: 50px;
line-height: 50px;
width: 100%;
text-align: center;
}
#policeradar .arrowbox {
justify-content: center;
align-items: center;
}
#policeradar .arrowbox i {
font-size: 20px;
padding-top: 5px;
padding-bottom: 5px;
color: black;
}
#policeradar .arrowbox .active {
color: white;
}
#policeradar .arrowbox .inactive {
color: black;
}
/* Police Radar - Remote Control */
#policeradarrc {
width: 290px;
height: 380px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
padding: 10px 5px;
color: white;
background-color: rgba( 20, 20, 20, 0.95 );
border-radius: 5px;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
#policeradarrc .breakline {
width: 230px;
height: 10px;
background-color: white;
}
#policeradarrc .label {
font-family: Verdana;
}
#policeradarrc .container {
font-family: Verdana;
align-items: center;
}
#policeradarrc .container button {
display: inline-block;
cursor: pointer;
text-decoration: none;
outline: none;
border: none;
}
#policeradarrc .container button:hover {
background-color: #6cd3f9;
}
#policeradarrc .container button:active {
background-color: #56a8c7;
}
#policeradarrc .container .toggle {
padding: 5px 15px;
font-size: 16px;
text-align: center;
color: black;
background-color: white;
border-radius: 15px;
margin-bottom: 15px;
}
#policeradarrc .container .limit {
padding: 5px 15px;
font-size: 16px;
text-align: center;
color: black;
background-color: white;
border-radius: 15px;
margin-top: 15px;
}
#policeradarrc .container .close {
padding: 3px 7px;
font-size: 12px;
}
#policeradarrc .container .rowbutton {
width: 60px;
height: 60px;
}
#policeradarrc .container .frontopp {
border-top-left-radius: 50%;
}
#policeradarrc .container .frontsame {
border-top-right-radius: 50%;
}
#policeradarrc .container .rearopp {
border-bottom-left-radius: 50%;
}
#policeradarrc .container .rearsame {
border-bottom-right-radius: 50%;
}

158
nui/radar.html Normal file
View File

@@ -0,0 +1,158 @@
<!--
Wraith Radar System - v1.0.3
Created by WolfKnight
-->
<html>
<head>
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
<script src="radar.js" type="text/javascript"></script>
<link href="radar.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body onselectstart="return false;" ondragstart="return false;">
<!-- Police Radar -->
<div id="policeradar" style="display: none;">
<div class="antennalabel antennalabeltop">Front Antenna</div>
<div class="logo">WraithRS</div>
<div class="main">
<div class="container">
<div class="typecontainer">
<div class="text"><span class="fwdsame">SAME</span></div>
<div class="text"><span class="fwdopp">OPP</span></div>
<div class="text"><span class="fwdxmit">XMIT</span></div>
</div>
<div class="typecontainer">
<div class="text"><span class="bwdsame">SAME</span></div>
<div class="text"><span class="bwdopp">OPP</span></div>
<div class="text"><span class="bwdxmit">XMIT</span></div>
</div>
</div>
<div class="container">
<div class="patrolcontainer">
<div class="speedsourcecontainer target" data-target="fwdspeed">
<div class="speednumber text"></div>
<div class="speednumber text"></div>
<div class="speednumber text"></div>
</div>
<div class="label">FWD</div>
</div>
<div class="patrolcontainer">
<div class="speedsourcecontainer target" data-target="bwdspeed">
<div class="speednumber text"></div>
<div class="speednumber text"></div>
<div class="speednumber text"></div>
</div>
<div class="label">BWD</div>
</div>
</div>
<div class="container" style="width: 5px;">
<div class="arrowbox">
<i class="fa fa-arrow-up fwdarrowfront"></i>
<i class="fa fa-arrow-down fwdarrowback"></i>
</div>
<div class="arrowbox">
<i class="fa fa-arrow-up bwdarrowfront"></i>
<i class="fa fa-arrow-down bwdarrowback"></i>
</div>
</div>
<div class="container">
<div class="patrolcontainer" style="margin-top: 20px;">
<div class="speedfastcontainer target" data-target="fwdfast">
<div class="speednumber text"></div>
<div class="speednumber text"></div>
<div class="speednumber text"></div>
</div>
<div class="label">FWD FAST</div>
</div>
<div class="patrolcontainer" style="margin-bottom: 20px;">
<div class="speedfastcontainer target" data-target="bwdfast">
<div class="speednumber text"></div>
<div class="speednumber text"></div>
<div class="speednumber text"></div>
</div>
<div class="label">BWD FAST</div>
</div>
</div>
<div class="container">
<div class="patrolcontainer">
<div class="speedfastcontainer patrol" data-target="patrolspeed">
<div class="speednumber text"></div>
<div class="speednumber text"></div>
<div class="speednumber text"></div>
</div>
<div class="label">PATROL SPEED</div>
</div>
</div>
</div>
<div class="antennalabel antennalabelbottom">Rear Antenna</div>
</div>
<!-- Police Radar - Remote control -->
<div id="policeradarrc" style="display: none;">
<div class="container">
<button class="toggle" data-action="radar_toggle">TOGGLE RADAR</button>
</div>
<div class="label">FRONT ANTENNA</div>
<div class="container">
<button class="rowbutton frontopp" data-action="radar_frontopp">OPP</button>
<button class="rowbutton frontxmit" data-action="radar_frontxmit">XMIT</button>
<button class="rowbutton frontsame" data-action="radar_frontsame">SAME</button>
</div>
<div class="breakline"></div>
<div class="container">
<button class="rowbutton rearopp" data-action="radar_rearopp">OPP</button>
<button class="rowbutton rearxmit" data-action="radar_rearxmit">XMIT</button>
<button class="rowbutton rearsame" data-action="radar_rearsame">SAME</button>
</div>
<div class="label">REAR ANTENNA</div>
<div class="container">
<button class="limit" data-action="radar_setlimit">SET FAST LIMIT</button>
</div>
<div class="container">
<button class="limit" data-action="radar_speedtype" style="margin-top: 0px;">TOGGLE SPEED TYPE</button>
</div>
<div class="container">
<button class="limit" data-action="radar_lockbeep" style="margin-top: 0px;">TOGGLE LOCK BEEP</button>
</div>
<div class="container">
<button class="close" data-action="close">CLOSE</button>
</div>
</div>
<!-- Police Radar - Set Fast Limit Numpad -->
<div id="policeradarnumpad" style="display: none;">
</div>
</body>
</html>

197
nui/radar.js Normal file
View File

@@ -0,0 +1,197 @@
/*-------------------------------------------------------------------------
Wraith Radar System - v1.0.3
Created by WolfKnight
-------------------------------------------------------------------------*/
var resourceName = "";
var radarEnabled = false;
var targets = [];
$( function() {
radarInit();
var radarContainer = $( "#policeradar" );
var fwdArrowFront = radarContainer.find( ".fwdarrowfront" );
var fwdArrowBack = radarContainer.find( ".fwdarrowback" );
var bwdArrowFront = radarContainer.find( ".bwdarrowfront" );
var bwdArrowBack = radarContainer.find( ".bwdarrowback" );
var fwdSame = radarContainer.find( ".fwdsame" );
var fwdOpp = radarContainer.find( ".fwdopp" );
var fwdXmit = radarContainer.find( ".fwdxmit" );
var bwdSame = radarContainer.find( ".bwdsame" );
var bwdOpp = radarContainer.find( ".bwdopp" );
var bwdXmit = radarContainer.find( ".bwdxmit" );
var radarRCContainer = $( "#policeradarrc" );
window.addEventListener( 'message', function( event ) {
var item = event.data;
// change this to a switch/case instead of multiple if statements
if ( item.resourcename ) {
resourceName = item.resourcename;
}
if ( item.toggleradar ) {
radarEnabled = !radarEnabled;
radarContainer.fadeToggle();
}
if ( item.hideradar ) {
radarContainer.fadeOut();
} else if ( item.hideradar == false ) {
radarContainer.fadeIn();
}
if ( item.patrolspeed ) {
updateSpeed( "patrolspeed", item.patrolspeed );
}
if ( item.fwdspeed ) {
updateSpeed( "fwdspeed", item.fwdspeed );
}
if ( item.fwdfast ) {
updateSpeed( "fwdfast", item.fwdfast );
}
if ( item.lockfwdfast == true || item.lockfwdfast == false ) {
lockSpeed( "fwdfast", item.lockfwdfast )
}
if ( item.bwdspeed ) {
updateSpeed( "bwdspeed", item.bwdspeed );
}
if ( item.bwdfast ) {
updateSpeed( "bwdfast", item.bwdfast );
}
if ( item.lockbwdfast == true || item.lockbwdfast == false ) {
lockSpeed( "bwdfast", item.lockbwdfast )
}
if ( item.fwddir || item.fwddir == false || item.fwddir == null ) {
updateArrowDir( fwdArrowFront, fwdArrowBack, item.fwddir )
}
if ( item.bwddir || item.bwddir == false || item.bwddir == null ) {
updateArrowDir( bwdArrowFront, bwdArrowBack, item.bwddir )
}
if ( item.fwdxmit ) {
fwdXmit.addClass( "active" );
} else if ( item.fwdxmit == false ) {
fwdXmit.removeClass( "active" );
}
if ( item.bwdxmit ) {
bwdXmit.addClass( "active" );
} else if ( item.bwdxmit == false ) {
bwdXmit.removeClass( "active" );
}
if ( item.fwdmode ) {
modeSwitch( fwdSame, fwdOpp, item.fwdmode );
}
if ( item.bwdmode ) {
modeSwitch( bwdSame, bwdOpp, item.bwdmode );
}
if ( item.toggleradarrc ) {
radarRCContainer.toggle();
}
} );
} )
function radarInit() {
$( '.container' ).each( function( i, obj ) {
$( this ).find( '[data-target]' ).each( function( subi, subobj ) {
targets[ $( this ).attr( "data-target" ) ] = $( this )
} )
} );
$( "#policeradarrc" ).find( "button" ).each( function( i, obj ) {
if ( $( this ).attr( "data-action" ) ) {
$( this ).click( function() {
var data = $( this ).data( "action" );
sendData( "RadarRC", data );
} )
}
} );
/* With the new scaling option in the css file, it can cause the radar to go off the screen if
the transform-origin property is not set according to where the radar is positioned. The below
code is a simple workaround that sets the origin depending on what the user has configured for
the position of the radar from the two available options in the css file. */
var left = $( "#policeradar" ).css( "left" );
if ( left == "auto" ) {
$( "#policeradar" ).css( "transform-origin", "bottom right" );
} else {
$( "#policeradar" ).css( "transform-origin", "bottom center" );
}
}
// function dbgFunc()
// {
// var left = $( "#policeradar" ).css( "left" );
// sendData( "debug", "Left: " + left );
// }
function updateSpeed( attr, data ) {
targets[ attr ].find( ".speednumber" ).each( function( i, obj ) {
$( obj ).html( data[i] );
} );
}
function lockSpeed( attr, state ) {
targets[ attr ].find( ".speednumber" ).each( function( i, obj ) {
if ( state == true ) {
$( obj ).addClass( "locked" );
} else {
$( obj ).removeClass( "locked" );
}
} );
}
function modeSwitch( sameEle, oppEle, state ) {
if ( state == "same" ) {
sameEle.addClass( "active" );
oppEle.removeClass( "active" );
} else if ( state == "opp" ) {
oppEle.addClass( "active" );
sameEle.removeClass( "active" );
} else if ( state == "none" ) {
oppEle.removeClass( "active" );
sameEle.removeClass( "active" );
}
}
function updateArrowDir( fwdEle, bwdEle, state ) {
if ( state == true ) {
fwdEle.addClass( "active" );
bwdEle.removeClass( "active" );
} else if ( state == false ) {
bwdEle.addClass( "active" );
fwdEle.removeClass( "active" );
} else if ( state == null ) {
fwdEle.removeClass( "active" );
bwdEle.removeClass( "active" );
}
}
function sendData( name, data ) {
$.post( "http://" + resourceName + "/" + name, JSON.stringify( data ), function( datab ) {
if ( datab != "ok" ) {
console.log( datab );
}
} );
}

619
old_cl_radar.lua Normal file
View File

@@ -0,0 +1,619 @@
--[[------------------------------------------------------------------------
Wraith Radar System - v1.0.3
Created by WolfKnight
------------------------------------------------------------------------]]--
--[[------------------------------------------------------------------------
Resource Rename Fix
------------------------------------------------------------------------]]--
Citizen.CreateThread( function()
Citizen.Wait( 1000 )
local resourceName = GetCurrentResourceName()
SendNUIMessage( { resourcename = resourceName } )
end )
--[[-----------------------------------------------------------------------
Test
-----------------------------------------------------------------------]]--
local entityEnumerator = {
__gc = function(enum)
if enum.destructor and enum.handle then
enum.destructor(enum.handle)
end
enum.destructor = nil
enum.handle = nil
end
}
local function EnumerateEntities(initFunc, moveFunc, disposeFunc)
return coroutine.wrap(function()
local iter, id = initFunc()
if not id or id == 0 then
disposeFunc(iter)
return
end
local enum = {handle = iter, destructor = disposeFunc}
setmetatable(enum, entityEnumerator)
local next = true
repeat
coroutine.yield(id)
next, id = moveFunc(iter)
until not next
enum.destructor, enum.handle = nil, nil
disposeFunc(iter)
end)
end
function EnumerateObjects()
return EnumerateEntities(FindFirstObject, FindNextObject, EndFindObject)
end
function EnumeratePeds()
return EnumerateEntities(FindFirstPed, FindNextPed, EndFindPed)
end
function EnumerateVehicles()
return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
end
function EnumeratePickups()
return EnumerateEntities(FindFirstPickup, FindNextPickup, EndFindPickup)
end
--[[------------------------------------------------------------------------
Utils
------------------------------------------------------------------------]]--
function round( num )
return tonumber( string.format( "%.0f", num ) )
end
function oppang( ang )
return ( ang + 180 ) % 360
end
function FormatSpeed( speed )
return string.format( "%03d", speed )
end
function GetVehicleInDirectionSphere( entFrom, coordFrom, coordTo )
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 2.0, 10, entFrom, 7 )
local _, _, _, _, vehicle = GetShapeTestResult( rayHandle )
return vehicle
end
function IsEntityInMyHeading( myAng, tarAng, range )
local rangeStartFront = myAng - ( range / 2 )
local rangeEndFront = myAng + ( range / 2 )
local opp = oppang( myAng )
local rangeStartBack = opp - ( range / 2 )
local rangeEndBack = opp + ( range / 2 )
if ( ( tarAng > rangeStartFront ) and ( tarAng < rangeEndFront ) ) then
return true
elseif ( ( tarAng > rangeStartBack ) and ( tarAng < rangeEndBack ) ) then
return false
else
return nil
end
end
--[[------------------------------------------------------------------------
Police Vehicle Radar
------------------------------------------------------------------------]]--
local radarEnabled = false
local hidden = false
local radarInfo =
{
patrolSpeed = "000",
speedType = "mph",
fwdPrevVeh = 0,
fwdXmit = true,
fwdMode = "same",
fwdSpeed = "000",
fwdFast = "000",
fwdFastLocked = false,
fwdDir = nil,
fwdFastSpeed = 0,
bwdPrevVeh = 0,
bwdXmit = false,
bwdMode = "none",
bwdSpeed = "OFF",
bwdFast = "OFF",
bwdFastLocked = false,
bwdDir = nil,
bwdFastSpeed = 0,
fastResetLimit = 150,
fastLimit = 60,
angles = { [ "same" ] = { x = 0.0, y = 70.0, z = 0.0 }, [ "opp" ] = { x = -10.0, y = 50.0, z = 0.0 } },
lockBeep = true
}
RegisterNetEvent( 'wk:toggleRadar' )
AddEventHandler( 'wk:toggleRadar', function()
local ped = GetPlayerPed( -1 )
if ( IsPedSittingInAnyVehicle( ped ) ) then
local vehicle = GetVehiclePedIsIn( ped, false )
if ( GetVehicleClass( vehicle ) == 18 ) then
radarEnabled = not radarEnabled
if ( radarEnabled ) then
Notify( "~b~Radar enabled." )
else
Notify( "~b~Radar disabled." )
end
ResetFrontAntenna()
ResetRearAntenna()
SendNUIMessage({
toggleradar = true,
fwdxmit = radarInfo.fwdXmit,
fwdmode = radarInfo.fwdMode,
bwdxmit = radarInfo.bwdXmit,
bwdmode = radarInfo.bwdMode
})
else
Notify( "~r~You must be in a police vehicle." )
end
else
Notify( "~r~You must be in a vehicle." )
end
end )
RegisterNetEvent( 'wk:changeRadarLimit' )
AddEventHandler( 'wk:changeRadarLimit', function( speed )
radarInfo.fastLimit = speed
end )
function Radar_SetLimit()
Citizen.CreateThread( function()
DisplayOnscreenKeyboard( false, "", "", "", "", "", "", 4 )
while true do
if ( UpdateOnscreenKeyboard() == 1 ) then
local speedStr = GetOnscreenKeyboardResult()
if ( string.len( speedStr ) > 0 ) then
local speed = tonumber( speedStr )
if ( speed < 999 and speed > 1 ) then
TriggerEvent( 'wk:changeRadarLimit', speed )
end
break
else
DisplayOnscreenKeyboard( false, "", "", "", "", "", "", 4 )
end
elseif ( UpdateOnscreenKeyboard() == 2 ) then
break
end
Citizen.Wait( 0 )
end
end )
end
function ResetFrontAntenna()
if ( radarInfo.fwdXmit ) then
radarInfo.fwdSpeed = "000"
radarInfo.fwdFast = "000"
else
radarInfo.fwdSpeed = "OFF"
radarInfo.fwdFast = " "
end
radarInfo.fwdDir = nil
radarInfo.fwdFastSpeed = 0
radarInfo.fwdFastLocked = false
end
function ResetRearAntenna()
if ( radarInfo.bwdXmit ) then
radarInfo.bwdSpeed = "000"
radarInfo.bwdFast = "000"
else
radarInfo.bwdSpeed = "OFF"
radarInfo.bwdFast = " "
end
radarInfo.bwdDir = nil
radarInfo.bwdFastSpeed = 0
radarInfo.bwdFastLocked = false
end
function ResetFrontFast()
if ( radarInfo.fwdXmit ) then
radarInfo.fwdFast = "000"
radarInfo.fwdFastSpeed = 0
radarInfo.fwdFastLocked = false
SendNUIMessage( { lockfwdfast = false } )
end
end
function ResetRearFast()
if ( radarInfo.bwdXmit ) then
radarInfo.bwdFast = "000"
radarInfo.bwdFastSpeed = 0
radarInfo.bwdFastLocked = false
SendNUIMessage( { lockbwdfast = false } )
end
end
function CloseRadarRC()
SendNUIMessage({
toggleradarrc = true
})
TriggerEvent( 'wk:toggleMenuControlLock', false )
SetNuiFocus( false )
end
function ToggleSpeedType()
if ( radarInfo.speedType == "mph" ) then
radarInfo.speedType = "kmh"
Notify( "~b~Speed type set to Km/h." )
else
radarInfo.speedType = "mph"
Notify( "~b~Speed type set to MPH." )
end
end
function ToggleLockBeep()
if ( radarInfo.lockBeep ) then
radarInfo.lockBeep = false
Notify( "~b~Radar fast lock beep disabled." )
else
radarInfo.lockBeep = true
Notify( "~b~Radar fast lock beep enabled." )
end
end
function GetVehSpeed( veh )
if ( radarInfo.speedType == "mph" ) then
return GetEntitySpeed( veh ) * 2.236936
else
return GetEntitySpeed( veh ) * 3.6
end
end
function ManageVehicleRadar()
if ( radarEnabled ) then
local ped = GetPlayerPed( -1 )
if ( IsPedSittingInAnyVehicle( ped ) ) then
local vehicle = GetVehiclePedIsIn( ped, false )
if ( GetPedInVehicleSeat( vehicle, -1 ) == ped and GetVehicleClass( vehicle ) == 18 ) then
-- Patrol speed
local vehicleSpeed = round( GetVehSpeed( vehicle ), 0 )
radarInfo.patrolSpeed = FormatSpeed( vehicleSpeed )
-- Rest of the radar options
local vehiclePos = GetEntityCoords( vehicle, true )
local h = round( GetEntityHeading( vehicle ), 0 )
-- Front Antenna
if ( radarInfo.fwdXmit ) then
local newPos = GetOffsetFromEntityInWorldCoords( vehicle, 0.0, 5.0, 0.0 )
local forwardPosition = GetOffsetFromEntityInWorldCoords( vehicle, radarInfo.angles[ radarInfo.fwdMode ].x, radarInfo.angles[ radarInfo.fwdMode ].y, radarInfo.angles[ radarInfo.fwdMode ].z )
local fwdPos = { x = forwardPosition.x, y = forwardPosition.y, z = forwardPosition.z }
local _, fwdZ = GetGroundZFor_3dCoord( fwdPos.x, fwdPos.y, fwdPos.z + 500.0 )
if ( fwdPos.z < fwdZ and not ( fwdZ > vehiclePos.z + 1.0 ) ) then
fwdPos.z = fwdZ + 0.5
end
-- Draw line for debug
--DrawLine( newPos.x, newPos.y, newPos.z, fwdPos.x, fwdPos.y, fwdPos.z, 255, 255, 255, 255 )
--DrawDText( 0.015, 0.25, 0.65, false, "Vehicle X: " .. vehiclePos.x .. "\nVehicle Y: " .. vehiclePos.y .. "\nVehicle Z: " .. vehiclePos.z, 255, 255, 255, 255 )
--DrawDText( 0.2, 0.25, 0.65, false, "New X: " .. newPos.x .. "\nNew Y: " .. newPos.y .. "\nNew Z: " .. newPos.z, 255, 255, 255, 255 )
--DrawDText( 0.015, 0.42, 0.65, false, "End X: " .. fwdPos.x .. "\nEnd Y: " .. fwdPos.y .. "\nEnd Z: " .. fwdPos.z, 255, 255, 255, 255 )
local packedFwdPos = vector3( fwdPos.x, fwdPos.y, fwdPos.z )
local newVehiclePos = vector3( newPos.x, newPos.y, newPos.z )
local fwdVeh = GetVehicleInDirectionSphere( vehicle, newVehiclePos, packedFwdPos )
--DrawDText( 0.015, 0.65, 0.65, false, "Ray entity: " .. tostring( fwdVeh ) .. "\nType: " .. GetEntityType( fwdVeh ), 255, 255, 255, 255 )
if ( DoesEntityExist( fwdVeh ) and IsEntityAVehicle( fwdVeh ) ) then
local fwdVehSpeed = round( GetVehSpeed( fwdVeh ), 0 )
local fwdVehHeading = round( GetEntityHeading( fwdVeh ), 0 )
local dir = IsEntityInMyHeading( h, fwdVehHeading, 100 )
-- Draw line for debug to car
local pos = GetEntityCoords( fwdVeh, true )
-- DrawLine( vehiclePos.x, vehiclePos.y, vehiclePos.z, pos.x, pos.y, pos.z, 255, 255, 255, 255 )
DrawMarker(2, pos.x, pos.y, pos.z + 6, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 2.0, 2.0, 2.0, 255, 128, 0, 50, false, true, 2, nil, nil, false)
radarInfo.fwdSpeed = FormatSpeed( fwdVehSpeed )
radarInfo.fwdDir = dir
if ( fwdVehSpeed > radarInfo.fastLimit and not radarInfo.fwdFastLocked ) then
if ( radarInfo.lockBeep ) then
PlaySoundFrontend( -1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", 1 )
end
radarInfo.fwdFastSpeed = fwdVehSpeed
radarInfo.fwdFastLocked = true
SendNUIMessage( { lockfwdfast = true } )
end
radarInfo.fwdFast = FormatSpeed( radarInfo.fwdFastSpeed )
radarInfo.fwdPrevVeh = fwdVeh
--[[ Test
local plate = GetVehicleNumberPlateText( fwdVeh )
local colourPrimary, colourSecondary = GetVehicleColours( fwdVeh )
local name = GetLabelText( GetDisplayNameFromVehicleModel( GetEntityModel( fwdVeh ) ) )
local class = GetLabelText( "VEH_CLASS_" .. tostring( GetVehicleClass( fwdVeh ) ) )
Notify( "Name: " .. name .. "\nClass: " .. class .. "\nPlate: " .. plate .. "\nColour: " .. CAR_COLOURS[ tostring( colourPrimary ) ] .. " / " .. CAR_COLOURS[ tostring( colourSecondary ) ] )
]]
end
end
-- Rear Antenna
if ( radarInfo.bwdXmit ) then
local backwardPosition = GetOffsetFromEntityInWorldCoords( vehicle, radarInfo.angles[ radarInfo.bwdMode ].x, -radarInfo.angles[ radarInfo.bwdMode ].y, radarInfo.angles[ radarInfo.bwdMode ].z )
local bwdPos = { x = backwardPosition.x, y = backwardPosition.y, z = backwardPosition.z }
local _, bwdZ = GetGroundZFor_3dCoord( bwdPos.x, bwdPos.y, bwdPos.z + 500.0 )
if ( bwdPos.z < bwdZ and not ( bwdZ > vehiclePos.z + 1.0 ) ) then
bwdPos.z = bwdZ + 0.5
end
local packedBwdPos = vector3( bwdPos.x, bwdPos.y, bwdPos.z )
local bwdVeh = GetVehicleInDirectionSphere( vehicle, vehiclePos, packedBwdPos )
if ( DoesEntityExist( bwdVeh ) and IsEntityAVehicle( bwdVeh ) ) then
local bwdVehSpeed = round( GetVehSpeed( bwdVeh ), 0 )
local bwdVehHeading = round( GetEntityHeading( bwdVeh ), 0 )
local dir = IsEntityInMyHeading( h, bwdVehHeading, 100 )
radarInfo.bwdSpeed = FormatSpeed( bwdVehSpeed )
radarInfo.bwdDir = dir
if ( bwdVehSpeed > radarInfo.fastLimit and not radarInfo.bwdFastLocked ) then
if ( radarInfo.lockBeep ) then
PlaySoundFrontend( -1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", 1 )
end
radarInfo.bwdFastSpeed = bwdVehSpeed
radarInfo.bwdFastLocked = true
SendNUIMessage( { lockbwdfast = true } )
end
radarInfo.bwdFast = FormatSpeed( radarInfo.bwdFastSpeed )
radarInfo.bwdPrevVeh = bwdVeh
end
end
SendNUIMessage({
patrolspeed = radarInfo.patrolSpeed,
fwdspeed = radarInfo.fwdSpeed,
fwdfast = radarInfo.fwdFast,
fwddir = radarInfo.fwdDir,
bwdspeed = radarInfo.bwdSpeed,
bwdfast = radarInfo.bwdFast,
bwddir = radarInfo.bwdDir
})
end
end
end
end
RegisterNetEvent( 'wk:radarRC' )
AddEventHandler( 'wk:radarRC', function()
Citizen.Wait( 10 )
TriggerEvent( 'wk:toggleMenuControlLock', true )
SendNUIMessage({
toggleradarrc = true
})
SetNuiFocus( true, true )
end )
RegisterNUICallback( "debug", function( data, cb )
TriggerEvent( "chat:addMessage", {
color = { 255, 255, 255 },
multiline = true,
args = { "WraithRS DEBUG", data }
})
end )
RegisterNUICallback( "RadarRC", function( data, cb )
-- Toggle Radar
if ( data == "radar_toggle" ) then
TriggerEvent( 'wk:toggleRadar' )
-- Front Antenna
elseif ( data == "radar_frontopp" and radarInfo.fwdXmit ) then
radarInfo.fwdMode = "opp"
SendNUIMessage( { fwdmode = radarInfo.fwdMode } )
elseif ( data == "radar_frontxmit" ) then
radarInfo.fwdXmit = not radarInfo.fwdXmit
ResetFrontAntenna()
SendNUIMessage( { fwdxmit = radarInfo.fwdXmit } )
if ( radarInfo.fwdXmit == false ) then
radarInfo.fwdMode = "none"
else
radarInfo.fwdMode = "same"
end
SendNUIMessage( { fwdmode = radarInfo.fwdMode } )
elseif ( data == "radar_frontsame" and radarInfo.fwdXmit ) then
radarInfo.fwdMode = "same"
SendNUIMessage( { fwdmode = radarInfo.fwdMode } )
-- Rear Antenna
elseif ( data == "radar_rearopp" and radarInfo.bwdXmit ) then
radarInfo.bwdMode = "opp"
SendNUIMessage( { bwdmode = radarInfo.bwdMode } )
elseif ( data == "radar_rearxmit" ) then
radarInfo.bwdXmit = not radarInfo.bwdXmit
ResetRearAntenna()
SendNUIMessage( { bwdxmit = radarInfo.bwdXmit } )
if ( radarInfo.bwdXmit == false ) then
radarInfo.bwdMode = "none"
else
radarInfo.bwdMode = "same"
end
SendNUIMessage( { bwdmode = radarInfo.bwdMode } )
elseif ( data == "radar_rearsame" and radarInfo.bwdXmit ) then
radarInfo.bwdMode = "same"
SendNUIMessage( { bwdmode = radarInfo.bwdMode } )
-- Set Fast Limit
elseif ( data == "radar_setlimit" ) then
CloseRadarRC()
Radar_SetLimit()
-- Speed Type
elseif ( data == "radar_speedtype" ) then
ToggleSpeedType()
elseif ( data == "radar_lockbeep" ) then
ToggleLockBeep()
-- Close
elseif ( data == "close" ) then
CloseRadarRC()
end
if ( cb ) then cb( 'ok' ) end
end )
Citizen.CreateThread( function()
SetNuiFocus( false )
while true do
ManageVehicleRadar()
-- Only run 10 times a second, more realistic, also prevents spam
Citizen.Wait( 100 )
-- Citizen.Wait( 0 )
end
end )
Citizen.CreateThread( function()
while true do
local ped = GetPlayerPed( -1 )
-- These control pressed natives must be the disabled check ones.
-- LCtrl is pressed and M has just been pressed
if ( IsDisabledControlPressed( 1, 36 ) and IsDisabledControlJustPressed( 1, 244 ) and IsPedSittingInAnyVehicle( ped ) ) then
TriggerEvent( 'wk:radarRC' )
end
-- LCtrl is not being pressed and M has just been pressed
if ( not IsDisabledControlPressed( 1, 36 ) and IsDisabledControlJustPressed( 1, 244 ) ) then
ResetFrontFast()
ResetRearFast()
end
local inVeh = IsPedSittingInAnyVehicle( ped )
local veh = nil
if ( inVeh ) then
veh = GetVehiclePedIsIn( ped, false )
end
if ( ( (not inVeh or (inVeh and GetVehicleClass( veh ) ~= 18)) and radarEnabled and not hidden) or IsPauseMenuActive() and radarEnabled ) then
hidden = true
SendNUIMessage( { hideradar = true } )
elseif ( inVeh and GetVehicleClass( veh ) == 18 and radarEnabled and hidden ) then
hidden = false
SendNUIMessage( { hideradar = false } )
end
Citizen.Wait( 0 )
end
end )
--[[------------------------------------------------------------------------
Menu Control Lock - Prevents certain actions
Thanks to the authors of the ES Banking script.
------------------------------------------------------------------------]]--
local locked = false
RegisterNetEvent( 'wk:toggleMenuControlLock' )
AddEventHandler( 'wk:toggleMenuControlLock', function( lock )
locked = lock
end )
Citizen.CreateThread( function()
while true do
if ( locked ) then
local ped = GetPlayerPed( -1 )
DisableControlAction( 0, 1, true ) -- LookLeftRight
DisableControlAction( 0, 2, true ) -- LookUpDown
DisableControlAction( 0, 24, true ) -- Attack
DisablePlayerFiring( ped, true ) -- Disable weapon firing
DisableControlAction( 0, 142, true ) -- MeleeAttackAlternate
DisableControlAction( 0, 106, true ) -- VehicleMouseControlOverride
SetPauseMenuActive( false )
end
Citizen.Wait( 0 )
end
end )
--[[------------------------------------------------------------------------
Notify
------------------------------------------------------------------------]]--
function Notify( text )
SetNotificationTextEntry( "STRING" )
AddTextComponentSubstringPlayerName( text )
DrawNotification( false, true )
end
function DrawDText( x, y, scale, centre, text, r, g, b, a )
SetTextFont(4)
SetTextProportional(0)
SetTextScale(scale, scale)
SetTextColour(r, g, b, a)
SetTextDropShadow(0, 0, 0, 0,255)
SetTextEdge(2, 0, 0, 0, 255)
SetTextCentre( centre )
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText( x, y )
end

17
radar operation.txt Normal file
View File

@@ -0,0 +1,17 @@
Process:
- Run the custom ray trace function to check bounding boxes
- Collect all of the hit vehicles in a table (RADAR.vars.capturedVehicles)
- Priority goes to the vehicle which fits the set direction mode (fwd/bwd) and the set radar mode (fastest/biggest)
- Loop through the vehicle table and grab the one that fits the above mentioned modes
- Display the chosen vehicle's speed in the radar
Checks:
- Vehicle must be moving faster than 1.0 (units)
- Vehicle is not the player's vehicle
- Vehicle is a car, motorcycle, or a quadbike
Possible TODO:
- Create a system that stores bounding box data of models in a table so that the system doesn't have to create new data for models that have been previously caught by the radar
Development notes:
- Set the radiusSqr to be based on vehicle class