mirror of
https://github.com/Michatec/wk_wars2x.git
synced 2026-04-01 00:16:27 +02:00
Comments and formatting
This commit is contained in:
@@ -15,26 +15,30 @@ READER = {}
|
|||||||
----------------------------------------------------------------------------------]]--
|
----------------------------------------------------------------------------------]]--
|
||||||
READER.vars =
|
READER.vars =
|
||||||
{
|
{
|
||||||
-- Whether or not the radar's UI is visible
|
-- Whether or not the plate reader's UI is visible
|
||||||
displayed = false,
|
displayed = false,
|
||||||
|
|
||||||
-- Whether or not the radar should be hidden, e.g. the display is active but the player then steps
|
-- Whether or not the plate reader should be hidden, e.g. the display is active but the player then steps
|
||||||
-- out of their vehicle
|
-- out of their vehicle
|
||||||
hidden = false,
|
hidden = false,
|
||||||
|
|
||||||
|
-- The BOLO plate
|
||||||
boloPlate = "",
|
boloPlate = "",
|
||||||
|
|
||||||
|
-- Cameras, this table contains all of the data needed for operation of the front and rear plate reader
|
||||||
cams = {
|
cams = {
|
||||||
|
-- Variables for the front camera
|
||||||
["front"] = {
|
["front"] = {
|
||||||
plate = "",
|
plate = "", -- The current plate caught by the reader
|
||||||
index = "",
|
index = "", -- The index of the current plate
|
||||||
locked = false
|
locked = false -- If the reader is locked
|
||||||
},
|
},
|
||||||
|
|
||||||
|
-- Variables for the rear camera
|
||||||
["rear"] = {
|
["rear"] = {
|
||||||
plate = "",
|
plate = "", -- The current plate caught by the reader
|
||||||
index = "",
|
index = "", -- The index of the current plate
|
||||||
lockec = false
|
locked = false -- If the reader is locked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +48,7 @@ function READER:GetDisplayState()
|
|||||||
return self.vars.displayed
|
return self.vars.displayed
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Toggles the display state of the radar system
|
-- Toggles the display state of the plate reader system
|
||||||
function READER:ToggleDisplayState()
|
function READER:ToggleDisplayState()
|
||||||
-- Toggle the display variable
|
-- Toggle the display variable
|
||||||
self.vars.displayed = not self.vars.displayed
|
self.vars.displayed = not self.vars.displayed
|
||||||
@@ -63,48 +67,63 @@ function READER:GetDisplayHidden()
|
|||||||
return self.vars.hidden
|
return self.vars.hidden
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns the stored plate for the given reader
|
||||||
function READER:GetPlate( cam )
|
function READER:GetPlate( cam )
|
||||||
return self.vars.cams[cam].plate
|
return self.vars.cams[cam].plate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Sets the plate for the given reader to the given plate
|
||||||
function READER:SetPlate( cam, plate )
|
function READER:SetPlate( cam, plate )
|
||||||
self.vars.cams[cam].plate = plate
|
self.vars.cams[cam].plate = plate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns the stored plate index for the given reader
|
||||||
function READER:GetIndex( cam )
|
function READER:GetIndex( cam )
|
||||||
return self.vars.cams[cam].index
|
return self.vars.cams[cam].index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Sets the plate index for the given reader to the given index
|
||||||
function READER:SetIndex( cam, index )
|
function READER:SetIndex( cam, index )
|
||||||
self.vars.cams[cam].index = index
|
self.vars.cams[cam].index = index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns the bolo plate
|
||||||
function READER:GetBoloPlate()
|
function READER:GetBoloPlate()
|
||||||
return self.vars.boloPlate
|
return self.vars.boloPlate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Sets the bolo plate to the given plate
|
||||||
function READER:SetBoloPlate( plate )
|
function READER:SetBoloPlate( plate )
|
||||||
self.vars.boloPlate = plate
|
self.vars.boloPlate = plate
|
||||||
UTIL:Notify( "BOLO plate set to: " .. plate )
|
UTIL:Notify( "BOLO plate set to: " .. plate )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns if the given reader is locked
|
||||||
function READER:GetCamLocked( cam )
|
function READER:GetCamLocked( cam )
|
||||||
return self.vars.cams[cam].locked
|
return self.vars.cams[cam].locked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Locks the given reader
|
||||||
function READER:LockCam( cam )
|
function READER:LockCam( cam )
|
||||||
|
-- Check that plate readers can actually be locked
|
||||||
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
|
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
|
||||||
|
-- Toggle the lock state
|
||||||
self.vars.cams[cam].locked = not self.vars.cams[cam].locked
|
self.vars.cams[cam].locked = not self.vars.cams[cam].locked
|
||||||
|
|
||||||
|
-- Tell the NUI side to show/hide the lock icon
|
||||||
SendNUIMessage( { _type = "lockPlate", cam = cam, state = self:GetCamLocked( cam ) } )
|
SendNUIMessage( { _type = "lockPlate", cam = cam, state = self:GetCamLocked( cam ) } )
|
||||||
|
|
||||||
|
-- Play a beep
|
||||||
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
|
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns if the plate reader system can perform tasks
|
||||||
function READER:CanPerformMainTask()
|
function READER:CanPerformMainTask()
|
||||||
return self.vars.displayed and not self.vars.hidden
|
return self.vars.displayed and not self.vars.hidden
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns if the given relative position value is for front or rear
|
||||||
function READER:GetCamFromNum( relPos )
|
function READER:GetCamFromNum( relPos )
|
||||||
if ( relPos == 1 ) then
|
if ( relPos == 1 ) then
|
||||||
return "front"
|
return "front"
|
||||||
@@ -119,32 +138,56 @@ RegisterNUICallback( "togglePlateReaderDisplay", function()
|
|||||||
READER:ToggleDisplayState()
|
READER:ToggleDisplayState()
|
||||||
end )
|
end )
|
||||||
|
|
||||||
-- Runs when the "Toggle Display" button is pressed on the plate reder box
|
-- Runs when the "Set BOLO Plate" button is pressed on the plate reader box
|
||||||
RegisterNUICallback( "setBoloPlate", function( plate, cb )
|
RegisterNUICallback( "setBoloPlate", function( plate, cb )
|
||||||
|
-- Set the BOLO plate
|
||||||
READER:SetBoloPlate( plate )
|
READER:SetBoloPlate( plate )
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
-- This is the main function that runs and scans all vehicles in front and behind the patrol vehicle
|
||||||
function READER:Main()
|
function READER:Main()
|
||||||
|
-- Check that the system can actually run
|
||||||
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
|
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
|
||||||
|
-- Loop through front (1) and rear (-1)
|
||||||
for i = 1, -1, -2 do
|
for i = 1, -1, -2 do
|
||||||
local start = GetEntityCoords( PLY.veh )
|
-- Get the world position of the player's vehicle
|
||||||
local offset = GetOffsetFromEntityInWorldCoords( PLY.veh, 0.0, ( 40.0 * i ), 0.0 )
|
local pos = GetEntityCoords( PLY.veh )
|
||||||
|
|
||||||
|
-- Get a start position 5m in front/behind the player's vehicle
|
||||||
|
local start = GetOffsetFromEntityInWorldCoords( PLY.veh, 0.0, ( 5.0 * i ), 0.0 )
|
||||||
|
|
||||||
|
-- Get the end position 40m in front/behind the player's vehicle
|
||||||
|
local offset = GetOffsetFromEntityInWorldCoords( PLY.veh, -2.5, ( 50.0 * i ), 0.0 )
|
||||||
|
|
||||||
|
-- Run the ray trace to get a vehicle
|
||||||
local veh = UTIL:GetVehicleInDirection( PLY.veh, start, offset )
|
local veh = UTIL:GetVehicleInDirection( PLY.veh, start, offset )
|
||||||
|
|
||||||
|
-- Get the plate reader text for front/rear
|
||||||
local cam = self:GetCamFromNum( i )
|
local cam = self:GetCamFromNum( i )
|
||||||
|
|
||||||
|
-- Only proceed to read a plate if the hit entity is a valid vehicle and the current camera isn't locked
|
||||||
if ( DoesEntityExist( veh ) and IsEntityAVehicle( veh ) and not self:GetCamLocked( cam ) ) then
|
if ( DoesEntityExist( veh ) and IsEntityAVehicle( veh ) and not self:GetCamLocked( cam ) ) then
|
||||||
|
-- Get the licence plate text from the vehicle
|
||||||
local plate = GetVehicleNumberPlateText( veh )
|
local plate = GetVehicleNumberPlateText( veh )
|
||||||
|
|
||||||
|
-- Get the licence plate index from the vehicle
|
||||||
local index = GetVehicleNumberPlateTextIndex( veh )
|
local index = GetVehicleNumberPlateTextIndex( veh )
|
||||||
|
|
||||||
|
-- Only update the stored plate if it's different, otherwise we'd keep sending a NUI message to update the displayed
|
||||||
|
-- plate and image even though they're the same
|
||||||
if ( self:GetPlate( cam ) ~= plate ) then
|
if ( self:GetPlate( cam ) ~= plate ) then
|
||||||
|
-- Set the plate for the current reader
|
||||||
self:SetPlate( cam, plate )
|
self:SetPlate( cam, plate )
|
||||||
|
|
||||||
|
-- Set the plate index for the current reader
|
||||||
self:SetIndex( cam, index )
|
self:SetIndex( cam, index )
|
||||||
|
|
||||||
|
-- Automatically lock the plate if the scanned plate matches the BOLO
|
||||||
if ( plate == self:GetBoloPlate() ) then
|
if ( plate == self:GetBoloPlate() ) then
|
||||||
self:LockCam( cam )
|
self:LockCam( cam )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Send the plate information to the NUI side to update the UI
|
||||||
SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } )
|
SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -152,14 +195,20 @@ function READER:Main()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Main thread
|
||||||
Citizen.CreateThread( function()
|
Citizen.CreateThread( function()
|
||||||
while ( true ) do
|
while ( true ) do
|
||||||
|
-- Run the main plate reader function
|
||||||
READER:Main()
|
READER:Main()
|
||||||
|
|
||||||
|
-- Wait half a second
|
||||||
Citizen.Wait( 500 )
|
Citizen.Wait( 500 )
|
||||||
end
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
-- This function is pretty much straight from WraithRS, it does the job so I didn't see the point in not
|
||||||
|
-- using it. Hides the radar UI when certain criteria is met, e.g. in pause menu or stepped out ot the
|
||||||
|
-- patrol vehicle
|
||||||
function READER:RunDisplayValidationCheck()
|
function READER:RunDisplayValidationCheck()
|
||||||
if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then
|
if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then
|
||||||
self:SetDisplayHidden( true )
|
self:SetDisplayHidden( true )
|
||||||
@@ -170,12 +219,15 @@ function READER:RunDisplayValidationCheck()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Runs the display validation check for the radar
|
||||||
Citizen.CreateThread( function()
|
Citizen.CreateThread( function()
|
||||||
Citizen.Wait( 100 )
|
Citizen.Wait( 100 )
|
||||||
|
|
||||||
while ( true ) do
|
while ( true ) do
|
||||||
|
-- Run the check
|
||||||
READER:RunDisplayValidationCheck()
|
READER:RunDisplayValidationCheck()
|
||||||
|
|
||||||
|
-- Wait half a second
|
||||||
Citizen.Wait( 500 )
|
Citizen.Wait( 500 )
|
||||||
end
|
end
|
||||||
end )
|
end )
|
||||||
177
cl_radar.lua
177
cl_radar.lua
@@ -35,16 +35,20 @@ end )
|
|||||||
----------------------------------------------------------------------------------]]--
|
----------------------------------------------------------------------------------]]--
|
||||||
local spawned = false
|
local spawned = false
|
||||||
|
|
||||||
|
-- Runs every time the player spawns, but the additional check means it only runs the first time
|
||||||
|
-- the player spawns
|
||||||
AddEventHandler( "playerSpawned", function()
|
AddEventHandler( "playerSpawned", function()
|
||||||
if ( not spawned ) then
|
if ( not spawned ) then
|
||||||
TriggerServerEvent( "wk:getUiData" )
|
-- Ask the server to get the player's saved UI data
|
||||||
spawned = true
|
TriggerServerEvent( "wk:getUiData" )
|
||||||
end
|
spawned = true
|
||||||
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
-- Grabs the saved UI data sent by the server and forwards it to the NUI side
|
||||||
RegisterNetEvent( "wk:loadUiData" )
|
RegisterNetEvent( "wk:loadUiData" )
|
||||||
AddEventHandler( "wk:loadUiData", function( data )
|
AddEventHandler( "wk:loadUiData", function( data )
|
||||||
SendNUIMessage( { _type = "loadUiSettings", data = data } )
|
SendNUIMessage( { _type = "loadUiSettings", data = data } )
|
||||||
end )
|
end )
|
||||||
|
|
||||||
--[[----------------------------------------------------------------------------------
|
--[[----------------------------------------------------------------------------------
|
||||||
@@ -52,10 +56,10 @@ end )
|
|||||||
----------------------------------------------------------------------------------]]--
|
----------------------------------------------------------------------------------]]--
|
||||||
PLY =
|
PLY =
|
||||||
{
|
{
|
||||||
ped = PlayerPedId(),
|
ped = PlayerPedId(),
|
||||||
veh = nil,
|
veh = nil,
|
||||||
inDriverSeat = false,
|
inDriverSeat = false,
|
||||||
vehClassValid = false
|
vehClassValid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Used to check if the player is in a position where the radar should be allowed operation
|
-- Used to check if the player is in a position where the radar should be allowed operation
|
||||||
@@ -109,10 +113,10 @@ RADAR.vars =
|
|||||||
["opp"] = 3,
|
["opp"] = 3,
|
||||||
|
|
||||||
-- The volume of the audible beep
|
-- The volume of the audible beep
|
||||||
["beep"] = 1.0,
|
["beep"] = 1.0,
|
||||||
|
|
||||||
-- The volume of the verbal lock confirmation
|
-- The volume of the verbal lock confirmation
|
||||||
["voice"] = 1.0,
|
["voice"] = 1.0,
|
||||||
|
|
||||||
-- The speed unit used in conversions
|
-- The speed unit used in conversions
|
||||||
["speedType"] = "mph"
|
["speedType"] = "mph"
|
||||||
@@ -126,8 +130,8 @@ RADAR.vars =
|
|||||||
{ displayText = { "¦¦¦", "FAS" }, optionsText = { "On¦", "Off" }, options = { true, false }, optionIndex = 1, settingText = "fastDisplay" },
|
{ displayText = { "¦¦¦", "FAS" }, optionsText = { "On¦", "Off" }, options = { true, false }, optionIndex = 1, settingText = "fastDisplay" },
|
||||||
{ displayText = { "¦SL", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 3, settingText = "same" },
|
{ displayText = { "¦SL", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 3, settingText = "same" },
|
||||||
{ displayText = { "¦OP", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 3, settingText = "opp" },
|
{ displayText = { "¦OP", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 3, settingText = "opp" },
|
||||||
{ displayText = { "bEE", "P¦¦" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 6, settingText = "beep" },
|
{ displayText = { "bEE", "P¦¦" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 6, settingText = "beep" },
|
||||||
{ displayText = { "VOI", "CE¦" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 6, settingText = "voice" },
|
{ displayText = { "VOI", "CE¦" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = 6, settingText = "voice" },
|
||||||
{ displayText = { "Uni", "tS¦" }, optionsText = { "USA", "INT" }, options = { "mph", "kmh" }, optionIndex = 1, settingText = "speedType" }
|
{ displayText = { "Uni", "tS¦" }, optionsText = { "USA", "INT" }, options = { "mph", "kmh" }, optionIndex = 1, settingText = "speedType" }
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -193,10 +197,10 @@ RADAR.vars =
|
|||||||
|
|
||||||
-- The wait time for the ray trace system, this changes dynamically based on if the player's vehicle is stationary
|
-- The wait time for the ray trace system, this changes dynamically based on if the player's vehicle is stationary
|
||||||
-- or not
|
-- or not
|
||||||
threadWaitTime = 500,
|
threadWaitTime = 500,
|
||||||
|
|
||||||
-- Key lock, when true, prevents any of the radar's key events from working, like the ELS key lock
|
-- Key lock, when true, prevents any of the radar's key events from working, like the ELS key lock
|
||||||
keyLock = false
|
keyLock = false
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Speed conversion values
|
-- Speed conversion values
|
||||||
@@ -411,19 +415,19 @@ end
|
|||||||
|
|
||||||
-- Toggles the internal key lock state, which stops any of the radar's key binds from working
|
-- Toggles the internal key lock state, which stops any of the radar's key binds from working
|
||||||
function RADAR:ToggleKeyLock()
|
function RADAR:ToggleKeyLock()
|
||||||
-- Check the player state is valid
|
-- Check the player state is valid
|
||||||
if ( PLY:VehicleStateValid() ) then
|
if ( PLY:VehicleStateValid() ) then
|
||||||
-- Toggle the key lock variable
|
-- Toggle the key lock variable
|
||||||
self.vars.keyLock = not self.vars.keyLock
|
self.vars.keyLock = not self.vars.keyLock
|
||||||
|
|
||||||
-- Tell the NUI side to display the key lock message
|
-- Tell the NUI side to display the key lock message
|
||||||
SendNUIMessage( { _type = "displayKeyLock", state = self:GetKeyLockState() } )
|
SendNUIMessage( { _type = "displayKeyLock", state = self:GetKeyLockState() } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns the key lock state
|
-- Returns the key lock state
|
||||||
function RADAR:GetKeyLockState()
|
function RADAR:GetKeyLockState()
|
||||||
return self.vars.keyLock
|
return self.vars.keyLock
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -626,12 +630,12 @@ end
|
|||||||
-- much further away (400+ units). Also, as my system uses sphere intersections, each sphere can have a different
|
-- much further away (400+ units). Also, as my system uses sphere intersections, each sphere can have a different
|
||||||
-- radius, which means that larger vehicles can have larger spheres, and smaller vehicles can have smaller spheres.
|
-- radius, which means that larger vehicles can have larger spheres, and smaller vehicles can have smaller spheres.
|
||||||
function RADAR:GetLineHitsSphereAndDir( c, radius, rs, re )
|
function RADAR:GetLineHitsSphereAndDir( c, radius, rs, re )
|
||||||
-- Take the vector3's and turn them into vector2's, this way all of the calculations below are for an
|
-- Take the vector3's and turn them into vector2's, this way all of the calculations below are for an
|
||||||
-- infinite cylinder rather than a sphere, which also means that vehicles can be detected even when on
|
-- infinite cylinder rather than a sphere, which also means that vehicles can be detected even when on
|
||||||
-- an incline!
|
-- an incline!
|
||||||
local rayStart = vector2( rs.x, rs.y )
|
local rayStart = vector2( rs.x, rs.y )
|
||||||
local rayEnd = vector2( re.x, re.y )
|
local rayEnd = vector2( re.x, re.y )
|
||||||
local centre = vector2( c.x, c.y )
|
local centre = vector2( c.x, c.y )
|
||||||
|
|
||||||
-- First we get the normalised ray, this way we then know the direction the ray is going
|
-- First we get the normalised ray, this way we then know the direction the ray is going
|
||||||
local rayNorm = norm( rayEnd - rayStart )
|
local rayNorm = norm( rayEnd - rayStart )
|
||||||
@@ -674,7 +678,7 @@ function RADAR:ShootCustomRay( plyVeh, veh, s, e )
|
|||||||
|
|
||||||
-- Calculate the distance between the target vehicle and the start point of the ray trace, note how we don't
|
-- Calculate the distance between the target vehicle and the start point of the ray trace, note how we don't
|
||||||
-- use GetDistanceBetweenCoords or Vdist, the method below still returns the same result with less cpu time
|
-- use GetDistanceBetweenCoords or Vdist, the method below still returns the same result with less cpu time
|
||||||
local dist = #( pos - s )
|
local dist = #( pos - s )
|
||||||
|
|
||||||
-- We only perform a trace on the target vehicle if it exists, isn't the player's vehicle, and the distance is
|
-- We only perform a trace on the target vehicle if it exists, isn't the player's vehicle, and the distance is
|
||||||
-- less than the max distance defined by the system
|
-- less than the max distance defined by the system
|
||||||
@@ -683,10 +687,10 @@ function RADAR:ShootCustomRay( plyVeh, veh, s, e )
|
|||||||
local entSpeed = GetEntitySpeed( veh )
|
local entSpeed = GetEntitySpeed( veh )
|
||||||
|
|
||||||
-- Check that the target vehicle is within the line of sight of the player's vehicle
|
-- Check that the target vehicle is within the line of sight of the player's vehicle
|
||||||
local visible = HasEntityClearLosToEntity( plyVeh, veh, 15 ) -- 13 seems okay, 15 too (doesn't grab ents through ents)
|
local visible = HasEntityClearLosToEntity( plyVeh, veh, 15 ) -- 13 seems okay, 15 too (doesn't grab ents through ents)
|
||||||
|
|
||||||
-- Get the pitch of the player's vehicle
|
-- Get the pitch of the player's vehicle
|
||||||
local pitch = GetEntityPitch( plyVeh )
|
local pitch = GetEntityPitch( plyVeh )
|
||||||
|
|
||||||
-- Now we check that the target vehicle is moving and is visible
|
-- Now we check that the target vehicle is moving and is visible
|
||||||
if ( entSpeed > 0.1 and ( pitch > -35 and pitch < 35 ) and visible ) then
|
if ( entSpeed > 0.1 and ( pitch > -35 and pitch < 35 ) and visible ) then
|
||||||
@@ -928,10 +932,10 @@ function RADAR:SetAntennaSpeedLock( ant, speed, dir, lockType )
|
|||||||
self:SetAntennaSpeedIsLocked( ant, true )
|
self:SetAntennaSpeedIsLocked( ant, true )
|
||||||
|
|
||||||
-- Send a message to the NUI side to play the beep sound with the current volume setting
|
-- Send a message to the NUI side to play the beep sound with the current volume setting
|
||||||
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
|
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
|
||||||
|
|
||||||
-- Send a message to the NUI side to play the lock audio with the current voice volume setting
|
-- Send a message to the NUI side to play the lock audio with the current voice volume setting
|
||||||
SendNUIMessage( { _type = "lockAudio", ant = ant, dir = dir, vol = RADAR:GetSettingValue( "voice" ) } )
|
SendNUIMessage( { _type = "lockAudio", ant = ant, dir = dir, vol = RADAR:GetSettingValue( "voice" ) } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -966,10 +970,10 @@ end
|
|||||||
function RADAR:LockAntennaSpeed( ant )
|
function RADAR:LockAntennaSpeed( ant )
|
||||||
-- Only lock a speed if the antenna is on and the UI is displayed
|
-- Only lock a speed if the antenna is on and the UI is displayed
|
||||||
if ( self:IsPowerOn() and self:GetDisplayState() and not self:GetDisplayHidden() and self:IsAntennaTransmitting( ant ) ) then
|
if ( self:IsPowerOn() and self:GetDisplayState() and not self:GetDisplayHidden() and self:IsAntennaTransmitting( ant ) ) then
|
||||||
-- Check if the antenna doesn't have a locked speed, if it doesn't then we lock in the speed, otherwise we
|
-- Check if the antenna doesn't have a locked speed, if it doesn't then we lock in the speed, otherwise we
|
||||||
-- reset the lock
|
-- reset the lock
|
||||||
if ( not self:IsAntennaSpeedLocked( ant ) ) then
|
if ( not self:IsAntennaSpeedLocked( ant ) ) then
|
||||||
-- Set up a temporary table with 3 nil values, this way if the system isn't able to get a speed or
|
-- Set up a temporary table with 3 nil values, this way if the system isn't able to get a speed or
|
||||||
-- direction, the speed lock function won't work
|
-- direction, the speed lock function won't work
|
||||||
local data = { nil, nil, nil }
|
local data = { nil, nil, nil }
|
||||||
|
|
||||||
@@ -986,7 +990,7 @@ function RADAR:LockAntennaSpeed( ant )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Lock in the speed data for the antenna
|
-- Lock in the speed data for the antenna
|
||||||
self:SetAntennaSpeedLock( ant, data[1], data[2], data[3] )
|
self:SetAntennaSpeedLock( ant, data[1], data[2], data[3] )
|
||||||
else
|
else
|
||||||
self:ResetAntennaSpeedLock( ant )
|
self:ResetAntennaSpeedLock( ant )
|
||||||
end
|
end
|
||||||
@@ -1039,8 +1043,8 @@ function RADAR:InsertCapturedVehicleData( t, rt )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
These need to be changed so a ray type can be set too, otherwise in its current state, messes up vehicle
|
These need to be changed so a ray type can be set too, otherwise in its current state, messes up vehicle
|
||||||
detection.
|
detection.
|
||||||
|
|
||||||
-- Sets the given value to true in the temp vehicles table, it is a test system used to reduce ray traces
|
-- Sets the given value to true in the temp vehicles table, it is a test system used to reduce ray traces
|
||||||
-- on vehicles that have already been hit by another trace. Currently not implemented fully, as it doesn't
|
-- on vehicles that have already been hit by another trace. Currently not implemented fully, as it doesn't
|
||||||
@@ -1342,7 +1346,7 @@ end )
|
|||||||
|
|
||||||
-- Runs when the JavaScript side sends the UI data for saving
|
-- Runs when the JavaScript side sends the UI data for saving
|
||||||
RegisterNUICallback( "saveUiData", function( data, cb )
|
RegisterNUICallback( "saveUiData", function( data, cb )
|
||||||
TriggerServerEvent( "wk:saveUiData", data )
|
TriggerServerEvent( "wk:saveUiData", data )
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
|
||||||
@@ -1526,15 +1530,21 @@ end
|
|||||||
|
|
||||||
-- Main thread
|
-- Main thread
|
||||||
Citizen.CreateThread( function()
|
Citizen.CreateThread( function()
|
||||||
|
-- Remove the NUI focus just in case
|
||||||
SetNuiFocus( false, false )
|
SetNuiFocus( false, false )
|
||||||
|
|
||||||
|
-- Run the function to cache the number of rays, this way a hard coded number is never needed
|
||||||
RADAR:CacheNumRays()
|
RADAR:CacheNumRays()
|
||||||
|
|
||||||
|
-- Update the end coordinates for the ray traces based on the config, again, reduced hard coding
|
||||||
RADAR:UpdateRayEndCoords()
|
RADAR:UpdateRayEndCoords()
|
||||||
|
|
||||||
|
-- If the fast limit feature is allowed, create the config in the radar variables
|
||||||
if ( RADAR:IsFastLimitAllowed() ) then
|
if ( RADAR:IsFastLimitAllowed() ) then
|
||||||
RADAR:CreateFastLimitConfig()
|
RADAR:CreateFastLimitConfig()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Run the main radar function
|
||||||
while ( true ) do
|
while ( true ) do
|
||||||
RADAR:Main()
|
RADAR:Main()
|
||||||
|
|
||||||
@@ -1542,6 +1552,9 @@ Citizen.CreateThread( function()
|
|||||||
end
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
-- This function is pretty much straight from WraithRS, it does the job so I didn't see the point in not
|
||||||
|
-- using it. Hides the radar UI when certain criteria is met, e.g. in pause menu or stepped out ot the
|
||||||
|
-- patrol vehicle
|
||||||
function RADAR:RunDisplayValidationCheck()
|
function RADAR:RunDisplayValidationCheck()
|
||||||
if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then
|
if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then
|
||||||
self:SetDisplayHidden( true )
|
self:SetDisplayHidden( true )
|
||||||
@@ -1552,69 +1565,79 @@ function RADAR:RunDisplayValidationCheck()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Runs the display validation check for the radar
|
||||||
Citizen.CreateThread( function()
|
Citizen.CreateThread( function()
|
||||||
Citizen.Wait( 100 )
|
Citizen.Wait( 100 )
|
||||||
|
|
||||||
while ( true ) do
|
while ( true ) do
|
||||||
|
-- Run the check
|
||||||
RADAR:RunDisplayValidationCheck()
|
RADAR:RunDisplayValidationCheck()
|
||||||
|
|
||||||
|
-- Wait half a second
|
||||||
Citizen.Wait( 500 )
|
Citizen.Wait( 500 )
|
||||||
end
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
-- Update the vehicle pool every 3 seconds
|
-- Update the vehicle pool every 3 seconds
|
||||||
function RADAR:UpdateVehiclePool()
|
function RADAR:UpdateVehiclePool()
|
||||||
|
-- Only update the vehicle pool if we need to
|
||||||
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
|
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
|
||||||
|
-- Get the active vehicle set
|
||||||
local vehs = self:GetAllVehicles()
|
local vehs = self:GetAllVehicles()
|
||||||
|
|
||||||
|
-- Update the vehicle pool
|
||||||
self:SetVehiclePool( vehs )
|
self:SetVehiclePool( vehs )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Runs the vehicle pool updater
|
||||||
Citizen.CreateThread( function()
|
Citizen.CreateThread( function()
|
||||||
while ( true ) do
|
while ( true ) do
|
||||||
|
-- Update the vehicle pool
|
||||||
RADAR:UpdateVehiclePool()
|
RADAR:UpdateVehiclePool()
|
||||||
|
|
||||||
|
-- Wait 3 seconds
|
||||||
Citizen.Wait( 3000 )
|
Citizen.Wait( 3000 )
|
||||||
end
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
function RunControlManager()
|
function RunControlManager()
|
||||||
if ( not RADAR:GetKeyLockState() ) then
|
if ( not RADAR:GetKeyLockState() ) then
|
||||||
-- Opens the remote control
|
-- Opens the remote control
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.remote_control_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.remote_control_key ) ) then
|
||||||
RADAR:OpenRemote()
|
RADAR:OpenRemote()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Locks speed from front antenna
|
-- Locks speed from front antenna
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.front_lock_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.front_lock_key ) ) then
|
||||||
RADAR:LockAntennaSpeed( "front" )
|
RADAR:LockAntennaSpeed( "front" )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Locks speed from rear antenna
|
-- Locks speed from rear antenna
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.rear_lock_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.rear_lock_key ) ) then
|
||||||
RADAR:LockAntennaSpeed( "rear" )
|
RADAR:LockAntennaSpeed( "rear" )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Locks front plate reader
|
-- Locks front plate reader
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.plate_front_lock_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.plate_front_lock_key ) ) then
|
||||||
READER:LockCam( "front" )
|
READER:LockCam( "front" )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Locks front plate reader
|
-- Locks front plate reader
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.plate_rear_lock_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.plate_rear_lock_key ) ) then
|
||||||
READER:LockCam( "rear" )
|
READER:LockCam( "rear" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Toggles the key lock state
|
-- Toggles the key lock state
|
||||||
if ( IsDisabledControlJustPressed( 1, CONFIG.key_lock_key ) ) then
|
if ( IsDisabledControlJustPressed( 1, CONFIG.key_lock_key ) ) then
|
||||||
RADAR:ToggleKeyLock()
|
RADAR:ToggleKeyLock()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Shortcut to restart the resource
|
-- Shortcut to restart the resource
|
||||||
if ( IsDisabledControlJustPressed( 1, 167 ) ) then
|
--[[ if ( IsDisabledControlJustPressed( 1, 167 ) ) then
|
||||||
ExecuteCommand( "restart wk_wars2x" )
|
ExecuteCommand( "restart wk_wars2x" )
|
||||||
end
|
end ]]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Control manager
|
-- Control manager
|
||||||
|
|||||||
42
cl_utils.lua
42
cl_utils.lua
@@ -7,33 +7,45 @@
|
|||||||
|
|
||||||
UTIL = {}
|
UTIL = {}
|
||||||
|
|
||||||
|
-- Returns a number to a set number of decimal places
|
||||||
function UTIL:Round( num, numDecimalPlaces )
|
function UTIL:Round( num, numDecimalPlaces )
|
||||||
return tonumber( string.format( "%." .. ( numDecimalPlaces or 0 ) .. "f", num ) )
|
return tonumber( string.format( "%." .. ( numDecimalPlaces or 0 ) .. "f", num ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- The custom font used for the digital displays have the ¦ symbol as an empty character, this function
|
||||||
|
-- takes a speed and returns a formatted speed that can be displayed on the radar
|
||||||
function UTIL:FormatSpeed( speed )
|
function UTIL:FormatSpeed( speed )
|
||||||
|
-- Return "Err" (Error) if the given speed is outside the 0-999 range
|
||||||
if ( speed < 0 or speed > 999 ) then return "Err" end
|
if ( speed < 0 or speed > 999 ) then return "Err" end
|
||||||
|
|
||||||
|
-- Convert the speed to a string
|
||||||
local text = tostring( speed )
|
local text = tostring( speed )
|
||||||
local pipes = ""
|
local pipes = ""
|
||||||
|
|
||||||
|
-- Create a string of pipes (¦) for the number of spaces
|
||||||
for i = 1, 3 - string.len( text ) do
|
for i = 1, 3 - string.len( text ) do
|
||||||
pipes = pipes .. "¦"
|
pipes = pipes .. "¦"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Return the formatted speed
|
||||||
return pipes .. text
|
return pipes .. text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns a clamped numerical value based on the given parameters
|
||||||
function UTIL:Clamp( val, min, max )
|
function UTIL:Clamp( val, min, max )
|
||||||
|
-- Return the min value if the given value is less than the min
|
||||||
if ( val < min ) then
|
if ( val < min ) then
|
||||||
return min
|
return min
|
||||||
|
-- Return the max value if the given value is larger than the max
|
||||||
elseif ( val > max ) then
|
elseif ( val > max ) then
|
||||||
return max
|
return max
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Return the given value if it's between the min and max
|
||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns if the given table is empty, includes numerical and non-numerical key values
|
||||||
function UTIL:IsTableEmpty( t )
|
function UTIL:IsTableEmpty( t )
|
||||||
local c = 0
|
local c = 0
|
||||||
|
|
||||||
@@ -52,12 +64,15 @@ function UTIL:Values( xs )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Old ray trace function for getting a vehicle in a specific direction from a start point
|
||||||
function UTIL:GetVehicleInDirection( entFrom, coordFrom, coordTo )
|
function UTIL:GetVehicleInDirection( entFrom, coordFrom, coordTo )
|
||||||
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 5.0, 10, entFrom, 7 )
|
local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 8.0, 10, entFrom, 7 )
|
||||||
local _, hitEntity, endCoords, surfaceNormal, vehicle = GetShapeTestResult( rayHandle )
|
local _, _, _, _, vehicle = GetShapeTestResult( rayHandle )
|
||||||
return vehicle
|
return vehicle
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns if a target vehicle is coming towards or going away from the patrol vehicle, it has a range
|
||||||
|
-- so if a vehicle is sideways compared to the patrol vehicle, the directional arrows won't light up
|
||||||
function UTIL:GetEntityRelativeDirection( myAng, tarAng )
|
function UTIL:GetEntityRelativeDirection( myAng, tarAng )
|
||||||
local angleDiff = math.abs( ( myAng - tarAng + 180 ) % 360 - 180 )
|
local angleDiff = math.abs( ( myAng - tarAng + 180 ) % 360 - 180 )
|
||||||
|
|
||||||
@@ -70,6 +85,7 @@ function UTIL:GetEntityRelativeDirection( myAng, tarAng )
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Your everyday GTA notification function
|
||||||
function UTIL:Notify( text )
|
function UTIL:Notify( text )
|
||||||
SetNotificationTextEntry( "STRING" )
|
SetNotificationTextEntry( "STRING" )
|
||||||
AddTextComponentSubstringPlayerName( text )
|
AddTextComponentSubstringPlayerName( text )
|
||||||
@@ -91,28 +107,6 @@ function UTIL:DrawDebugText( x, y, scale, centre, text )
|
|||||||
DrawText( x, y )
|
DrawText( x, y )
|
||||||
end
|
end
|
||||||
|
|
||||||
function UTIL:DrawDebugSphere( x, y, z, r, col )
|
|
||||||
if ( 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 ( 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
|
|
||||||
|
|
||||||
function UTIL:DebugPrint( text )
|
|
||||||
if ( CONFIG.debug_mode ) then
|
|
||||||
print( text )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[The MIT License (MIT)
|
--[[The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2017 IllidanS4
|
Copyright (c) 2017 IllidanS4
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
-- Do not touch this
|
-- Do not touch this
|
||||||
CONFIG = {}
|
CONFIG = {}
|
||||||
|
|
||||||
-- Radar Control Panel key
|
-- Remote control key
|
||||||
-- The default key to open the radar control panel is 166 (F5 - INPUT_SELECT_CHARACTER_MICHAEL)
|
-- The default key to open the remote control is 166 (F5 - INPUT_SELECT_CHARACTER_MICHAEL)
|
||||||
CONFIG.remote_control_key = 166
|
CONFIG.remote_control_key = 166
|
||||||
|
|
||||||
-- Radar front antenna lock/unlock Key
|
-- Radar front antenna lock/unlock Key
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ button:focus { outline: none; }
|
|||||||
width: 675px;
|
width: 675px;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
|
||||||
/* Temp centre */
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -160,8 +159,6 @@ button:focus { outline: none; }
|
|||||||
grid-template-columns: 45px 50px 150px 35px 50px 135px 35px 135px;
|
grid-template-columns: 45px 50px 150px 35px 50px 135px 35px 135px;
|
||||||
gap: 0 0;
|
gap: 0 0;
|
||||||
|
|
||||||
/* z-index: 2; */
|
|
||||||
|
|
||||||
box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 );
|
box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 );
|
||||||
}
|
}
|
||||||
#radar .label {
|
#radar .label {
|
||||||
@@ -194,7 +191,6 @@ button:focus { outline: none; }
|
|||||||
background: linear-gradient( to bottom, rgba( 230, 230, 230, 0.8 ), rgb( 40, 168, 40 ) 10%, rgb( 0, 134, 0 ) );
|
background: linear-gradient( to bottom, rgba( 230, 230, 230, 0.8 ), rgb( 40, 168, 40 ) 10%, rgb( 0, 134, 0 ) );
|
||||||
box-shadow: 0px 0px 3px 0px rgb( 80, 80, 80 );
|
box-shadow: 0px 0px 3px 0px rgb( 80, 80, 80 );
|
||||||
text-align: center;
|
text-align: center;
|
||||||
/* font-family: 'Heebo-Regular'; */
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: rgb( 34, 34, 34 );
|
color: rgb( 34, 34, 34 );
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
@@ -372,20 +368,13 @@ button:focus { outline: none; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
#rc {
|
#rc {
|
||||||
/* width: 275px;
|
|
||||||
height: 750px; */
|
|
||||||
width: 315px;
|
width: 315px;
|
||||||
height: 800px;
|
height: 800px;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0; */
|
|
||||||
top: calc( 50% - ( 800px / 2 ) );
|
top: calc( 50% - ( 800px / 2 ) );
|
||||||
left: calc( 50% - ( 315px / 2 ) );
|
left: calc( 50% - ( 315px / 2 ) );
|
||||||
margin: auto;
|
margin: auto;
|
||||||
/* padding-top: 25px; */
|
|
||||||
padding: 65px 30px 50px 30px;
|
padding: 65px 30px 50px 30px;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -394,12 +383,9 @@ button:focus { outline: none; }
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
color: white;
|
color: white;
|
||||||
/* background-color: rgb( 50, 50, 50 ); */
|
|
||||||
background-image: url( "images/rc_bg.png" );
|
background-image: url( "images/rc_bg.png" );
|
||||||
|
|
||||||
transition: transform 0.5s;
|
transition: transform 0.5s;
|
||||||
|
|
||||||
/* clip-path: polygon( 5% 0, 95% 0, 100% 25%, 90% 100%, 10% 100%, 0 25% ); */
|
|
||||||
|
|
||||||
/* Settings for scaling */
|
/* Settings for scaling */
|
||||||
transform: scale( 1.0 );
|
transform: scale( 1.0 );
|
||||||
@@ -414,8 +400,6 @@ button:focus { outline: none; }
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
background-color: rgb( 200, 200, 200 );
|
background-color: rgb( 200, 200, 200 );
|
||||||
|
|
||||||
/* font-family: 'Heebo-Regular'; */
|
|
||||||
|
|
||||||
box-shadow: 2px 3px rgb( 100, 100, 100 );
|
box-shadow: 2px 3px rgb( 100, 100, 100 );
|
||||||
}
|
}
|
||||||
@@ -495,10 +479,8 @@ button:focus { outline: none; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
#rc .label {
|
#rc .label {
|
||||||
/* font-family: 'Heebo-Regular'; */
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
/* margin: 5px 0; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#rc .antenna_btns_container {
|
#rc .antenna_btns_container {
|
||||||
@@ -625,9 +607,6 @@ button:focus { outline: none; }
|
|||||||
transform: scale( 1.0 );
|
transform: scale( 1.0 );
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
|
|
||||||
/* background-color: rgb(70, 70, 70);
|
|
||||||
box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 ); */
|
|
||||||
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
#plateReaderFrame .frame_border {
|
#plateReaderFrame .frame_border {
|
||||||
@@ -644,8 +623,6 @@ button:focus { outline: none; }
|
|||||||
background-color: rgb( 20, 22, 18 );
|
background-color: rgb( 20, 22, 18 );
|
||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
/* clip-path: polygon( 20px 2px, 665px 2px, 682px 30%, 682px 70%, 665px 208px, 20px 208px, 3px 70%, 3px 30% ); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#plateReader {
|
#plateReader {
|
||||||
@@ -721,7 +698,6 @@ button:focus { outline: none; }
|
|||||||
font-size: 58px;
|
font-size: 58px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
letter-spacing: -3px;
|
letter-spacing: -3px;
|
||||||
/* color: rgb(0, 0, 163); */
|
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
@@ -754,11 +730,9 @@ button:focus { outline: none; }
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
/* background-color: rgb( 50, 54, 45 ); */
|
|
||||||
background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) );
|
background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) );
|
||||||
border: 3px solid rgb( 0, 0, 0 );
|
border: 3px solid rgb( 0, 0, 0 );
|
||||||
|
|
||||||
/* for testing */
|
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
#plateReaderBox .title {
|
#plateReaderBox .title {
|
||||||
@@ -805,10 +779,10 @@ button:focus { outline: none; }
|
|||||||
font-family: "Plate-Font";
|
font-family: "Plate-Font";
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 38px;
|
font-size: 38px;
|
||||||
|
text-transform: uppercase;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
margin-bottom: -15px;
|
margin-bottom: -15px;
|
||||||
/* border: 3px solid rgb( 0, 0, 0 ); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#plateReaderBox .close {
|
#plateReaderBox .close {
|
||||||
@@ -843,9 +817,8 @@ button:focus { outline: none; }
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
/* background-color: rgb( 50, 54, 45 ); */
|
|
||||||
background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) );
|
background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) );
|
||||||
border: 3px solid rgb( 0, 0, 0 );
|
border: 3px solid rgb( 0, 0, 0 );
|
||||||
|
|
||||||
@@ -872,10 +845,6 @@ button:focus { outline: none; }
|
|||||||
|
|
||||||
#uiSettingsBox .scaling {
|
#uiSettingsBox .scaling {
|
||||||
height: 70px;
|
height: 70px;
|
||||||
|
|
||||||
/* display: flex;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
align-items: center; */
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 2fr 1fr;
|
grid-template-columns: 1fr 2fr 1fr;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<div class="label label_top">FRONT ANTENNA</div>
|
<div class="label label_top">FRONT ANTENNA</div>
|
||||||
|
|
||||||
<div class="pwr_button_container">
|
<div class="pwr_button_container">
|
||||||
<div id="pwrBtn" class="pwr_button">PWR</div>
|
<div id="pwrBtn" data-nuitype="togglePower" class="pwr_button">PWR</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modes_container">
|
<div class="modes_container">
|
||||||
|
|||||||
143
nui/radar.js
143
nui/radar.js
@@ -14,6 +14,7 @@
|
|||||||
var resourceName;
|
var resourceName;
|
||||||
var uiEdited = false;
|
var uiEdited = false;
|
||||||
|
|
||||||
|
// All of the audio file names
|
||||||
const audioNames =
|
const audioNames =
|
||||||
{
|
{
|
||||||
// Beeps
|
// Beeps
|
||||||
@@ -29,6 +30,7 @@ const audioNames =
|
|||||||
away: "away.ogg"
|
away: "away.ogg"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines which audio needs to play for which direction
|
||||||
const lockAudio =
|
const lockAudio =
|
||||||
{
|
{
|
||||||
front: {
|
front: {
|
||||||
@@ -50,7 +52,6 @@ const elements =
|
|||||||
remote: $( "#rc" ),
|
remote: $( "#rc" ),
|
||||||
plateReader: $( "#plateReaderFrame" ),
|
plateReader: $( "#plateReaderFrame" ),
|
||||||
|
|
||||||
// toggleDisplay: $( "#toggleDisplay" ),
|
|
||||||
pwrBtn: $( "#pwrBtn" ),
|
pwrBtn: $( "#pwrBtn" ),
|
||||||
|
|
||||||
uiSettingsBtn: $( "#uiSettings" ),
|
uiSettingsBtn: $( "#uiSettings" ),
|
||||||
@@ -163,6 +164,7 @@ const elements =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Antenna mode values
|
||||||
const modes =
|
const modes =
|
||||||
{
|
{
|
||||||
off: 0,
|
off: 0,
|
||||||
@@ -171,6 +173,7 @@ const modes =
|
|||||||
both: 3
|
both: 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Antenna direction values
|
||||||
const dirs =
|
const dirs =
|
||||||
{
|
{
|
||||||
none: 0,
|
none: 0,
|
||||||
@@ -190,45 +193,45 @@ elements.uiSettingsBox.hide();
|
|||||||
elements.keyLock.label.hide();
|
elements.keyLock.label.hide();
|
||||||
elements.helpWindow.hide();
|
elements.helpWindow.hide();
|
||||||
|
|
||||||
|
// Sets the action for the "UI SETTINGS" button on the remote to open the UI settings box
|
||||||
elements.uiSettingsBtn.click( function() {
|
elements.uiSettingsBtn.click( function() {
|
||||||
setEleVisible( elements.uiSettingsBox, true );
|
setEleVisible( elements.uiSettingsBox, true );
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
// Sets the action for the "PLATE READER" button on the remote to open the plate reader box
|
||||||
elements.plateReaderBtn.click( function() {
|
elements.plateReaderBtn.click( function() {
|
||||||
setEleVisible( elements.plateReaderBox, true );
|
setEleVisible( elements.plateReaderBox, true );
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
// Sets the action for the "HELP" button on the remote to open the help window and load the web page
|
||||||
elements.openHelp.click( function() {
|
elements.openHelp.click( function() {
|
||||||
setEleVisible( elements.helpWindow, true );
|
setEleVisible( elements.helpWindow, true );
|
||||||
loadHelp( true );
|
loadHelp( true );
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
// Sets the action for the "Close Help" button under the help window to close the help window and unload the web page
|
||||||
elements.closeHelp.click( function() {
|
elements.closeHelp.click( function() {
|
||||||
setEleVisible( elements.helpWindow, false );
|
setEleVisible( elements.helpWindow, false );
|
||||||
loadHelp( false );
|
loadHelp( false );
|
||||||
} )
|
} )
|
||||||
|
|
||||||
elements.pwrBtn.click( function() {
|
|
||||||
togglePower();
|
|
||||||
} )
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Setters
|
Setters
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
|
// Sets the visibility of an element to the given state
|
||||||
function setEleVisible( ele, state )
|
function setEleVisible( ele, state )
|
||||||
{
|
{
|
||||||
state ? ele.fadeIn() : ele.fadeOut();
|
state ? ele.fadeIn() : ele.fadeOut();
|
||||||
|
|
||||||
if ( state ) {
|
|
||||||
ele.blur();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changes the class of the given element so it looks lit up
|
||||||
function setLight( ant, cat, item, state )
|
function setLight( ant, cat, item, state )
|
||||||
{
|
{
|
||||||
|
// Grab the obj element from the elements table
|
||||||
let obj = elements.antennas[ant][cat][item];
|
let obj = elements.antennas[ant][cat][item];
|
||||||
|
|
||||||
|
// Either add the active class or remove it
|
||||||
if ( state ) {
|
if ( state ) {
|
||||||
obj.addClass( cat == "dirs" ? "active_arrow" : "active" );
|
obj.addClass( cat == "dirs" ? "active_arrow" : "active" );
|
||||||
} else {
|
} else {
|
||||||
@@ -236,48 +239,72 @@ function setLight( ant, cat, item, state )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the XMIT state of an antenna based on the passed state, makes the fast box display "HLd"
|
||||||
|
// when the state is false
|
||||||
function setAntennaXmit( ant, state )
|
function setAntennaXmit( ant, state )
|
||||||
{
|
{
|
||||||
|
// Set the light state of the antenna's XMIT icon
|
||||||
setLight( ant, "modes", "xmit", state );
|
setLight( ant, "modes", "xmit", state );
|
||||||
|
|
||||||
|
// Clear the antenna's directional arrows and speeds, display "HLd" in the fast box
|
||||||
if ( !state ) {
|
if ( !state ) {
|
||||||
clearDirs( ant );
|
clearDirs( ant );
|
||||||
elements.antennas[ant].targetSpeed.html( "¦¦¦" );
|
elements.antennas[ant].targetSpeed.html( "¦¦¦" );
|
||||||
elements.antennas[ant].fastSpeed.html( "HLd" );
|
elements.antennas[ant].fastSpeed.html( "HLd" );
|
||||||
|
|
||||||
|
// Blank the fast box when the antenna is set to transmit
|
||||||
} else {
|
} else {
|
||||||
elements.antennas[ant].fastSpeed.html( "¦¦¦" );
|
elements.antennas[ant].fastSpeed.html( "¦¦¦" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the mode lights for the given antenna
|
||||||
function setAntennaMode( ant, mode )
|
function setAntennaMode( ant, mode )
|
||||||
{
|
{
|
||||||
setLight( ant, "modes", "same", mode == modes.same );
|
// Light up the 'same' led if the given mode is the same mode, otherwise blank it
|
||||||
|
setLight( ant, "modes", "same", mode == modes.same );
|
||||||
|
|
||||||
|
// Light up the 'opp' led if the given mode is the opp mode, otherwise blank it
|
||||||
setLight( ant, "modes", "opp", mode == modes.opp );
|
setLight( ant, "modes", "opp", mode == modes.opp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the fast light for the given antenna
|
||||||
function setAntennaFastMode( ant, state )
|
function setAntennaFastMode( ant, state )
|
||||||
{
|
{
|
||||||
|
// Lighten or dull the fast led based on the given state
|
||||||
setLight( ant, "fast", "fastLabel", state );
|
setLight( ant, "fast", "fastLabel", state );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the lock light for the given antenna
|
||||||
function setAntennaLock( ant, state )
|
function setAntennaLock( ant, state )
|
||||||
{
|
{
|
||||||
|
// Lighten or dull the lock led based on the given state
|
||||||
setLight( ant, "fast", "lockLabel", state );
|
setLight( ant, "fast", "lockLabel", state );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the directional arrows light for the given antenna
|
||||||
function setAntennaDirs( ant, dir, fastDir )
|
function setAntennaDirs( ant, dir, fastDir )
|
||||||
{
|
{
|
||||||
setLight( ant, "dirs", "fwd", dir == dirs.closing );
|
// Target forward
|
||||||
|
setLight( ant, "dirs", "fwd", dir == dirs.closing );
|
||||||
|
|
||||||
|
// Target backward
|
||||||
setLight( ant, "dirs", "bwd", dir == dirs.away );
|
setLight( ant, "dirs", "bwd", dir == dirs.away );
|
||||||
|
|
||||||
setLight( ant, "dirs", "fwdFast", fastDir == dirs.closing );
|
// Fast forward
|
||||||
|
setLight( ant, "dirs", "fwdFast", fastDir == dirs.closing );
|
||||||
|
|
||||||
|
// Fast backward
|
||||||
setLight( ant, "dirs", "bwdFast", fastDir == dirs.away );
|
setLight( ant, "dirs", "bwdFast", fastDir == dirs.away );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sets the plate lock light for the given plate reader
|
||||||
function setPlateLock( cam, state )
|
function setPlateLock( cam, state )
|
||||||
{
|
{
|
||||||
|
// Get the plate reader lock object
|
||||||
let obj = elements.plates[cam].lock;
|
let obj = elements.plates[cam].lock;
|
||||||
|
|
||||||
|
// Add or remove the active class
|
||||||
if ( state ) {
|
if ( state ) {
|
||||||
obj.addClass( "active" );
|
obj.addClass( "active" );
|
||||||
} else {
|
} else {
|
||||||
@@ -285,6 +312,7 @@ function setPlateLock( cam, state )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the license text and plate image of the given plate reader
|
||||||
function setPlate( cam, plate, index )
|
function setPlate( cam, plate, index )
|
||||||
{
|
{
|
||||||
// Get the plate items
|
// Get the plate items
|
||||||
@@ -309,40 +337,55 @@ function setPlate( cam, plate, index )
|
|||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Clearing functions
|
Clearing functions
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
|
// Clears the same, opp, fast, and lock leds for the given antenna
|
||||||
function clearModes( ant )
|
function clearModes( ant )
|
||||||
{
|
{
|
||||||
|
// Iterate through the modes and clear them
|
||||||
for ( let i in elements.antennas[ant].modes )
|
for ( let i in elements.antennas[ant].modes )
|
||||||
{
|
{
|
||||||
elements.antennas[ant].modes[i].removeClass( "active" );
|
elements.antennas[ant].modes[i].removeClass( "active" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate through the fast leds and clear them
|
||||||
for ( let a in elements.antennas[ant].fast )
|
for ( let a in elements.antennas[ant].fast )
|
||||||
{
|
{
|
||||||
elements.antennas[ant].fast[a].removeClass( "active" );
|
elements.antennas[ant].fast[a].removeClass( "active" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clears the directional arrows for the given antenna
|
||||||
function clearDirs( ant )
|
function clearDirs( ant )
|
||||||
{
|
{
|
||||||
|
// Iterate through the directional arrows and clear them
|
||||||
for ( let i in elements.antennas[ant].dirs )
|
for ( let i in elements.antennas[ant].dirs )
|
||||||
{
|
{
|
||||||
elements.antennas[ant].dirs[i].removeClass( "active_arrow" );
|
elements.antennas[ant].dirs[i].removeClass( "active_arrow" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clears all of the elements of the given antenna
|
||||||
function clearAntenna( ant )
|
function clearAntenna( ant )
|
||||||
{
|
{
|
||||||
clearModes( ant );
|
// Clear the modes
|
||||||
|
clearModes( ant );
|
||||||
|
|
||||||
|
// Clear the directional arrows
|
||||||
clearDirs( ant );
|
clearDirs( ant );
|
||||||
|
|
||||||
elements.antennas[ant].targetSpeed.html( "¦¦¦" );
|
// Blank the target speed box
|
||||||
|
elements.antennas[ant].targetSpeed.html( "¦¦¦" );
|
||||||
|
|
||||||
|
// Blank the fast speed box
|
||||||
elements.antennas[ant].fastSpeed.html( "¦¦¦" );
|
elements.antennas[ant].fastSpeed.html( "¦¦¦" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clears all the elements on the radar's UI
|
||||||
function clearEverything()
|
function clearEverything()
|
||||||
{
|
{
|
||||||
|
// Blank the patrol speed
|
||||||
elements.patrolSpeed.html( "¦¦¦" );
|
elements.patrolSpeed.html( "¦¦¦" );
|
||||||
|
|
||||||
|
// Blank both the antennas
|
||||||
for ( let i in elements.antennas )
|
for ( let i in elements.antennas )
|
||||||
{
|
{
|
||||||
clearAntenna( i );
|
clearAntenna( i );
|
||||||
@@ -353,24 +396,26 @@ function clearEverything()
|
|||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Radar power functions
|
Radar power functions
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
function togglePower()
|
// Simulates the radar unit powering up by lighting all of the elements
|
||||||
{
|
|
||||||
sendData( "togglePower", null );
|
|
||||||
}
|
|
||||||
|
|
||||||
function poweringUp()
|
function poweringUp()
|
||||||
{
|
{
|
||||||
|
// Set the patrol speed container to be fully lit
|
||||||
elements.patrolSpeed.html( "888" );
|
elements.patrolSpeed.html( "888" );
|
||||||
|
|
||||||
|
// Iterate through the front and rear antenna elements
|
||||||
for ( let i of [ "front", "rear" ] )
|
for ( let i of [ "front", "rear" ] )
|
||||||
{
|
{
|
||||||
|
// Get the antenna object to shorten the target reference
|
||||||
let e = elements.antennas[i];
|
let e = elements.antennas[i];
|
||||||
|
|
||||||
|
// Set the target and fast speed box to be fully lit
|
||||||
e.targetSpeed.html( "888" );
|
e.targetSpeed.html( "888" );
|
||||||
e.fastSpeed.html( "888" );
|
e.fastSpeed.html( "888" );
|
||||||
|
|
||||||
|
// Iterate through the rest of the antenna's elements
|
||||||
for ( let a of [ "dirs", "modes", "fast" ] )
|
for ( let a of [ "dirs", "modes", "fast" ] )
|
||||||
{
|
{
|
||||||
|
// Iterate through the objects for the current category and add the active class
|
||||||
for ( let obj in e[a] )
|
for ( let obj in e[a] )
|
||||||
{
|
{
|
||||||
a == "dirs" ? e[a][obj].addClass( "active_arrow" ) : e[a][obj].addClass( "active" );
|
a == "dirs" ? e[a][obj].addClass( "active_arrow" ) : e[a][obj].addClass( "active" );
|
||||||
@@ -379,17 +424,23 @@ function poweringUp()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simulates the 'fully powered' state of the radar unit
|
||||||
function poweredUp()
|
function poweredUp()
|
||||||
{
|
{
|
||||||
|
// Completely clear everything
|
||||||
clearEverything();
|
clearEverything();
|
||||||
|
|
||||||
|
// Activate the 'fast' led for both antennas, and make sure the xmit led is off
|
||||||
for ( let ant of [ "front", "rear" ] )
|
for ( let ant of [ "front", "rear" ] )
|
||||||
{
|
{
|
||||||
|
// Even though the clearEverything() function is called above, we run this so the fast window
|
||||||
|
// displays 'HLd'
|
||||||
setAntennaXmit( ant, false );
|
setAntennaXmit( ant, false );
|
||||||
setAntennaFastMode( ant, true );
|
setAntennaFastMode( ant, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs the startup process or clears everything, the Lua side calls for the full powered up state
|
||||||
function radarPower( state )
|
function radarPower( state )
|
||||||
{
|
{
|
||||||
state ? poweringUp() : clearEverything();
|
state ? poweringUp() : clearEverything();
|
||||||
@@ -399,17 +450,26 @@ function radarPower( state )
|
|||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Audio
|
Audio
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
|
// Plays the given audio file name from the audioNames list at the given volume
|
||||||
function playAudio( name, vol )
|
function playAudio( name, vol )
|
||||||
{
|
{
|
||||||
let audio = new Audio( "sounds/" + audioNames[name] );
|
// Create the new audio object
|
||||||
audio.volume = vol;
|
let audio = new Audio( "sounds/" + audioNames[name] );
|
||||||
|
|
||||||
|
// Set the volume
|
||||||
|
audio.volume = vol;
|
||||||
|
|
||||||
|
// Play the audio clip
|
||||||
audio.play();
|
audio.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plays the verbal lock, this is a separate from the function above as it plays two sounds with a delay
|
||||||
function playLockAudio( ant, dir, vol )
|
function playLockAudio( ant, dir, vol )
|
||||||
{
|
{
|
||||||
|
// Play the front/rear sound
|
||||||
playAudio( ant, vol );
|
playAudio( ant, vol );
|
||||||
|
|
||||||
|
// If the vehicle was closing or away, play that sound too
|
||||||
if ( dir > 0 )
|
if ( dir > 0 )
|
||||||
{
|
{
|
||||||
setTimeout( function() {
|
setTimeout( function() {
|
||||||
@@ -422,23 +482,31 @@ function playLockAudio( ant, dir, vol )
|
|||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Radar updating
|
Radar updating
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
|
// Updates patrol speed as well as the speeds and directional arrows for the given antenna
|
||||||
function updateDisplays( ps, ants )
|
function updateDisplays( ps, ants )
|
||||||
{
|
{
|
||||||
|
// Update the patrol speed
|
||||||
elements.patrolSpeed.html( ps );
|
elements.patrolSpeed.html( ps );
|
||||||
|
|
||||||
|
// Iterate through the antenna data
|
||||||
for ( let ant in ants )
|
for ( let ant in ants )
|
||||||
{
|
{
|
||||||
|
// Make sure there is actually data for the current antenna data
|
||||||
if ( ants[ant] != null ) {
|
if ( ants[ant] != null ) {
|
||||||
|
// Grab the antenna element from the elements table
|
||||||
let e = elements.antennas[ant];
|
let e = elements.antennas[ant];
|
||||||
|
|
||||||
|
// Update the target and fast speeds
|
||||||
e.targetSpeed.html( ants[ant][0].speed );
|
e.targetSpeed.html( ants[ant][0].speed );
|
||||||
e.fastSpeed.html( ants[ant][1].speed );
|
e.fastSpeed.html( ants[ant][1].speed );
|
||||||
|
|
||||||
|
// Update the directional arrows
|
||||||
setAntennaDirs( ant, ants[ant][0].dir, ants[ant][1].dir );
|
setAntennaDirs( ant, ants[ant][0].dir, ants[ant][1].dir );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates all of the mode leds on the radar interface
|
||||||
function settingUpdate( ants )
|
function settingUpdate( ants )
|
||||||
{
|
{
|
||||||
for ( let ant in ants )
|
for ( let ant in ants )
|
||||||
@@ -454,22 +522,30 @@ function settingUpdate( ants )
|
|||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
Misc
|
Misc
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
|
// Displays the given option text and current option value on the radar
|
||||||
function menu( optionText, option )
|
function menu( optionText, option )
|
||||||
{
|
{
|
||||||
|
// Clear everything
|
||||||
clearEverything();
|
clearEverything();
|
||||||
|
|
||||||
|
// Set the target and fast box to the option text
|
||||||
elements.antennas.front.targetSpeed.html( optionText[0] );
|
elements.antennas.front.targetSpeed.html( optionText[0] );
|
||||||
elements.antennas.front.fastSpeed.html( optionText[1] );
|
elements.antennas.front.fastSpeed.html( optionText[1] );
|
||||||
|
|
||||||
|
// Set the patrol speed to the value
|
||||||
elements.patrolSpeed.html( option );
|
elements.patrolSpeed.html( option );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes the key lock label fade in then fade out after 2 seconds
|
||||||
function displayKeyLock( state )
|
function displayKeyLock( state )
|
||||||
{
|
{
|
||||||
|
// Set the state label text to enabled or disabled
|
||||||
elements.keyLock.stateLabel.html( state ? "enabled" : "disabled" );
|
elements.keyLock.stateLabel.html( state ? "enabled" : "disabled" );
|
||||||
|
|
||||||
|
// Fade in the label
|
||||||
elements.keyLock.label.fadeIn();
|
elements.keyLock.label.fadeIn();
|
||||||
|
|
||||||
|
// Make the label fade out after 2 seconds
|
||||||
setTimeout( function() {
|
setTimeout( function() {
|
||||||
elements.keyLock.label.fadeOut();
|
elements.keyLock.label.fadeOut();
|
||||||
}, 2000 );
|
}, 2000 );
|
||||||
@@ -484,18 +560,22 @@ function sendData( name, data ) {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the ui edited variable to the given state, this is used in the UI save system
|
||||||
function setUiHasBeenEdited( state )
|
function setUiHasBeenEdited( state )
|
||||||
{
|
{
|
||||||
uiEdited = state;
|
uiEdited = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns if the UI has been edited
|
||||||
function hasUiBeenEdited()
|
function hasUiBeenEdited()
|
||||||
{
|
{
|
||||||
return uiEdited;
|
return uiEdited;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gathers the UI data and sends it to the Lua side
|
||||||
function sendSaveData()
|
function sendSaveData()
|
||||||
{
|
{
|
||||||
|
// Make sure we only collect and send the UI data if it has been edited
|
||||||
if ( hasUiBeenEdited() ) {
|
if ( hasUiBeenEdited() ) {
|
||||||
let data =
|
let data =
|
||||||
{
|
{
|
||||||
@@ -520,10 +600,12 @@ function sendSaveData()
|
|||||||
safezone: safezone
|
safezone: safezone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send the data
|
||||||
sendData( "saveUiData", data );
|
sendData( "saveUiData", data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loads the UI settings
|
||||||
function loadUiSettings( data )
|
function loadUiSettings( data )
|
||||||
{
|
{
|
||||||
// Iterate through "remote", "radar" and "plateReader"
|
// Iterate through "remote", "radar" and "plateReader"
|
||||||
@@ -550,20 +632,28 @@ function loadUiSettings( data )
|
|||||||
elements.safezoneSlider.trigger( "input" );
|
elements.safezoneSlider.trigger( "input" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the on click function for the set BOLO plate button
|
||||||
elements.setBoloBtn.click( function() {
|
elements.setBoloBtn.click( function() {
|
||||||
|
// Grab the value of the text input box
|
||||||
let plate = elements.boloText.val();
|
let plate = elements.boloText.val();
|
||||||
|
|
||||||
|
// Send the plate to the Lua side
|
||||||
sendData( "setBoloPlate", plate );
|
sendData( "setBoloPlate", plate );
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
// Checks what the user is typing into the plate box
|
||||||
function checkPlateInput( event )
|
function checkPlateInput( event )
|
||||||
{
|
{
|
||||||
let valid = /[A-Z0-9"?!£$%^&*()+\=\-_\[\]\{\};:'@#~,<.>/?|\\ ]/g.test( event.key );
|
// See if what has been typed is a valid key, GTA only seems to like A-Z and 0-9
|
||||||
|
let valid = /[a-zA-Z0-9 ]/g.test( event.key );
|
||||||
|
|
||||||
|
// If the key is not valid, prevent the key from being input into the box
|
||||||
if ( !valid ) {
|
if ( !valid ) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the src of the in-game help element, when true it loads the manual, when false it blanks the element
|
||||||
function loadHelp( state )
|
function loadHelp( state )
|
||||||
{
|
{
|
||||||
if ( state ) {
|
if ( state ) {
|
||||||
@@ -575,7 +665,10 @@ function loadHelp( state )
|
|||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------------
|
||||||
UI scaling and positioning
|
UI scaling and positioning
|
||||||
|
|
||||||
|
This whole bit could most likely be streamlined and made more efficient, it
|
||||||
|
works for now though. Redo it at a later date.
|
||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
var remoteScale = 1.0;
|
var remoteScale = 1.0;
|
||||||
var remoteMoving = false;
|
var remoteMoving = false;
|
||||||
@@ -794,7 +887,7 @@ function clamp( num, min, max )
|
|||||||
------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------*/
|
||||||
// This runs when the JS file is loaded, loops through all of the remote buttons and assigns them an onclick function
|
// This runs when the JS file is loaded, loops through all of the remote buttons and assigns them an onclick function
|
||||||
// elements.remote.find( "button" ).each( function( i, obj ) {
|
// elements.remote.find( "button" ).each( function( i, obj ) {
|
||||||
$( "body" ).find( "button" ).each( function( i, obj ) {
|
$( "body" ).find( "button, div" ).each( function( i, obj ) {
|
||||||
if ( $( this ).attr( "data-nuitype" ) ) {
|
if ( $( this ).attr( "data-nuitype" ) ) {
|
||||||
$( this ).click( function() {
|
$( this ).click( function() {
|
||||||
let type = $( this ).data( "nuitype" );
|
let type = $( this ).data( "nuitype" );
|
||||||
|
|||||||
159
sv_saving.lua
159
sv_saving.lua
@@ -21,117 +21,130 @@ DATASAVE.idType = "license"
|
|||||||
|
|
||||||
-- Saves the data for the given player into the saves folder within the resource
|
-- Saves the data for the given player into the saves folder within the resource
|
||||||
function DATASAVE:SavePlayerData( src, data )
|
function DATASAVE:SavePlayerData( src, data )
|
||||||
-- Get the player's identifier
|
-- Get the player's identifier
|
||||||
local id = self:GetIdentifier( src )
|
local id = self:GetIdentifier( src )
|
||||||
|
|
||||||
-- Save the JSON file into the saves folder
|
-- Save the JSON file into the saves folder
|
||||||
SaveResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json", json.encode( data ), -1 )
|
SaveResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json", json.encode( data ), -1 )
|
||||||
|
|
||||||
-- Print out a message in the console to say the player's UI data has been saved
|
-- Print out a message in the console to say the player's UI data has been saved
|
||||||
self:Print( "Saved UI data for " .. GetPlayerName( src ) .. " (ID: " .. src .. ")" )
|
self:Print( "Saved UI data for " .. GetPlayerName( src ) .. " (ID: " .. src .. ")" )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Attempts to retrieve the UI data for the given player
|
-- Attempts to retrieve the UI data for the given player
|
||||||
function DATASAVE:GetPlayerData( src )
|
function DATASAVE:GetPlayerData( src )
|
||||||
-- Get the player's identifier
|
-- Get the player's identifier
|
||||||
local id = self:GetIdentifier( src )
|
local id = self:GetIdentifier( src )
|
||||||
|
|
||||||
-- Try to grab the raw data from the player's JSON file
|
-- Try to grab the raw data from the player's JSON file
|
||||||
local rawData = LoadResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json" )
|
local rawData = LoadResourceFile( GetCurrentResourceName(), self.dir .. "/" .. id .. ".json" )
|
||||||
|
|
||||||
-- In the event there is no file for the player, return nil
|
-- In the event there is no file for the player, return nil
|
||||||
if ( rawData == nil ) then
|
if ( rawData == nil ) then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Decode the JSON data into a Lua table
|
-- Decode the JSON data into a Lua table
|
||||||
local data = json.decode( rawData )
|
local data = json.decode( rawData )
|
||||||
|
|
||||||
-- Return the data
|
-- Return the data
|
||||||
return data
|
return data
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Checks that the given data is valid, helps to stop modified data from being sent through the save system
|
-- Checks that the given data is valid, helps to stop modified data from being sent through the save system
|
||||||
function DATASAVE:CheckDataIsValid( data )
|
function DATASAVE:CheckDataIsValid( data )
|
||||||
-- First we check to make sure the data being passed is actually a table
|
-- First we check to make sure the data being passed is actually a table
|
||||||
if ( type( data ) ~= "table" ) then return false end
|
if ( type( data ) ~= "table" ) then return false end
|
||||||
|
|
||||||
-- Then we check to make sure that the data has only 3 elements, "remote", "radar", "reader" and "safezone"
|
-- Then we check to make sure that the data has only 3 elements, "remote", "radar", "reader" and "safezone"
|
||||||
local c = 0
|
local c = 0
|
||||||
for _ in pairs( data ) do c = c + 1 end
|
for _ in pairs( data ) do c = c + 1 end
|
||||||
|
|
||||||
-- If there isn't 4 elements, then the data isn't valid
|
-- If there isn't 4 elements, then the data isn't valid
|
||||||
if ( c ~= 4 ) then return false end
|
if ( c ~= 4 ) then return false end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Gets the identifier for the given player based on the identifier type specified at the top
|
-- Gets the identifier for the given player based on the identifier type specified at the top
|
||||||
function DATASAVE:GetIdentifier( src )
|
function DATASAVE:GetIdentifier( src )
|
||||||
-- Get the number of identifiers the player has
|
-- Get the number of identifiers the player has
|
||||||
local max = GetNumPlayerIdentifiers( src )
|
local max = GetNumPlayerIdentifiers( src )
|
||||||
|
|
||||||
-- Iterate through the identifier numerical range
|
-- Iterate through the identifier numerical range
|
||||||
for i = 0, max do
|
for i = 0, max do
|
||||||
-- Get the current identifier
|
-- Get the current identifier
|
||||||
local id = GetPlayerIdentifier( src, i )
|
local id = GetPlayerIdentifier( src, i )
|
||||||
|
|
||||||
-- In the event the identifier is nil, report it to the server console and return nil
|
-- In the event the identifier is nil, report it to the server console and return nil
|
||||||
if ( id == nil ) then
|
if ( id == nil ) then
|
||||||
self:Print( "^1It appears there was an error trying to find the specified ID (" .. self.idType .. ") for player " .. GetPlayerName( source ) )
|
self:Print( "^1It appears there was an error trying to find the specified ID (" .. self.idType .. ") for player " .. GetPlayerName( source ) )
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
-- If we find the identifier type set in DATASAVE.idType, then we have the identifier
|
||||||
if ( string.find( id, self.idType, 1 ) ) then
|
if ( string.find( id, self.idType, 1 ) ) then
|
||||||
local split = self:SplitString( id, ":" )
|
-- Split the identifier so we just get the actual identifier
|
||||||
return split[2]
|
local split = self:SplitString( id, ":" )
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
-- Return the identifier
|
||||||
|
return split[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In the event we get nothing, return nil
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Your typical split string function!
|
||||||
function DATASAVE:SplitString( inputstr, sep )
|
function DATASAVE:SplitString( inputstr, sep )
|
||||||
if ( sep == nil ) then
|
if ( sep == nil ) then
|
||||||
sep = "%s"
|
sep = "%s"
|
||||||
end
|
end
|
||||||
|
|
||||||
local t = {}
|
local t = {}
|
||||||
local i = 1
|
local i = 1
|
||||||
|
|
||||||
for str in string.gmatch( inputstr, "([^" .. sep .. "]+)" ) do
|
for str in string.gmatch( inputstr, "([^" .. sep .. "]+)" ) do
|
||||||
t[i] = str
|
t[i] = str
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Prints the given message with the resource name attached
|
||||||
function DATASAVE:Print( msg )
|
function DATASAVE:Print( msg )
|
||||||
print( "^3[wk_wars2x] ^0" .. msg .. "^0" )
|
print( "^3[wk_wars2x] ^0" .. msg .. "^0" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Serverside event for saving a player's UI data
|
||||||
RegisterServerEvent( "wk:saveUiData" )
|
RegisterServerEvent( "wk:saveUiData" )
|
||||||
AddEventHandler( "wk:saveUiData", function( data )
|
AddEventHandler( "wk:saveUiData", function( data )
|
||||||
-- Check to make sure that the data being sent by the client is valid
|
-- Check to make sure that the data being sent by the client is valid
|
||||||
local valid = DATASAVE:CheckDataIsValid( data )
|
local valid = DATASAVE:CheckDataIsValid( data )
|
||||||
|
|
||||||
-- Only proceed if the data is actually valid
|
-- Only proceed if the data is actually valid
|
||||||
if ( valid ) then
|
if ( valid ) then
|
||||||
DATASAVE:SavePlayerData( source, data )
|
DATASAVE:SavePlayerData( source, data )
|
||||||
else
|
else
|
||||||
DATASAVE:Print( "^1Save data being sent from " .. GetPlayerName( source ) .. " (ID: " .. source .. ") is not valid, either something went wrong, or the player has modified the data being sent." )
|
-- Print a message to the console saying the data sent by the client is not valid, this should rarely occur but it could be because
|
||||||
end
|
-- the client has modified the data being sent (mods/injections)
|
||||||
|
DATASAVE:Print( "^1Save data being sent from " .. GetPlayerName( source ) .. " (ID: " .. source .. ") is not valid, either something went wrong, or the player has modified the data being sent." )
|
||||||
|
end
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
-- Serverside event for when the player loads in and the system needs to get their saved UI data
|
||||||
RegisterServerEvent( "wk:getUiData" )
|
RegisterServerEvent( "wk:getUiData" )
|
||||||
AddEventHandler( "wk:getUiData", function()
|
AddEventHandler( "wk:getUiData", function()
|
||||||
local data = DATASAVE:GetPlayerData( source )
|
-- Try and get the player's data
|
||||||
|
local data = DATASAVE:GetPlayerData( source )
|
||||||
|
|
||||||
if ( data ) then
|
-- Send the client the data if we get any
|
||||||
TriggerClientEvent( "wk:loadUiData", source, data )
|
if ( data ) then
|
||||||
else
|
TriggerClientEvent( "wk:loadUiData", source, data )
|
||||||
DATASAVE:Print( "Player " .. GetPlayerName( source ) .. " (ID: " .. source .. ") doesn't have a UI settings file." )
|
else
|
||||||
end
|
-- When player's first use the radar, they won't have saved UI data
|
||||||
|
DATASAVE:Print( "Player " .. GetPlayerName( source ) .. " (ID: " .. source .. ") doesn't have a UI settings file." )
|
||||||
|
end
|
||||||
end )
|
end )
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
-----------------------------------------------------------------------]]--
|
-----------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
-- Branding!
|
||||||
local label =
|
local label =
|
||||||
[[
|
[[
|
||||||
//
|
//
|
||||||
@@ -13,25 +14,38 @@ local label =
|
|||||||
|| \ \ /\ / / __ __ _ _| |_| |__ / \ | |__) | (___ ) |\ V /
|
|| \ \ /\ / / __ __ _ _| |_| |__ / \ | |__) | (___ ) |\ V /
|
||||||
|| \ \/ \/ / '__/ _` | | __| '_ \ / /\ \ | _ / \___ \ / / > <
|
|| \ \/ \/ / '__/ _` | | __| '_ \ / /\ \ | _ / \___ \ / / > <
|
||||||
|| \ /\ /| | | (_| | | |_| | | | / ____ \| | \ \ ____) | / /_ / . \
|
|| \ /\ /| | | (_| | | |_| | | | / ____ \| | \ \ ____) | / /_ / . \
|
||||||
|| \/ \/ |_| \__,_|_|\__|_| |_| /_/ \_\_| \_\_____/ |____/_/ \_\]]
|
|| \/ \/ |_| \__,_|_|\__|_| |_| /_/ \_\_| \_\_____/ |____/_/ \_\
|
||||||
|
||]]
|
||||||
|
|
||||||
|
-- Returns the current version set in fxmanifest.lua
|
||||||
function GetCurrentVersion()
|
function GetCurrentVersion()
|
||||||
return GetResourceMetadata( GetCurrentResourceName(), "version" )
|
return GetResourceMetadata( GetCurrentResourceName(), "version" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Grabs the latest version number from the web GitHub
|
||||||
PerformHttpRequest( "https://wolfknight98.github.io/wk_wars2x_web/version.txt", function( err, text, headers )
|
PerformHttpRequest( "https://wolfknight98.github.io/wk_wars2x_web/version.txt", function( err, text, headers )
|
||||||
Citizen.Wait( 2000 )
|
-- Wait to reduce spam
|
||||||
|
Citizen.Wait( 2000 )
|
||||||
|
|
||||||
print( label )
|
-- Print the branding!
|
||||||
|
print( label )
|
||||||
|
|
||||||
|
-- Get the current resource version
|
||||||
local curVer = GetCurrentVersion()
|
local curVer = GetCurrentVersion()
|
||||||
|
|
||||||
print( " ||\n || Current version: " .. curVer )
|
if ( text ~= nil ) then
|
||||||
print( " || Latest version: " .. text .."\n ||" )
|
-- Print out the current and latest version
|
||||||
|
print( " || Current version: " .. curVer )
|
||||||
if ( text ~= curVer ) then
|
print( " || Latest version: " .. text .."\n ||" )
|
||||||
print( " || ^1Your Wraith ARS 2X version is outdated, visit the FiveM forum post to get the latest version.\n^0 \\\\\n" )
|
|
||||||
else
|
-- If the versions are different, print it out
|
||||||
print( " || ^2Wraith ARS 2X is up to date!\n^0 ||\n \\\\\n" )
|
if ( text ~= curVer ) then
|
||||||
end
|
print( " || ^1Your Wraith ARS 2X version is outdated, visit the FiveM forum post to get the latest version.\n^0 \\\\\n" )
|
||||||
|
else
|
||||||
|
print( " || ^2Wraith ARS 2X is up to date!\n^0 ||\n \\\\\n" )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- In case the version can not be requested, print out an error message
|
||||||
|
print( " || ^1There was an error getting the latest version information, if the issue persists contact WolfKnight#8586 on Discord.\n^0 ||\n \\\\\n" )
|
||||||
|
end
|
||||||
end )
|
end )
|
||||||
Reference in New Issue
Block a user