Merge pull request #16 from WolfKnight98/passenger-control

1.3.0 - Passenger control update
This commit is contained in:
Dan
2021-03-21 21:25:24 +00:00
committed by GitHub
16 changed files with 1979 additions and 1155 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
saves/*.json
.vscode/settings.json

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -27,13 +27,29 @@ All of the configuration for the Wraith ARS 2X is done inside the `config.lua` f
-- Radar fast limit locking
-- When enabled, the player will be able to define a fast limit within the radar's menu, when a vehicle
-- exceeds the fast limit, it will be locked into the fast box. Default setting is disabled to maintain realism
CONFIG.allow_fast_limit = false
CONFIG.allow_fast_limit = true
-- Radar only lock players with auto fast locking
-- When enabled, the radar will only automatically lock a speed if the caught vehicle has a real player in it.
CONFIG.only_lock_players = false
-- In-game first time quick start video
-- When enabled, the player will be asked if they'd like to view the quick start video the first time they
-- open the remote.
CONFIG.allow_quick_start_video = true
-- Allow passenger view
-- When enabled, the front seat passenger will be able to view the radar and plate reader from their end.
CONFIG.allow_passenger_view = true
-- Allow passenger control
-- Dependent on CONFIG.allow_passenger_view. When enabled, the front seat passenger will be able to open the
-- radar remote and control the radar and plate reader for themself and the driver.
CONFIG.allow_passenger_control = true
-- Set this to true if you use Sonoran CAD with the WraithV2 plugin
CONFIG.use_sonorancad = false
-- Sets the defaults of all keybinds
-- These keybinds can be changed by each person in their GTA Settings->Keybinds->FiveM
CONFIG.keyDefaults =
@@ -84,7 +100,15 @@ CONFIG.menuDefaults =
-- The speed unit used in conversions
-- Options: mph or kmh
["speedType"] = "mph"
["speedType"] = "mph",
-- The state for automatic speed locking. This requires CONFIG.allow_fast_limit to be true.
-- Options: true or false
["fastLock"] = false,
-- The speed limit required for automatic speed locking. This requires CONFIG.allow_fast_limit to be true.
-- Options: 0 to 200
["fastLimit"] = 60
}
-- Here you can change the default scale of the UI elements, as well as the safezone size
@@ -94,9 +118,9 @@ CONFIG.uiDefaults =
-- Options: 0.25 - 2.5
scale =
{
radar = 1.0,
remote = 1.0,
plateReader = 1.0
radar = 0.75,
remote = 0.75,
plateReader = 0.75
},
-- The safezone size, must be a multiple of 5.

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -68,6 +68,10 @@ READER.vars =
}
}
--[[----------------------------------------------------------------------------------
Plate reader functions
----------------------------------------------------------------------------------]]--
-- Gets the display state
function READER:GetDisplayState()
return self.vars.displayed
@@ -82,64 +86,58 @@ function READER:ToggleDisplayState()
SendNUIMessage( { _type = "setReaderDisplayState", state = self:GetDisplayState() } )
end
-- Sets the display's hidden state to the given state
function READER:SetDisplayHidden( state )
self.vars.hidden = state
end
-- Getter and setter for the display hidden state
function READER:GetDisplayHidden() return self.vars.hidden end
function READER:SetDisplayHidden( state ) self.vars.hidden = state end
-- Returns if the display is hidden
function READER:GetDisplayHidden()
return self.vars.hidden
end
-- Getter and setter for the given camera's plate
function READER:GetPlate( cam ) return self.vars.cams[cam].plate end
function READER:SetPlate( cam, plate ) self.vars.cams[cam].plate = plate end
-- Returns the stored plate for the given reader
function READER:GetPlate( cam )
return self.vars.cams[cam].plate
end
-- Sets the plate for the given reader to the given plate
function READER:SetPlate( cam, plate )
self.vars.cams[cam].plate = plate
end
-- Returns the stored plate index for the given reader
function READER:GetIndex( cam )
return self.vars.cams[cam].index
end
-- Sets the plate index for the given reader to the given index
function READER:SetIndex( cam, index )
self.vars.cams[cam].index = index
end
-- Getter and setter for the given camera's plate display index
function READER:GetIndex( cam ) return self.vars.cams[cam].index end
function READER:SetIndex( cam, index ) self.vars.cams[cam].index = index end
-- Returns the bolo plate
function READER:GetBoloPlate()
if ( self.vars.boloPlate ~= nil ) then
return self.vars.boloPlate
end
end
-- Sets the bolo plate to the given plate
function READER:SetBoloPlate( plate )
self.vars.boloPlate = plate
UTIL:Notify( "BOLO plate set to: " .. plate )
UTIL:Notify( "BOLO plate set to: ~b~" .. plate )
end
-- Clears the BOLO plate
function READER:ClearBoloPlate()
self.vars.boloPlate = nil
UTIL:Notify( "~b~BOLO plate cleared!" )
end
-- Returns if the given reader is locked
function READER:GetCamLocked( cam )
return self.vars.cams[cam].locked
end
function READER:GetCamLocked( cam ) return self.vars.cams[cam].locked end
-- Locks the given reader
function READER:LockCam( cam, playBeep, isBolo )
function READER:LockCam( cam, playBeep, isBolo, override )
-- Check that plate readers can actually be locked
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() and self:GetPlate( cam ) ~= "" ) then
-- Toggle the lock state
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 ), isBolo = isBolo } )
-- Play a beep
if ( self:GetCamLocked( cam ) ) then
-- Here we check if the override parameter is valid, if so then we set the reader's plate data to the
-- plate data provided in the override table.
if ( override ~= nil ) then
self:SetPlate( cam, override[1] )
self:SetIndex( cam, override[2] )
self:ForceNUIUpdate( false )
end
if ( playBeep ) then
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "plateAudio" ) } )
end
@@ -151,6 +149,9 @@ function READER:LockCam( cam, playBeep, isBolo )
-- Trigger an event so developers can hook into the scanner every time a plate is locked
TriggerServerEvent( "wk:onPlateLocked", cam, self:GetPlate( cam ), self:GetIndex( cam ) )
end
-- Tell the NUI side to show/hide the lock icon
SendNUIMessage( { _type = "lockPlate", cam = cam, state = self:GetCamLocked( cam ), isBolo = isBolo } )
end
end
@@ -168,25 +169,64 @@ function READER:GetCamFromNum( relPos )
end
end
-- Forces an NUI update, used by the passenger control system
function READER:ForceNUIUpdate( lock )
for cam in UTIL:Values( { "front", "rear" } ) do
local plate = self:GetPlate( cam )
local index = self:GetIndex( cam )
if ( plate ~= "" and index ~= "" ) then
SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } )
if ( lock ) then
SendNUIMessage( { _type = "lockPlate", cam = cam, state = self:GetCamLocked( cam ), isBolo = false } )
end
end
end
end
-- Returns a table with both antenna's speed data and directions
function READER:GetCameraDataPacket( cam )
return {
self:GetPlate( cam ),
self:GetIndex( cam )
}
end
RegisterNetEvent( "wk:togglePlateLock" )
AddEventHandler( "wk:togglePlateLock", function( cam, beep, bolo )
READER:LockCam( cam, beep, bolo )
end )
--[[----------------------------------------------------------------------------------
Plate reader NUI callbacks
----------------------------------------------------------------------------------]]--
-- Runs when the "Toggle Display" button is pressed on the plate reder box
RegisterNUICallback( "togglePlateReaderDisplay", function( data, cb )
-- Toggle the display state
READER:ToggleDisplayState()
cb('ok')
cb( "ok" )
end )
-- Runs when the "Set BOLO Plate" button is pressed on the plate reader box
RegisterNUICallback( "setBoloPlate", function( plate, cb )
-- Set the BOLO plate
READER:SetBoloPlate( plate )
cb('ok')
cb( "ok" )
end )
-- Runs when the "Clear BOLO Plate" button is pressed on the plate reader box
RegisterNUICallback( "clearBoloPlate", function( plate, cb )
-- Clear the BOLO plate
READER:ClearBoloPlate()
cb( "ok" )
end )
--[[----------------------------------------------------------------------------------
Plate reader threads
----------------------------------------------------------------------------------]]--
-- This is the main function that runs and scans all vehicles in front and behind the patrol vehicle
function READER:Main()
-- Check that the system can actually run
@@ -237,11 +277,15 @@ function READER:Main()
-- Automatically lock the plate if the scanned plate matches the BOLO
if ( plate == self:GetBoloPlate() ) then
self:LockCam( cam, false, true )
SYNC:LockReaderCam( cam, READER:GetCameraDataPacket( cam ) )
end
-- Send the plate information to the NUI side to update the UI
SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } )
-- If we use Sonoran CAD, reduce the plate events to just player's vehicle, otherwise life as normal
if ( ( CONFIG.use_sonorancad and ( UTIL:IsPlayerInVeh( veh ) or IsVehiclePreviouslyOwnedByPlayer( veh ) ) and GetVehicleClass( veh ) ~= 18 ) or not CONFIG.use_sonorancad ) then
-- Trigger the event so developers can hook into the scanner every time a plate is scanned
TriggerServerEvent( "wk:onPlateScanned", cam, plate, index )
end
@@ -249,6 +293,7 @@ function READER:Main()
end
end
end
end
end
-- Main thread
@@ -269,7 +314,7 @@ 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
self:SetDisplayHidden( true )
SendNUIMessage( { _type = "setReaderDisplayState", state = false } )
elseif ( PLY.veh > 0 and PLY.vehClassValid and PLY.inDriverSeat and self:GetDisplayState() and self:GetDisplayHidden() ) then
elseif ( PLY:CanViewRadar() and self:GetDisplayState() and self:GetDisplayHidden() ) then
self:SetDisplayHidden( false )
SendNUIMessage( { _type = "setReaderDisplayState", state = true } )
end

136
cl_player.lua Normal file
View File

@@ -0,0 +1,136 @@
--[[---------------------------------------------------------------------------------------
Wraith ARS 2X
Created by WolfKnight
For discussions, information on future updates, and more, join
my Discord: https://discord.gg/fD4e6WD
MIT License
Copyright (c) 2020-2021 WolfKnight
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.
---------------------------------------------------------------------------------------]]--
--[[----------------------------------------------------------------------------------
Player info variables
----------------------------------------------------------------------------------]]--
PLY =
{
ped = PlayerPedId(),
veh = nil,
inDriverSeat = false,
inPassengerSeat = false,
vehClassValid = false
}
-- Returns if the current vehicle fits the validity requirements for the radar to work
function PLY:VehicleStateValid()
return DoesEntityExist( self.veh ) and self.veh > 0 and self.vehClassValid
end
-- Used to check if the player is in a position where the radar should be allowed operation
function PLY:IsDriver()
return self:VehicleStateValid() and self.inDriverSeat
end
-- Returns if the player is in the front passenger seat of an emergency vehicle
function PLY:IsPassenger()
return self:VehicleStateValid() and self.inPassengerSeat
end
-- Returns if the player can view the radar, ensures their vehicle state is valid and that they are a driver or
-- a passenger (where valid)
function PLY:CanViewRadar()
return self:IsDriver() or ( self:IsPassenger() and RADAR:IsPassengerViewAllowed() )
end
-- Returns if the player is allowed to control the radar from the passenger seat
function PLY:CanControlRadar()
return self:IsDriver() or ( self:IsPassenger() and RADAR:IsPassengerControlAllowed() )
end
-- Returns the ped in the opposite seat to the player, e.g. if we're the passenger, then return the driver
function PLY:GetOtherPed()
if ( self:IsDriver() ) then
return GetPedInVehicleSeat( PLY.veh, 0 )
elseif ( self:IsPassenger() ) then
return GetPedInVehicleSeat( PLY.veh, -1 )
end
return nil
end
-- Returns the server ID of the player in the opposite seat (driver/passenger)
function PLY:GetOtherPedServerId()
local otherPed = self:GetOtherPed()
if ( otherPed ~= nil and otherPed ~= 0 and IsPedAPlayer( otherPed ) ) then
local otherPly = GetPlayerServerId( NetworkGetPlayerIndexFromPed( otherPed ) )
return otherPly
end
return nil
end
-- The main purpose of this thread is to update the information about the local player, including their
-- ped id, the vehicle id (if they're in one), whether they're in a driver seat, and if the vehicle's class
-- is valid or not
Citizen.CreateThread( function()
while ( true ) do
PLY.ped = PlayerPedId()
PLY.veh = GetVehiclePedIsIn( PLY.ped, false )
PLY.inDriverSeat = GetPedInVehicleSeat( PLY.veh, -1 ) == PLY.ped
PLY.inPassengerSeat = GetPedInVehicleSeat( PLY.veh, 0 ) == PLY.ped
PLY.vehClassValid = GetVehicleClass( PLY.veh ) == 18
Citizen.Wait( 500 )
end
end )
-- This thread is used to check when the player is entering a vehicle and then triggers the sync system
Citizen.CreateThread( function()
while ( true ) do
-- The sync trigger should only start when the player is getting into a vehicle
if ( IsPedGettingIntoAVehicle( PLY.ped ) and RADAR:IsPassengerViewAllowed() ) then
-- Get the vehicle the player is entering
local vehEntering = GetVehiclePedIsEntering( PLY.ped )
-- Only proceed if the vehicle the player is entering is an emergency vehicle
if ( GetVehicleClass( vehEntering ) == 18 ) then
-- Wait two seconds, this gives enough time for the player to get sat in the seat
Citizen.Wait( 2000 )
-- Get the vehicle the player is now in
local veh = GetVehiclePedIsIn( PLY.ped, false )
-- Trigger the main sync data function if the vehicle the player is now in is the same as the one they
-- began entering
if ( veh == vehEntering ) then
SYNC:SyncDataOnEnter()
end
end
end
Citizen.Wait( 500 )
end
end )

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -39,31 +39,89 @@ local tostring = tostring
local math = math
local pairs = pairs
--[[----------------------------------------------------------------------------------
Resource Rename Fix - for those muppets who rename the resource and
complain that the NUI aspect doesn't work!
Key bind registering
----------------------------------------------------------------------------------]]--
Citizen.SetTimeout( 1000, function()
-- Get the name of the resource, for example the default name is 'wk_wars2x'
local name = string.lower( GetCurrentResourceName() )
local function RegisterKeyBinds()
if ( UTIL:IsResourceNameValid() ) then
UTIL:Log( "Registering radar commands and key binds." )
-- Print a little message in the client's console
UTIL:Log( "Sending resource name (" .. name .. ") to JavaScript side." )
-- Opens the remote control
RegisterCommand( "radar_remote", function()
if ( not RADAR:GetKeyLockState() ) then
RADAR:OpenRemote()
end
end )
RegisterKeyMapping( "radar_remote", "Open Remote Control", "keyboard", CONFIG.keyDefaults.remote_control )
-- Send a message through the NUI system to the JavaScript file to give the name of the resource
SendNUIMessage( { _type = "updatePathName", pathName = name } )
end )
-- Locks speed from front antenna
RegisterCommand( "radar_fr_ant", function()
if ( not RADAR:GetKeyLockState() and PLY:CanControlRadar() ) then
RADAR:LockAntennaSpeed( "front", nil )
SYNC:LockAntennaSpeed( "front", RADAR:GetAntennaDataPacket( "front" ) )
end
end )
RegisterKeyMapping( "radar_fr_ant", "Front Antenna Lock/Unlock", "keyboard", CONFIG.keyDefaults.front_lock )
-- Locks speed from rear antenna
RegisterCommand( "radar_bk_ant", function()
if ( not RADAR:GetKeyLockState() and PLY:CanControlRadar() ) then
RADAR:LockAntennaSpeed( "rear", nil )
SYNC:LockAntennaSpeed( "rear", RADAR:GetAntennaDataPacket( "rear" ) )
end
end )
RegisterKeyMapping( "radar_bk_ant", "Rear Antenna Lock/Unlock", "keyboard", CONFIG.keyDefaults.rear_lock )
-- Locks front plate reader
RegisterCommand( "radar_fr_cam", function()
if ( not RADAR:GetKeyLockState() and PLY:CanControlRadar() ) then
READER:LockCam( "front", true, false )
SYNC:LockReaderCam( "front", READER:GetCameraDataPacket( "front" ) )
end
end )
RegisterKeyMapping( "radar_fr_cam", "Front Plate Reader Lock/Unlock", "keyboard", CONFIG.keyDefaults.plate_front_lock )
-- Locks rear plate reader
RegisterCommand( "radar_bk_cam", function()
if ( not RADAR:GetKeyLockState() and PLY:CanControlRadar() ) then
READER:LockCam( "rear", true, false )
SYNC:LockReaderCam( "rear", READER:GetCameraDataPacket( "rear" ) )
end
end )
RegisterKeyMapping( "radar_bk_cam", "Rear Plate Reader Lock/Unlock", "keyboard", CONFIG.keyDefaults.plate_rear_lock )
-- Toggles the key lock state
RegisterCommand( "radar_key_lock", function()
RADAR:ToggleKeyLock()
end )
RegisterKeyMapping( "radar_key_lock", "Toggle Keybind Lock", "keyboard", CONFIG.keyDefaults.key_lock )
-- Deletes all of the KVPs
RegisterCommand( "reset_radar_data", function()
DeleteResourceKvp( "wk_wars2x_ui_data" )
DeleteResourceKvp( "wk_wars2x_om_data" )
DeleteResourceKvp( "wk_wars2x_new_user" )
UTIL:Notify( "Radar data deleted, please immediately restart your game without opening the radar's remote." )
end, false )
TriggerEvent( "chat:addSuggestion", "/reset_radar_data", "Resets the KVP data stored for the wk_wars2x resource." )
else
UTIL:Log( "ERROR: Resource name is not wk_wars2x. Key binds will not be registered for compatibility reasons. Contact the server owner and ask them to change the resource name back to wk_wars2x" )
end
end
--[[----------------------------------------------------------------------------------
UI loading trigger
UI loading and key binds trigger
----------------------------------------------------------------------------------]]--
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()
if ( not spawned ) then
local function LoadUISettings()
UTIL:Log( "Attempting to load saved UI settings data." )
-- Try and get the saved UI data
@@ -80,39 +138,31 @@ AddEventHandler( "playerSpawned", function()
UTIL:Log( "Could not find any saved UI settings data." )
end
end
-- Runs every time the player spawns, but the additional check means it only runs the first time
-- the player spawns
AddEventHandler( "playerSpawned", function()
if ( not spawned ) then
RegisterKeyBinds()
LoadUISettings()
spawned = true
end
end )
-- Loads the UI settings when the resource gets restarted, this way active users don't have the
-- default settings applied
AddEventHandler( "onResourceStart", function( resourceName )
if ( GetCurrentResourceName() == resourceName ) then
Citizen.CreateThread( function()
Citizen.Wait( 1000 )
--[[----------------------------------------------------------------------------------
Player info variables
----------------------------------------------------------------------------------]]--
PLY =
{
ped = PlayerPedId(),
veh = nil,
inDriverSeat = false,
vehClassValid = false
}
RegisterKeyBinds()
LoadUISettings()
-- Used to check if the player is in a position where the radar should be allowed operation
function PLY:VehicleStateValid()
return DoesEntityExist( self.veh ) and self.veh > 0 and self.inDriverSeat and self.vehClassValid
end
-- The main purpose of this thread is to update the information about the local player, including their
-- ped id, the vehicle id (if they're in one), whether they're in a driver seat, and if the vehicle's class
-- is valid or not
Citizen.CreateThread( function()
while ( true ) do
PLY.ped = PlayerPedId()
PLY.veh = GetVehiclePedIsIn( PLY.ped, false )
PLY.inDriverSeat = GetPedInVehicleSeat( PLY.veh, -1 ) == PLY.ped
PLY.vehClassValid = GetVehicleClass( PLY.veh ) == 18
Citizen.Wait( 500 )
DecorSetBool( PlayerPedId(), "wk_wars2x_sync_remoteOpen", false )
end )
end
end )
@@ -157,7 +207,13 @@ RADAR.vars =
["plateAudio"] = CONFIG.menuDefaults["plateAudio"],
-- The speed unit used in conversions
["speedType"] = CONFIG.menuDefaults["speedType"]
["speedType"] = CONFIG.menuDefaults["speedType"],
-- The state of automatic speed locking
["fastLock"] = CONFIG.menuDefaults["fastLock"],
-- The speed limit for automatic speed locking
["fastLimit"] = CONFIG.menuDefaults["fastLimit"]
},
-- These 3 variables are for the in-radar menu that can be accessed through the remote control, the menuOptions table
@@ -218,10 +274,6 @@ RADAR.vars =
-- Table to store tables for hit entities of captured vehicles
capturedVehicles = {},
-- Table for temp id storage to stop unnecessary trace checks
-- needs to be redone
-- tempVehicleIDs = {},
-- Table to store the valid vehicle models
validVehicles = {},
@@ -286,18 +338,24 @@ function RADAR:SetPoweringUpState( state )
end
-- Toggles the radar power
function RADAR:TogglePower()
function RADAR:SetPowerState( state, instantOverride )
local currentState = self:IsPowerOn()
-- Only power up if the system is not already powering up
if ( not self:IsPoweringUp() and currentState ~= state ) then
-- Toggle the power variable
self.vars.power = not self.vars.power
self.vars.power = state
-- Send the NUI message to toggle the power
SendNUIMessage( { _type = "radarPower", state = self:IsPowerOn() } )
SendNUIMessage( { _type = "radarPower", state = state, override = instantOverride, fast = self:IsFastDisplayEnabled() } )
-- Power is now turned on
if ( self:IsPowerOn() ) then
-- Also make sure the operator menu is inactive
self:SetMenuState( false )
-- Only do the power up simulation if allowed
if ( not instantOverride ) then
-- Tell the system the radar is 'powering up'
self:SetPoweringUpState( true )
@@ -307,13 +365,15 @@ function RADAR:TogglePower()
self:SetPoweringUpState( false )
-- Let the UI side know the system has loaded
SendNUIMessage( { _type = "poweredUp" } )
SendNUIMessage( { _type = "poweredUp", fast = self:IsFastDisplayEnabled() } )
end )
end
else
-- If the system is being turned off, then we reset the antennas
self:ResetAntenna( "front" )
self:ResetAntenna( "rear" )
end
end
end
-- Toggles the display state of the radar system
@@ -330,29 +390,9 @@ function RADAR:GetDisplayState()
return self.vars.displayed
end
-- Used to set individual settings within RADAR.vars.settings, as all of the settings use string keys, using this
-- function makes updating settings easier
function RADAR:SetSettingValue( setting, value )
-- Make sure that we're not trying to set a nil value for the setting
if ( value ~= nil ) then
-- Set the setting's value
self.vars.settings[setting] = value
-- If the setting that's being updated is same or opp, then we update the end coordinates for the ray tracer
if ( setting == "same" or setting == "opp" ) then
self:UpdateRayEndCoords()
end
end
end
-- Returns the value of the given setting
function RADAR:GetSettingValue( setting )
return self.vars.settings[setting]
end
-- Return the state of the fastDisplay setting, short hand direct way to check if the fast system is enabled
function RADAR:IsFastDisplayEnabled()
return self.vars.settings["fastDisplay"]
return self:GetSettingValue( "fastDisplay" )
end
-- Returns if either of the antennas are transmitting
@@ -385,32 +425,28 @@ function RADAR:CanPerformMainTask()
return self:IsPowerOn() and not self:IsPoweringUp() and not self:IsMenuOpen()
end
-- Returns what the dynamic thread wait time is
function RADAR:GetThreadWaitTime()
return self.vars.threadWaitTime
end
-- Returns/sets what the dynamic thread wait time is
function RADAR:GetThreadWaitTime() return self.vars.threadWaitTime end
function RADAR:SetThreadWaitTime( time ) self.vars.threadWaitTime = time end
-- Sets the dynamic thread wait time to the given value
function RADAR:SetThreadWaitTime( time )
self.vars.threadWaitTime = time
end
-- Returns/sets the radr's display hidden state
function RADAR:GetDisplayHidden() return self.vars.hidden end
function RADAR:SetDisplayHidden( state ) self.vars.hidden = state end
-- Sets the display's hidden state to the given state
function RADAR:SetDisplayHidden( state )
self.vars.hidden = state
end
-- Returns if the display is hidden
function RADAR:GetDisplayHidden()
return self.vars.hidden
end
-- Opens the remote only if the pause menu is not open and the player's vehicle state is valid
-- Opens the remote only if the pause menu is not open and the player's vehicle state is valid, as the
-- passenger can also open the remote, we check the config variable as well.
function RADAR:OpenRemote()
if ( not IsPauseMenuActive() and PLY:VehicleStateValid() ) then
if ( not IsPauseMenuActive() and PLY:CanViewRadar() ) then
-- Get the remote open state from the other player
local openByOtherPly = SYNC:IsRemoteAlreadyOpen( PLY:GetOtherPed() )
-- Check that the remote can be opened
if ( not openByOtherPly ) then
-- Tell the NUI side to open the remote
SendNUIMessage( { _type = "openRemote" } )
SYNC:SetRemoteOpenState( true )
if ( CONFIG.allow_quick_start_video ) then
-- Display the new user popup if we can
local show = GetResourceKvpInt( "wk_wars2x_new_user" )
@@ -422,6 +458,9 @@ function RADAR:OpenRemote()
-- Bring focus to the NUI side
SetNuiFocus( true, true )
else
UTIL:Notify( "Another player already has the remote open." )
end
end
end
@@ -431,6 +470,22 @@ AddEventHandler( "wk:openRemote", function()
RADAR:OpenRemote()
end )
-- Returns if the passenger can view the radar too
function RADAR:IsPassengerViewAllowed()
return CONFIG.allow_passenger_view
end
-- Returns if the passenger can control the radar and plate reader, reliant on the passenger being
-- able to view the radar and plate reader too
function RADAR:IsPassengerControlAllowed()
return CONFIG.allow_passenger_view and CONFIG.allow_passenger_control
end
-- Returns if we only auto lock vehicle speeds if said vehicle is a player
function RADAR:OnlyLockFastPlayers()
return CONFIG.only_lock_players
end
-- Returns if the fast limit option should be available for the radar
function RADAR:IsFastLimitAllowed()
return CONFIG.allow_fast_limit
@@ -455,10 +510,6 @@ if ( RADAR:IsFastLimitAllowed() ) then
table.insert( fastOptions[2].options, i )
end
-- Create the settings with the default options
self:SetSettingValue( "fastLock", false )
self:SetSettingValue( "fastLimit", 60 )
-- Add the fast options to the main menu options table
table.insert( self.vars.menuOptions, fastOptions[1] )
table.insert( self.vars.menuOptions, fastOptions[2] )
@@ -466,19 +517,19 @@ if ( RADAR:IsFastLimitAllowed() ) then
-- Returns the numerical fast limit
function RADAR:GetFastLimit()
return self.vars.settings["fastLimit"]
return self:GetSettingValue( "fastLimit" )
end
-- Returns if the fast lock menu option is on or off
function RADAR:IsFastLockEnabled()
return self.vars.settings["fastLock"]
return self:GetSettingValue( "fastLock" )
end
end
-- Toggles the internal key lock state, which stops any of the radar's key binds from working
function RADAR:ToggleKeyLock()
-- Check the player state is valid
if ( PLY:VehicleStateValid() ) then
if ( PLY:CanViewRadar() ) then
-- Toggle the key lock variable
self.vars.keyLock = not self.vars.keyLock
@@ -510,6 +561,30 @@ function RADAR:SetMenuState( state )
end
end
-- Closes the operator menu
function RADAR:CloseMenu( playAudio )
-- Set the internal menu state to be closed (false)
RADAR:SetMenuState( false )
-- Send a setting update to the NUI side
RADAR:SendSettingUpdate()
-- Play a menu done beep
if ( playAudio or playAudio == nil ) then
SendNUIMessage( { _type = "audio", name = "done", vol = RADAR:GetSettingValue( "beep" ) } )
end
-- Save the operator menu values
local omData = json.encode( RADAR.vars.settings )
SetResourceKvp( "wk_wars2x_om_data", omData )
-- Send the operator menu to the passenger if allowed
if ( self:IsPassengerViewAllowed() ) then
local updatedOMData = self:GetOMTableData()
SYNC:SendUpdatedOMData( updatedOMData )
end
end
-- Returns if the operator menu is open
function RADAR:IsMenuOpen()
return self.vars.menuActive
@@ -600,6 +675,26 @@ function RADAR:SendMenuUpdate()
SendNUIMessage( { _type = "menu", text = self:GetMenuOptionDisplayText(), option = self:GetMenuOptionText() } )
end
-- Used to set individual settings within RADAR.vars.settings, as all of the settings use string keys, using this
-- function makes updating settings easier
function RADAR:SetSettingValue( setting, value )
-- Make sure that we're not trying to set a nil value for the setting
if ( value ~= nil ) then
-- Set the setting's value
self.vars.settings[setting] = value
-- If the setting that's being updated is same or opp, then we update the end coordinates for the ray tracer
if ( setting == "same" or setting == "opp" ) then
self:UpdateRayEndCoords()
end
end
end
-- Returns the value of the given setting
function RADAR:GetSettingValue( setting )
return self.vars.settings[setting]
end
-- Attempts to load the saved operator menu data
function RADAR:LoadOMData()
UTIL:Log( "Attempting to load saved operator menu data." )
@@ -620,8 +715,10 @@ end
-- Updates the operator menu option indexes, as the default menu values can be changed in the config, we
-- need to update the indexes otherwise the menu will display the wrong values
function RADAR:UpdateOptionIndexes()
function RADAR:UpdateOptionIndexes( loadSaved )
if ( loadSaved ) then
self:LoadOMData()
end
-- Iterate through each of the internal settings
for k, v in pairs( self.vars.settings ) do
@@ -647,29 +744,19 @@ end
Radar basics functions
----------------------------------------------------------------------------------]]--
-- Returns the patrol speed value stored
function RADAR:GetPatrolSpeed()
return self.vars.patrolSpeed
end
function RADAR:GetPatrolSpeed() return self.vars.patrolSpeed end
-- Returns the current vehicle pool
function RADAR:GetVehiclePool()
return self.vars.vehiclePool
end
function RADAR:GetVehiclePool() return self.vars.vehiclePool end
-- Returns the maximum distance a ray trace can go
function RADAR:GetMaxCheckDist()
return self.vars.maxCheckDist
end
function RADAR:GetMaxCheckDist() return self.vars.maxCheckDist end
-- Returns the table sorting function 'strongest'
function RADAR:GetStrongestSortFunc()
return self.sorting.strongest
end
function RADAR:GetStrongestSortFunc() return self.sorting.strongest end
-- Returns the table sorting function 'fastest'
function RADAR:GetFastestSortFunc()
return self.sorting.fastest
end
function RADAR:GetFastestSortFunc() return self.sorting.fastest end
-- Sets the patrol speed to a formatted version of the given number
function RADAR:SetPatrolSpeed( speed )
@@ -690,29 +777,19 @@ end
Radar ray trace functions
----------------------------------------------------------------------------------]]--
-- Returns what the current ray trace state is
function RADAR:GetRayTraceState()
return self.vars.rayTraceState
end
function RADAR:GetRayTraceState() return self.vars.rayTraceState end
-- Caches the number of ray traces in RADAR.rayTraces
function RADAR:CacheNumRays()
self.vars.numberOfRays = #self.rayTraces
end
function RADAR:CacheNumRays() self.vars.numberOfRays = #self.rayTraces end
-- Returns the number of ray traces the system has
function RADAR:GetNumOfRays()
return self.vars.numberOfRays
end
function RADAR:GetNumOfRays() return self.vars.numberOfRays end
-- Increases the system's ray trace state ny 1
function RADAR:IncreaseRayTraceState()
self.vars.rayTraceState = self.vars.rayTraceState + 1
end
function RADAR:IncreaseRayTraceState() self.vars.rayTraceState = self.vars.rayTraceState + 1 end
-- Resets the ray trace state to 0
function RADAR:ResetRayTraceState()
self.vars.rayTraceState = 0
end
function RADAR:ResetRayTraceState() self.vars.rayTraceState = 0 end
-- This function is used to determine if a sphere intersect is in front or behind the player's vehicle, the
-- sphere intersect calculation has a 'tProj' value that is a line from the centre of the sphere that goes onto
@@ -913,21 +990,22 @@ end
----------------------------------------------------------------------------------]]--
-- Toggles the state of the given antenna between hold and transmitting, only works if the radar's power is
-- on. Also runs a callback function when present.
function RADAR:ToggleAntenna( ant, cb )
function RADAR:ToggleAntenna( ant )
-- Check power is on
if ( self:IsPowerOn() ) then
-- Toggle the given antennas state
self.vars.antennas[ant].xmit = not self.vars.antennas[ant].xmit
-- Run the callback function if there is one
if ( cb ) then cb() end
-- Update the interface with the new antenna transmit state
SendNUIMessage( { _type = "antennaXmit", ant = ant, on = self:IsAntennaTransmitting( ant ) } )
-- Play some audio specific to the transmit state
SendNUIMessage( { _type = "audio", name = self:IsAntennaTransmitting( ant ) and "xmit_on" or "xmit_off", vol = self:GetSettingValue( "beep" ) } )
end
end
-- Returns if the given antenna is transmitting
function RADAR:IsAntennaTransmitting( ant )
return self.vars.antennas[ant].xmit
end
function RADAR:IsAntennaTransmitting( ant ) return self.vars.antennas[ant].xmit end
-- Returns if the given relative position value is for the front or rear antenna
function RADAR:GetAntennaTextFromNum( relPos )
@@ -939,13 +1017,11 @@ function RADAR:GetAntennaTextFromNum( relPos )
end
-- Returns the mode of the given antenna
function RADAR:GetAntennaMode( ant )
return self.vars.antennas[ant].mode
end
function RADAR:GetAntennaMode( ant ) return self.vars.antennas[ant].mode end
-- Sets the mode of the given antenna if the mode is valid and the power is on. Also runs a callback function
-- when present.
function RADAR:SetAntennaMode( ant, mode, cb )
function RADAR:SetAntennaMode( ant, mode )
-- Check the mode is actually a number, this is needed as the radar system relies on the mode to be
-- a number to work
if ( type( mode ) == "number" ) then
@@ -954,57 +1030,36 @@ function RADAR:SetAntennaMode( ant, mode, cb )
-- Update the mode for the antenna
self.vars.antennas[ant].mode = mode
-- Run the callback function if there is one
if ( cb ) then cb() end
-- Update the interface with the new mode
SendNUIMessage( { _type = "antennaMode", ant = ant, mode = mode } )
-- Play a beep
SendNUIMessage( { _type = "audio", name = "beep", vol = self:GetSettingValue( "beep" ) } )
end
end
end
-- Returns the speed stored for the given antenna
function RADAR:GetAntennaSpeed( ant )
return self.vars.antennas[ant].speed
end
-- Returns/sets the speed for the given antenna
function RADAR:GetAntennaSpeed( ant ) return self.vars.antennas[ant].speed end
function RADAR:SetAntennaSpeed( ant, speed ) self.vars.antennas[ant].speed = speed end
-- Sets the speed of the given antenna to the given speed
function RADAR:SetAntennaSpeed( ant, speed )
self.vars.antennas[ant].speed = speed
end
-- Returns/sets the direction for the given antenna
function RADAR:GetAntennaDir( ant ) return self.vars.antennas[ant].dir end
function RADAR:SetAntennaDir( ant, dir ) self.vars.antennas[ant].dir = dir end
-- Returns the direction value stored for the given antenna
function RADAR:GetAntennaDir( ant )
return self.vars.antennas[ant].dir
end
-- Sets the direction value of the given antenna to the given direction
function RADAR:SetAntennaDir( ant, dir )
self.vars.antennas[ant].dir = dir
end
-- Sets the fast speed and direction in one go
-- Sets the speed and direction in one go
function RADAR:SetAntennaData( ant, speed, dir )
self:SetAntennaSpeed( ant, speed )
self:SetAntennaDir( ant, dir )
end
-- Returns the fast speed stored for the given antenna
function RADAR:GetAntennaFastSpeed( ant )
return self.vars.antennas[ant].fastSpeed
end
-- Returns/sets the fast speed for the given antenna
function RADAR:GetAntennaFastSpeed( ant ) return self.vars.antennas[ant].fastSpeed end
function RADAR:SetAntennaFastSpeed( ant, speed ) self.vars.antennas[ant].fastSpeed = speed end
-- Sets the fast speed of the given antenna to the given speed
function RADAR:SetAntennaFastSpeed( ant, speed )
self.vars.antennas[ant].fastSpeed = speed
end
-- Returns the direction value for the fast box stored for the given antenna
function RADAR:GetAntennaFastDir( ant )
return self.vars.antennas[ant].fastDir
end
-- Sets the direction value of the given antenna's fast box to the given direction
function RADAR:SetAntennaFastDir( ant, dir )
self.vars.antennas[ant].fastDir = dir
end
-- Returns/sets the fast direction for the given antenna
function RADAR:GetAntennaFastDir( ant ) return self.vars.antennas[ant].fastDir end
function RADAR:SetAntennaFastDir( ant, dir ) self.vars.antennas[ant].fastDir = dir end
-- Sets the fast speed and direction in one go
function RADAR:SetAntennaFastData( ant, speed, dir )
@@ -1042,7 +1097,7 @@ function RADAR:SetAntennaSpeedIsLocked( ant, state )
end
-- Sets a speed and direction to be locked in for the given antenna
function RADAR:SetAntennaSpeedLock( ant, speed, dir, lockType )
function RADAR:SetAntennaSpeedLock( ant, speed, dir, lockType, playAudio )
-- Check that the passed speed and direction are actually valid
if ( speed ~= nil and dir ~= nil and lockType ~= nil ) then
-- Set the locked speed and direction to the passed values
@@ -1053,11 +1108,13 @@ function RADAR:SetAntennaSpeedLock( ant, speed, dir, lockType )
-- Tell the system that a speed has been locked for the given antenna
self:SetAntennaSpeedIsLocked( ant, true )
if ( playAudio ) then
-- Send a message to the NUI side to play the beep sound with the current volume setting
SendNUIMessage( { _type = "audio", name = "beep", vol = self:GetSettingValue( "beep" ) } )
-- 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 = self:GetSettingValue( "voice" ) } )
end
-- Great Scott!
if ( speed == "¦88" and self:GetSettingValue( "speedType" ) == "mph" ) then
@@ -1101,12 +1158,28 @@ end
-- When the user presses the speed lock key for either antenna, this function is called to get the
-- necessary information from the antenna, and then lock it into the display
function RADAR:LockAntennaSpeed( ant )
function RADAR:LockAntennaSpeed( ant, override, lockRegardless )
-- 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() ) or lockRegardless ) and self:IsAntennaTransmitting( ant ) ) then
-- Used to determine whether or not to play the audio and update the display. This is mainly for the passenger
-- control system, as in theory one player could be in the operator menu, and the other player could lock a speed.
local isMenuOpen = self:IsMenuOpen()
-- 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
if ( not self:IsAntennaSpeedLocked( ant ) ) then
-- Here we check if the override parameter is valid, if so then we set the radar's speed data to the
-- speed data provided in the override table.
if ( override ~= nil ) then
self:SetAntennaData( ant, override[1], override[2] )
self:SetAntennaFastData( ant, override[3], override[4] )
end
-- This override parameter is used for the passenger control system, as the speeds displayed on the
-- recipients display can't be trusted. When the player who locks the speed triggers the sync, their
-- speed data is collected and sent to the other player so that their speed data is overriden to be the same.
override = override or { nil, nil, nil, nil }
-- 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
local data = { nil, nil, nil }
@@ -1124,15 +1197,17 @@ function RADAR:LockAntennaSpeed( ant )
end
-- 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], not isMenuOpen )
else
self:ResetAntennaSpeedLock( ant )
end
if ( not isMenuOpen ) then
-- Send an NUI message to change the lock label, otherwise we'd have to wait until the next main loop
SendNUIMessage( { _type = "antennaLock", ant = ant, state = self:IsAntennaSpeedLocked( ant ) } )
SendNUIMessage( { _type = "antennaFast", ant = ant, state = self:ShouldFastBeDisplayed( ant ) } )
end
end
end
-- Resets an antenna, used when the system is turned off
@@ -1146,6 +1221,16 @@ function RADAR:ResetAntenna( ant )
self:ResetAntennaSpeedLock( ant )
end
-- Returns a table with the given antenna's speed data and directions
function RADAR:GetAntennaDataPacket( ant )
return {
self:GetAntennaSpeed( ant ),
self:GetAntennaDir( ant ),
self:GetAntennaFastSpeed( ant ),
self:GetAntennaFastDir( ant )
}
end
--[[----------------------------------------------------------------------------------
Radar captured vehicle functions
@@ -1267,15 +1352,9 @@ function RADAR:GetVehSpeedConverted( speed )
return UTIL:Round( speed * self.speedConversions[unit], 0 )
end
-- Returns the validity of the given vehicle model
function RADAR:GetVehicleValidity( key )
return self.vars.validVehicles[key]
end
-- Sets the validity for the given vehicle model
function RADAR:SetVehicleValidity( key, validity )
self.vars.validVehicles[key] = validity
end
-- Returns/sets the validity of the given vehicle model
function RADAR:GetVehicleValidity( key ) return self.vars.validVehicles[key] end
function RADAR:SetVehicleValidity( key, validity ) self.vars.validVehicles[key] = validity end
-- Returns if vehicle validity data exists for the given vehicle model
function RADAR:DoesVehicleValidityExist( key )
@@ -1422,57 +1501,61 @@ end
RegisterNUICallback( "toggleRadarDisplay", function( data, cb )
-- Toggle the display state
RADAR:ToggleDisplayState()
cb('ok')
cb( "ok" )
end )
-- Runs when the user presses the power button on the radar ui
RegisterNUICallback( "togglePower", function( data, cb )
if ( PLY:CanControlRadar() ) then
if ( not RADAR:IsPoweringUp() ) then
-- Toggle the radar's power
RADAR:TogglePower()
cb('ok')
RADAR:SetPowerState( not RADAR:IsPowerOn(), false )
SYNC:SendPowerState( RADAR:IsPowerOn() )
end
end
cb( "ok" )
end )
-- Runs when the user presses the ESC or RMB when the remote is open
RegisterNUICallback( "closeRemote", function( data, cb )
-- Remove focus to the NUI side
SetNuiFocus( false, false )
cb('ok')
if ( RADAR:IsMenuOpen() ) then
RADAR:CloseMenu( false )
end
SYNC:SetRemoteOpenState( false )
cb( "ok" )
end )
-- Runs when the user presses any of the antenna mode buttons on the remote
RegisterNUICallback( "setAntennaMode", function( data, cb )
if ( PLY:CanControlRadar() ) then
-- Only run the codw if the radar has power and is not powering up
if ( RADAR:IsPowerOn() and not RADAR:IsPoweringUp() ) then
-- As the mode buttons are used to exit the menu, we check for that
if ( RADAR:IsMenuOpen() ) then
-- Set the internal menu state to be closed (false)
RADAR:SetMenuState( false )
-- Send a setting update to the NUI side
RADAR:SendSettingUpdate()
-- Play a menu done beep
SendNUIMessage( { _type = "audio", name = "done", vol = RADAR:GetSettingValue( "beep" ) } )
-- Save the operator menu values
local omData = json.encode( RADAR.vars.settings )
SetResourceKvp( "wk_wars2x_om_data", omData )
RADAR:CloseMenu()
else
-- Change the mode for the designated antenna, pass along a callback which contains data from this NUI callback
RADAR:SetAntennaMode( data.value, tonumber( data.mode ), function()
-- Update the interface with the new mode
SendNUIMessage( { _type = "antennaMode", ant = data.value, mode = tonumber( data.mode ) } )
RADAR:SetAntennaMode( data.value, tonumber( data.mode ) )
-- Play a beep
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
end )
-- Sync
SYNC:SendAntennaMode( data.value, tonumber( data.mode ) )
end
end
cb('ok')
end
cb( "ok" )
end )
-- Runs when the user presses either of the XMIT/HOLD buttons on the remote
RegisterNUICallback( "toggleAntenna", function( data, cb )
if ( PLY:CanControlRadar() ) then
-- Only run the codw if the radar has power and is not powering up
if ( RADAR:IsPowerOn() and not RADAR:IsPoweringUp() ) then
-- As the xmit/hold buttons are used to change settings in the menu, we check for that
@@ -1484,20 +1567,20 @@ RegisterNUICallback( "toggleAntenna", function( data, cb )
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
else
-- Toggle the transmit state for the designated antenna, pass along a callback which contains data from this NUI callback
RADAR:ToggleAntenna( data.value, function()
-- Update the interface with the new antenna transmit state
SendNUIMessage( { _type = "antennaXmit", ant = data.value, on = RADAR:IsAntennaTransmitting( data.value ) } )
RADAR:ToggleAntenna( data.value )
-- Play some audio specific to the transmit state
SendNUIMessage( { _type = "audio", name = RADAR:IsAntennaTransmitting( data.value ) and "xmit_on" or "xmit_off", vol = RADAR:GetSettingValue( "beep" ) } )
end )
-- Sync
SYNC:SendAntennaPowerState( RADAR:IsAntennaTransmitting( data.value ), data.value )
end
end
cb('ok')
end
cb( "ok" )
end )
-- Runs when the user presses the menu button on the remote control
RegisterNUICallback( "menu", function( data, cb )
if ( PLY:CanControlRadar() ) then
-- Only run the codw if the radar has power and is not powering up
if ( RADAR:IsPowerOn() and not RADAR:IsPoweringUp() ) then
-- As the menu button is a multipurpose button, we first check to see if the menu is already open
@@ -1515,20 +1598,22 @@ RegisterNUICallback( "menu", function( data, cb )
-- Play the standard audio beep
SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } )
end
cb('ok')
end
cb( "ok" )
end )
-- Runs when the JavaScript side sends the UI data for saving
RegisterNUICallback( "saveUiData", function( data, cb )
UTIL:Log( "Saving updated UI settings data." )
SetResourceKvp( "wk_wars2x_ui_data", json.encode( data ) )
cb('ok')
cb( "ok" )
end )
-- Runs when the JavaScript side sends the quick start video has been watched
RegisterNUICallback( "qsvWatched", function( data, cb )
SetResourceKvpInt( "wk_wars2x_new_user", 1 )
cb('ok')
cb( "ok" )
end )
@@ -1573,7 +1658,7 @@ end )
function RADAR:RunThreads()
-- For the system to even run, the player needs to be sat in the driver's seat of a class 18 vehicle, the
-- radar has to be visible and the power must be on, and either one of the antennas must be enabled.
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
if ( PLY:CanViewRadar() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
-- Before we create any of the custom ray trace threads, we need to make sure that the ray trace state
-- is at zero, if it is not at zero, then it means the system is still currently tracing
if ( self:GetRayTraceState() == 0 ) then
@@ -1615,7 +1700,7 @@ end )
function RADAR:Main()
-- Only run any of the main code if all of the states are met, player in the driver's seat of a class 18 vehicle, and
-- the system has to be able to perform main tasks
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then
if ( PLY:CanViewRadar() and self:CanPerformMainTask() ) then
-- Create a table that will be used to store all of the data to be sent to the NUI side
local data = {}
@@ -1687,7 +1772,12 @@ function RADAR:Main()
if ( self:IsFastLimitAllowed() ) then
-- Make sure the speed is larger than the limit, and that there isn't already a locked speed
if ( self:IsFastLockEnabled() and convertedSpeed > self:GetFastLimit() and not self:IsAntennaSpeedLocked( ant ) ) then
self:LockAntennaSpeed( ant )
if ( ( self:OnlyLockFastPlayers() and UTIL:IsPlayerInVeh( av[ant][i].veh ) ) or not self:OnlyLockFastPlayers() ) then
if ( PLY:IsDriver() ) then
self:LockAntennaSpeed( ant, nil, false )
SYNC:LockAntennaSpeed( ant, RADAR:GetAntennaDataPacket( ant ) )
end
end
end
end
else
@@ -1719,14 +1809,14 @@ Citizen.CreateThread( function()
-- Update the end coordinates for the ray traces based on the config, again, reduced hard coding
RADAR:UpdateRayEndCoords()
-- Update the operator menu positions
RADAR:UpdateOptionIndexes()
-- If the fast limit feature is allowed, create the config in the radar variables
if ( RADAR:IsFastLimitAllowed() ) then
RADAR:CreateFastLimitConfig()
end
-- Update the operator menu positions
RADAR:UpdateOptionIndexes( true )
-- Run the main radar function
while ( true ) do
RADAR:Main()
@@ -1742,7 +1832,7 @@ 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
self:SetDisplayHidden( true )
SendNUIMessage( { _type = "setRadarDisplayState", state = false } )
elseif ( PLY.veh > 0 and PLY.vehClassValid and PLY.inDriverSeat and self:GetDisplayState() and self:GetDisplayHidden() ) then
elseif ( PLY:CanViewRadar() and self:GetDisplayState() and self:GetDisplayHidden() ) then
self:SetDisplayHidden( false )
SendNUIMessage( { _type = "setRadarDisplayState", state = true } )
end
@@ -1764,7 +1854,7 @@ end )
-- Update the vehicle pool every 3 seconds
function RADAR:UpdateVehiclePool()
-- Only update the vehicle pool if we need to
if ( PLY:VehicleStateValid() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
if ( PLY:CanViewRadar() and self:CanPerformMainTask() and self:IsEitherAntennaOn() ) then
-- Get the active vehicle set
local vehs = self:GetAllVehicles()
@@ -1783,60 +1873,3 @@ Citizen.CreateThread( function()
Citizen.Wait( 3000 )
end
end )
Citizen.CreateThread( function()
Citizen.Wait( 3000 )
-- Opens the remote control
RegisterCommand( "radar_remote", function()
if ( not RADAR:GetKeyLockState() ) then
RADAR:OpenRemote()
end
end )
RegisterKeyMapping( "radar_remote", "Open Remote Control", "keyboard", CONFIG.keyDefaults.remote_control )
-- Locks speed from front antenna
RegisterCommand( "radar_fr_ant", function()
if ( not RADAR:GetKeyLockState() ) then
RADAR:LockAntennaSpeed( "front" )
end
end )
RegisterKeyMapping( "radar_fr_ant", "Front Antenna Lock/Unlock", "keyboard", CONFIG.keyDefaults.front_lock )
-- Locks speed from rear antenna
RegisterCommand( "radar_bk_ant", function()
if ( not RADAR:GetKeyLockState() ) then
RADAR:LockAntennaSpeed( "rear" )
end
end )
RegisterKeyMapping( "radar_bk_ant", "Rear Antenna Lock/Unlock", "keyboard", CONFIG.keyDefaults.rear_lock )
-- Locks front plate reader
RegisterCommand( "radar_fr_cam", function()
if ( not RADAR:GetKeyLockState() ) then
READER:LockCam( "front", true, false )
end
end )
RegisterKeyMapping( "radar_fr_cam", "Front Plate Reader Lock/Unlock", "keyboard", CONFIG.keyDefaults.plate_front_lock )
-- Locks rear plate reader
RegisterCommand( "radar_bk_cam", function()
if ( not RADAR:GetKeyLockState() ) then
READER:LockCam( "rear", true, false )
end
end )
RegisterKeyMapping( "radar_bk_cam", "Rear Plate Reader Lock/Unlock", "keyboard", CONFIG.keyDefaults.plate_rear_lock )
-- Toggles the key lock state
RegisterCommand( "radar_key_lock", function()
RADAR:ToggleKeyLock()
end )
RegisterKeyMapping( "radar_key_lock", "Toggle Keybind Lock", "keyboard", CONFIG.keyDefaults.key_lock )
-- Deletes all of the KVPs
RegisterCommand( "reset_radar_data", function()
DeleteResourceKvp( "wk_wars2x_ui_data" )
DeleteResourceKvp( "wk_wars2x_om_data" )
DeleteResourceKvp( "wk_wars2x_new_user" )
end, false )
end )

437
cl_sync.lua Normal file
View File

@@ -0,0 +1,437 @@
--[[---------------------------------------------------------------------------------------
Wraith ARS 2X
Created by WolfKnight
For discussions, information on future updates, and more, join
my Discord: https://discord.gg/fD4e6WD
MIT License
Copyright (c) 2020-2021 WolfKnight
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.
---------------------------------------------------------------------------------------]]--
-- Register the decorator used to tell if the other player has the remote open
DecorRegister( "wk_wars2x_sync_remoteOpen", 2 )
-- Takes the given backup functions and restores the data
local function RestoreData( obj, getFunc, setFunc, setBackupFunc, key )
if ( key ~= nil ) then
local data = getFunc( obj, key )
if ( data ~= nil ) then
setFunc( obj, key, data )
setBackupFunc( obj, key, nil )
end
else
local data = getFunc( obj )
if ( data ~= nil ) then
setFunc( obj, data )
setBackupFunc( obj, nil )
end
end
end
--[[----------------------------------------------------------------------------------
Plate reader sync variables and functions
----------------------------------------------------------------------------------]]--
-- Declares a table that is used to backup the player's plate reader data
READER.backupData =
{
cams = {
["front"] = nil,
["rear"] = nil
}
}
-- Returns a table with the front and rear plate reader data
function READER:GetReaderDataForSync()
return {
["front"] = self.vars.cams["front"],
["rear"] = self.vars.cams["rear"]
}
end
-- Sets the internal plate reader data for the given camera
function READER:SetReaderCamData( cam, data )
if ( type( data ) == "table" ) then
self.vars.cams[cam] = data
end
end
-- Getter and setter for the backup plate reader data
function READER:GetBackupReaderData( cam ) return self.backupData.cams[cam] end
function READER:SetBackupReaderData( cam, data ) self.backupData.cams[cam] = data end
-- Returns if there is any backup data for the plate reader
function READER:IsThereBackupData()
return self:GetBackupReaderData( "front" ) ~= nil or self:GetBackupReaderData( "rear" ) ~= nil
end
-- Backs up the player's plate reader data
function READER:BackupData()
-- Get the player's data
local data = self:GetReaderDataForSync()
-- Iterate through the front and rear camera
for cam in UTIL:Values( { "front", "rear" } ) do
-- Check that there isn't already backup data, then if not, back up the player's data
if ( self:GetBackupReaderData( cam ) == nil ) then
self:SetBackupReaderData( cam, data[cam] )
end
end
end
-- Replaces the internal plate reader data with the data provided
function READER:LoadDataFromDriver( data )
-- Backup the local data first
self:BackupData()
-- As a precaution, give the system 50ms before it replaces the local data with the data from the driver
Citizen.SetTimeout( 50, function()
-- Set the camera data
for cam in UTIL:Values( { "front", "rear" } ) do
self:SetReaderCamData( cam, data[cam] )
end
-- Force the NUI side to update the plate reader display with the new data
self:ForceNUIUpdate( true )
end )
end
-- Restores the backed up plate reader data
function READER:RestoreFromBackup()
-- Iterate through the cameras and restore their backups
for cam in UTIL:Values( { "front", "rear" } ) do
RestoreData( READER, READER.GetBackupReaderData, READER.SetReaderCamData, READER.SetBackupReaderData, cam )
end
-- Force the NUI side to update the plate reader display with the restored data
self:ForceNUIUpdate( true )
end
--[[----------------------------------------------------------------------------------
Radar sync variables and functions
----------------------------------------------------------------------------------]]--
-- Declares a table that is used to backup the player's radar data
RADAR.backupData = {
power = nil,
om = nil,
antennas = {
["front"] = nil,
["rear"] = nil
}
}
-- Returns a table with the power state, operator meny, front and rear radar data
function RADAR:GetRadarDataForSync()
return {
power = self.vars.power,
om = self.vars.settings,
["front"] = self.vars.antennas["front"],
["rear"] = self.vars.antennas["rear"]
}
end
-- Returns the radar's internal operator menu settings table
function RADAR:GetOMTableData() return self.vars.settings end
-- Sets the operator menu settings table within the radar's main variables table
function RADAR:SetOMTableData( data )
if ( type( data ) == "table" ) then
self.vars.settings = data
self:UpdateOptionIndexes( false )
end
end
-- Sets the antenna settings table for the given antenna within the radar's main variables table
function RADAR:SetAntennaTableData( ant, data )
if ( type( data ) == "table" ) then
self.vars.antennas[ant] = data
end
end
-- Getter and setter for the backup radar power state
function RADAR:GetBackupPowerState() return self.backupData.power end
function RADAR:SetBackupPowerState( state ) self.backupData.power = state end
-- Getter and setter for the backup radar operator menu data
function RADAR:GetBackupOMData() return self.backupData.om end
function RADAR:SetBackupOMData( data ) self.backupData.om = data end
-- Getter and setter for the backup radar antennas data
function RADAR:GetBackupAntennaData( ant ) return self.backupData.antennas[ant] end
function RADAR:SetBackupAntennaData( ant, data ) self.backupData.antennas[ant] = data end
-- Retuns if there is any backup radar data
function RADAR:IsThereBackupData()
return self:GetBackupOMData() ~= nil or self:GetBackupAntennaData( "front" ) ~= nil or self:GetBackupAntennaData( "rear" ) ~= nil
end
-- Used when the player becomes a passenger in another vehicle. The local data is backed up to make way for the data
-- provided by the driver. When the player becomes the driver again, the local data is restored.
function RADAR:BackupData()
local data = self:GetRadarDataForSync()
-- Backup the power state
if ( self:GetBackupPowerState() == nil ) then
self:SetBackupPowerState( data.power )
end
-- Backup operator menu data
if ( self:GetBackupOMData() == nil ) then
self:SetBackupOMData( data.om )
end
-- Only backup the radar data if the player has the power on. There's no point backing up the data as it'll just
-- get reset when they turn the power on anyway
if ( data.power ) then
-- Backup front and rear antenna data
for ant in UTIL:Values( { "front", "rear" } ) do
if ( self:GetBackupAntennaData( ant ) == nil ) then
self:SetBackupAntennaData( ant, data[ant] )
end
end
end
end
-- Backs up the local radar data and then replaces it with the data provided by the driver
function RADAR:LoadDataFromDriver( data )
-- Backup the local data first
self:BackupData()
-- As a precaution, give the system 50ms before it replaces the local data with the data from the driver
Citizen.SetTimeout( 50, function()
-- Set the operator menu settings
self:SetOMTableData( data.om )
-- Set the antenna data
for ant in UTIL:Values( { "front", "rear" } ) do
self:SetAntennaTableData( ant, data[ant] )
end
-- Set the power state
self:SetPowerState( data.power, true )
-- Update the display
if ( data.power ) then
self:SendSettingUpdate()
end
end )
end
-- Restores the local player's operator menu and antenna data
function RADAR:RestoreFromBackup()
-- Restore the operator menu data
RestoreData( RADAR, RADAR.GetBackupOMData, RADAR.SetOMTableData, RADAR.SetBackupOMData )
-- Iterate through the antennas and restore their backups
for ant in UTIL:Values( { "front", "rear" } ) do
RestoreData( RADAR, RADAR.GetBackupAntennaData, RADAR.SetAntennaTableData, RADAR.SetBackupAntennaData, ant )
end
-- Get the power state
local pwrState = self:GetBackupPowerState()
-- Restore the power state
if ( pwrState ~= nil ) then
self:SetPowerState( pwrState, true )
self:SetBackupPowerState( nil )
end
-- Update the display
if ( pwrState ) then
Citizen.SetTimeout( 50, function()
self:SendSettingUpdate()
end )
end
end
--[[----------------------------------------------------------------------------------
Sync variables
----------------------------------------------------------------------------------]]--
SYNC = {}
--[[----------------------------------------------------------------------------------
Sync functions
----------------------------------------------------------------------------------]]--
-- Returns if the given player has the remote open
function SYNC:IsRemoteAlreadyOpen( ply )
if ( not RADAR:IsPassengerViewAllowed() ) then
return false
else
return DecorGetBool( ply, "wk_wars2x_sync_remoteOpen" )
end
end
-- Sets the remote open decor for the local player to the given state
function SYNC:SetRemoteOpenState( state )
if ( RADAR:IsPassengerViewAllowed() ) then
DecorSetBool( PLY.ped, "wk_wars2x_sync_remoteOpen", state )
end
end
-- Used to get the other ped (driver/passenger) in a vehicle and calls the given callback. This function will only work
-- if the player can control the radar, it also ensures that the other ped (if found) exists and is a player. The other
-- player's server ID is passed to the given callback as an argument.
function SYNC:SyncData( cb )
if ( PLY:CanControlRadar() ) then
local otherPly = PLY:GetOtherPedServerId()
if ( otherPly ~= nil ) then
cb( otherPly )
end
end
end
-- Sends the radar's power state to the other player (driver/passenger)
function SYNC:SendPowerState( state )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendPowerState", ply, state )
end )
end
-- Sends the power state for the given antenna to the other player (driver/passenger)
function SYNC:SendAntennaPowerState( state, ant )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendAntennaPowerState", ply, state, ant )
end )
end
-- Sends the mode for the given antenna to the other player (driver/passenger)
function SYNC:SendAntennaMode( ant, mode )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendAntennaMode", ply, ant, mode )
end )
end
-- Sends a lock/unlock state, as well as the current player's displayed data to the other player (driver/passenger)
function SYNC:LockAntennaSpeed( ant, data )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendLockAntennaSpeed", ply, ant, data )
end )
end
-- Sends the given operator menu table data to the other player
function SYNC:SendUpdatedOMData( data )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendUpdatedOMData", ply, data )
end )
end
-- Sends the plate reader lock event with the data from the reader that was locked
function SYNC:LockReaderCam( cam, data )
self:SyncData( function( ply )
TriggerServerEvent( "wk_wars2x_sync:sendLockCameraPlate", ply, cam, data )
end )
end
-- Requests radar data from the driver if the player has just entered a valid vehicle as a front seat passenger
function SYNC:SyncDataOnEnter()
-- Make sure passenger view is allowed, also, using PLY:IsPassenger() already checks that the player's
-- vehicle meets the requirements of what the radar requires. This way we don't have to do additional
-- checks manually.
if ( PLY:IsPassenger() ) then
local driver = PLY:GetOtherPedServerId()
-- Only trigger the event if there is actually a driver
if ( driver ~= nil ) then
TriggerServerEvent( "wk_wars2x_sync:requestRadarData", driver )
end
elseif ( PLY:IsDriver() ) then
if ( RADAR:IsThereBackupData() ) then
-- Restore the local data
RADAR:RestoreFromBackup()
READER:RestoreFromBackup()
end
end
end
--[[----------------------------------------------------------------------------------
Sync client events
----------------------------------------------------------------------------------]]--
-- Event for receiving the radar powet state
RegisterNetEvent( "wk_wars2x_sync:receivePowerState" )
AddEventHandler( "wk_wars2x_sync:receivePowerState", function( state )
-- Set the radar's power
RADAR:SetPowerState( state, false )
end )
-- Event for receiving a power state for the given antenna
RegisterNetEvent( "wk_wars2x_sync:receiveAntennaPowerState" )
AddEventHandler( "wk_wars2x_sync:receiveAntennaPowerState", function( state, antenna )
-- Get the current local antenna power state
local power = RADAR:IsAntennaTransmitting( antenna )
-- If the local power state is not the same as the given state, toggle the antenna's power
if ( power ~= state ) then
RADAR:ToggleAntenna( antenna )
end
end )
-- Event for receiving a mode for the given antenna
RegisterNetEvent( "wk_wars2x_sync:receiveAntennaMode" )
AddEventHandler( "wk_wars2x_sync:receiveAntennaMode", function( antenna, mode )
RADAR:SetAntennaMode( antenna, mode )
end )
-- Event for receiving a lock state and speed data for the given antenna
RegisterNetEvent( "wk_wars2x_sync:receiveLockAntennaSpeed" )
AddEventHandler( "wk_wars2x_sync:receiveLockAntennaSpeed", function( antenna, data )
RADAR:LockAntennaSpeed( antenna, data, true )
end )
RegisterNetEvent( "wk_wars2x_sync:receiveLockCameraPlate" )
AddEventHandler( "wk_wars2x_sync:receiveLockCameraPlate", function( camera, data )
READER:LockCam( camera, true, false, data )
end )
-- Event for gathering the radar data and sending it to another player
RegisterNetEvent( "wk_wars2x_sync:getRadarDataFromDriver" )
AddEventHandler( "wk_wars2x_sync:getRadarDataFromDriver", function( playerFor )
local radarData = RADAR:GetRadarDataForSync()
local readerData = READER:GetReaderDataForSync()
TriggerServerEvent( "wk_wars2x_sync:sendRadarDataForPassenger", playerFor, { radarData, readerData } )
end )
-- Event for receiving radar data from another player
RegisterNetEvent( "wk_wars2x_sync:receiveRadarData" )
AddEventHandler( "wk_wars2x_sync:receiveRadarData", function( data )
RADAR:LoadDataFromDriver( data[1] )
READER:LoadDataFromDriver( data[2] )
end )
-- Event for receiving updated operator menu data from another player
RegisterNetEvent( "wk_wars2x_sync:receiveUpdatedOMData" )
AddEventHandler( "wk_wars2x_sync:receiveUpdatedOMData", function( data )
if ( PLY:IsDriver() or ( PLY:IsPassenger() and RADAR:IsThereBackupData() ) ) then
RADAR:SetOMTableData( data )
RADAR:SendSettingUpdate()
end
end )

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -110,6 +110,19 @@ function UTIL:GetEntityRelativeDirection( myAng, tarAng )
return 0
end
-- Returns if there is a player in the given vehicle
function UTIL:IsPlayerInVeh( veh )
for i = -1, GetVehicleMaxNumberOfPassengers( veh ) + 1, 1 do
local ped = GetPedInVehicleSeat( veh, i )
if ( DoesEntityExist( ped ) ) then
if ( IsPedAPlayer( ped ) ) then return true end
end
end
return false
end
-- Your everyday GTA notification function
function UTIL:Notify( text )
SetNotificationTextEntry( "STRING" )
@@ -117,10 +130,12 @@ function UTIL:Notify( text )
DrawNotification( false, true )
end
-- Prints the given message to the client console
function UTIL:Log( msg )
print( "[Wraith ARS 2X]: " .. msg )
end
-- Used to draw text to the screen, helpful for debugging issues
function UTIL:DrawDebugText( x, y, scale, centre, text )
SetTextFont( 4 )
SetTextProportional( 0 )
@@ -136,6 +151,11 @@ function UTIL:DrawDebugText( x, y, scale, centre, text )
DrawText( x, y )
end
-- Returns if the current resource name is valid
function UTIL:IsResourceNameValid()
return GetCurrentResourceName() == "wk_wars2x"
end
--[[The MIT License (MIT)
Copyright (c) 2017 IllidanS4

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -36,13 +36,29 @@ CONFIG = {}
-- Radar fast limit locking
-- When enabled, the player will be able to define a fast limit within the radar's menu, when a vehicle
-- exceeds the fast limit, it will be locked into the fast box. Default setting is disabled to maintain realism
CONFIG.allow_fast_limit = false
CONFIG.allow_fast_limit = true
-- Radar only lock players with auto fast locking
-- When enabled, the radar will only automatically lock a speed if the caught vehicle has a real player in it.
CONFIG.only_lock_players = false
-- In-game first time quick start video
-- When enabled, the player will be asked if they'd like to view the quick start video the first time they
-- open the remote.
CONFIG.allow_quick_start_video = true
-- Allow passenger view
-- When enabled, the front seat passenger will be able to view the radar and plate reader from their end.
CONFIG.allow_passenger_view = false
-- Allow passenger control
-- Dependent on CONFIG.allow_passenger_view. When enabled, the front seat passenger will be able to open the
-- radar remote and control the radar and plate reader for themself and the driver.
CONFIG.allow_passenger_control = false
-- Set this to true if you use Sonoran CAD with the WraithV2 plugin
CONFIG.use_sonorancad = false
-- Sets the defaults of all keybinds
-- These keybinds can be changed by each person in their GTA Settings->Keybinds->FiveM
CONFIG.keyDefaults =
@@ -93,7 +109,15 @@ CONFIG.menuDefaults =
-- The speed unit used in conversions
-- Options: mph or kmh
["speedType"] = "mph"
["speedType"] = "mph",
-- The state for automatic speed locking. This requires CONFIG.allow_fast_limit to be true.
-- Options: true or false
["fastLock"] = false,
-- The speed limit required for automatic speed locking. This requires CONFIG.allow_fast_limit to be true.
-- Options: 0 to 200
["fastLimit"] = 60
}
-- Here you can change the default scale of the UI elements, as well as the safezone size
@@ -103,9 +127,9 @@ CONFIG.uiDefaults =
-- Options: 0.25 - 2.5
scale =
{
radar = 1.0,
remote = 1.0,
plateReader = 1.0
radar = 0.75,
remote = 0.75,
plateReader = 0.75
},
-- The safezone size, must be a multiple of 5.

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -31,20 +31,19 @@
---------------------------------------------------------------------------------------]]--
-- Define the FX Server version and game type
fx_version "bodacious"
fx_version "cerulean"
game "gta5"
-- Define the resource metadata
name "Wraith ARS 2X"
description "Police radar and plate reader system for FiveM"
author "WolfKnight"
version "1.2.4"
version "1.3.0"
-- Include the files
files {
"nui/radar.html",
"nui/radar.css",
"nui/jquery-3.4.1.min.js",
"nui/radar.js",
"nui/images/*.png",
"nui/images/plates/*.png",
@@ -59,10 +58,13 @@ ui_page "nui/radar.html"
-- Run the server scripts
server_script "sv_version_check.lua"
server_script "sv_exports.lua"
server_script "sv_sync.lua"
server_export "TogglePlateLock"
-- Run the client scripts
client_script "config.lua"
client_script "cl_utils.lua"
client_script "cl_player.lua"
client_script "cl_radar.lua"
client_script "cl_plate_reader.lua"
client_script "cl_sync.lua"

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -159,6 +159,14 @@ button:focus { outline: none; }
color: rgb(255, 255, 0);
}
.green {
color: rgb( 0, 255, 0 );
}
.red {
color: rgb( 255, 0, 0 );
}
.arrow {
width: 11px;
height: 15.4px;
@@ -770,7 +778,7 @@ button:focus { outline: none; }
#plateReaderBox {
width: 225px;
height: 300px;
height: 330px;
position: absolute;
margin: auto;

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -245,6 +245,8 @@
<input id="boloText" type="text" maxlength="8" placeholder="12ABC345" onkeypress="checkPlateInput(event)" class="plate_input"/>
<button id="setBoloPlate" class="btn">Set BOLO Plate</button>
<button id="clearBoloPlate" class="btn">Clear BOLO Plate</button>
</div>
<button id="closePlateReaderSettings" class="close">CLOSE</button>
@@ -298,7 +300,7 @@
<button id="closeUiSettings" class="close">CLOSE</button>
</div>
<p id="keyLockLabel">Radar key lock <span id="keyLockStateLabel"></span></p>
<p id="keyLockLabel">Radar key binds <span id="keyLockStateLabel"></span></p>
<div id="helpWindow">
<iframe id="helpWeb" src="about:blank"></iframe>
@@ -317,7 +319,7 @@
</div>
<!-- Load JavaScript files -->
<script src="jquery-3.4.1.min.js"></script>
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
<script src="radar.js"></script>
</body>
</html>

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -33,7 +33,6 @@
/*------------------------------------------------------------------------------------
Variables
------------------------------------------------------------------------------------*/
var resourceName;
var uiEdited = false;
// All of the audio file names
@@ -90,6 +89,7 @@ const elements =
plateReaderBox: $( "#plateReaderBox" ),
boloText: $( "#boloText" ),
setBoloBtn: $( "#setBoloPlate" ),
clearBoloBtn: $( "#clearBoloPlate" ),
closePrBtn: $( "#closePlateReaderSettings" ),
openHelp: $( "#helpBtn" ),
@@ -494,7 +494,7 @@ function poweringUp()
}
// Simulates the 'fully powered' state of the radar unit
function poweredUp()
function poweredUp( fastDisplay )
{
// Completely clear everything
clearEverything();
@@ -505,14 +505,14 @@ function poweredUp()
// Even though the clearEverything() function is called above, we run this so the fast window
// displays 'HLd'
setAntennaXmit( ant, false );
setAntennaFastMode( ant, true );
setAntennaFastMode( ant, fastDisplay );
}
}
// Runs the startup process or clears everything, the Lua side calls for the full powered up state
function radarPower( state )
function radarPower( state, override, fastDisplay )
{
state ? poweringUp() : clearEverything();
state ? ( override ? poweredUp( fastDisplay ) : poweringUp() ) : clearEverything();
}
@@ -605,17 +605,27 @@ function menu( optionText, option )
elements.patrolSpeed.html( option );
}
var keyLockTimeout;
// Makes the key lock label fade in then fade out after 2 seconds
function displayKeyLock( state )
{
let sl = elements.keyLock.stateLabel;
// Set the state label text to enabled or disabled
elements.keyLock.stateLabel.html( state ? "enabled" : "disabled" );
sl.html( state ? "blocked" : "enabled" );
// Change the colour of the altered text
state ? sl.addClass( "red" ).removeClass( "green" ) : sl.addClass( "green" ).removeClass( "red" );
// Fade in the label
elements.keyLock.label.fadeIn();
// Clear the timeout if it already exists
clearTimeout( keyLockTimeout );
// Make the label fade out after 2 seconds
setTimeout( function() {
keyLockTimeout = setTimeout( function() {
elements.keyLock.label.fadeOut();
}, 2000 );
}
@@ -629,7 +639,7 @@ $.ajaxSetup({
// This function is used to send data back through to the LUA side
function sendData( name, data ) {
$.post( "https://" + resourceName + "/" + name, JSON.stringify( data ), function( datab ) {
$.post( "https://wk_wars2x/" + name, JSON.stringify( data ), function( datab ) {
if ( datab != "ok" ) {
console.log( datab );
}
@@ -767,6 +777,11 @@ elements.setBoloBtn.click( function() {
}
} )
// Sets the on click function for the clear BOLO button
elements.clearBoloBtn.click( function() {
sendData( "clearBoloPlate", null );
} )
// Checks what the user is typing into the plate box
function checkPlateInput( event )
{
@@ -1077,9 +1092,6 @@ window.addEventListener( "message", function( event ) {
switch ( type ) {
// System events
case "updatePathName":
resourceName = item.pathName
break;
case "loadUiSettings":
loadUiSettings( item.data, true );
break;
@@ -1102,10 +1114,10 @@ window.addEventListener( "message", function( event ) {
setEleVisible( elements.radar, item.state );
break;
case "radarPower":
radarPower( item.state );
radarPower( item.state, item.override, item.fast );
break;
case "poweredUp":
poweredUp();
poweredUp( item.fast );
break;
case "update":
updateDisplays( item.speed, item.antennas );

78
sv_sync.lua Normal file
View File

@@ -0,0 +1,78 @@
--[[---------------------------------------------------------------------------------------
Wraith ARS 2X
Created by WolfKnight
For discussions, information on future updates, and more, join
my Discord: https://discord.gg/fD4e6WD
MIT License
Copyright (c) 2020-2021 WolfKnight
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.
---------------------------------------------------------------------------------------]]--
--[[----------------------------------------------------------------------------------
Sync server events
----------------------------------------------------------------------------------]]--
RegisterNetEvent( "wk_wars2x_sync:sendPowerState" )
AddEventHandler( "wk_wars2x_sync:sendPowerState", function( target, state )
TriggerClientEvent( "wk_wars2x_sync:receivePowerState", target, state )
end )
RegisterNetEvent( "wk_wars2x_sync:sendAntennaPowerState" )
AddEventHandler( "wk_wars2x_sync:sendAntennaPowerState", function( target, state, ant )
TriggerClientEvent( "wk_wars2x_sync:receiveAntennaPowerState", target, state, ant )
end )
RegisterNetEvent( "wk_wars2x_sync:sendAntennaMode" )
AddEventHandler( "wk_wars2x_sync:sendAntennaMode", function( target, ant, mode )
TriggerClientEvent( "wk_wars2x_sync:receiveAntennaMode", target, ant, mode )
end )
RegisterNetEvent( "wk_wars2x_sync:sendLockAntennaSpeed" )
AddEventHandler( "wk_wars2x_sync:sendLockAntennaSpeed", function( target, ant, data )
TriggerClientEvent( "wk_wars2x_sync:receiveLockAntennaSpeed", target, ant, data )
end )
RegisterNetEvent( "wk_wars2x_sync:sendLockCameraPlate" )
AddEventHandler( "wk_wars2x_sync:sendLockCameraPlate", function( target, cam, data )
TriggerClientEvent( "wk_wars2x_sync:receiveLockCameraPlate", target, cam, data )
end )
--[[----------------------------------------------------------------------------------
Radar data sync server events
----------------------------------------------------------------------------------]]--
RegisterNetEvent( "wk_wars2x_sync:requestRadarData" )
AddEventHandler( "wk_wars2x_sync:requestRadarData", function( target )
TriggerClientEvent( "wk_wars2x_sync:getRadarDataFromDriver", target, source )
end )
RegisterNetEvent( "wk_wars2x_sync:sendRadarDataForPassenger" )
AddEventHandler( "wk_wars2x_sync:sendRadarDataForPassenger", function( playerFor, data )
TriggerClientEvent( "wk_wars2x_sync:receiveRadarData", playerFor, data )
end )
RegisterNetEvent( "wk_wars2x_sync:sendUpdatedOMData" )
AddEventHandler( "wk_wars2x_sync:sendUpdatedOMData", function( playerFor, data )
TriggerClientEvent( "wk_wars2x_sync:receiveUpdatedOMData", playerFor, data )
end )

View File

@@ -8,7 +8,7 @@
MIT License
Copyright (c) 2020 WolfKnight
Copyright (c) 2020-2021 WolfKnight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -34,12 +34,10 @@
local label =
[[
//
|| __ __ _ _ _ _____ _____ ___ __ __
|| \ \ / / (_) | | | /\ | __ \ / ____| |__ \\ \ / /
|| \ \ /\ / / __ __ _ _| |_| |__ / \ | |__) | (___ ) |\ V /
|| \ \/ \/ / '__/ _` | | __| '_ \ / /\ \ | _ / \___ \ / / > <
|| \ /\ /| | | (_| | | |_| | | | / ____ \| | \ \ ____) | / /_ / . \
|| \/ \/ |_| \__,_|_|\__|_| |_| /_/ \_\_| \_\_____/ |____/_/ \_\
|| __ __ _ _ _ _ ___ ___ _____ __
|| \ \ / / _ __ _(_) |_| |_ /_\ | _ \/ __| |_ ) \/ /
|| \ \/\/ / '_/ _` | | _| ' \ / _ \| /\__ \ / / > <
|| \_/\_/|_| \__,_|_|\__|_||_| /_/ \_\_|_\|___/ /___/_/\_\
||
|| Created by WolfKnight
||]]
@@ -60,9 +58,10 @@ PerformHttpRequest( "https://wolfknight98.github.io/wk_wars2x_web/version.txt",
-- Get the current resource version
local curVer = GetCurrentVersion()
if ( text ~= nil ) then
-- Print out the current and latest version
print( " || Current version: " .. curVer )
if ( text ~= nil ) then
-- Print latest version
print( " || Latest recommended version: " .. text .."\n ||" )
-- If the versions are different, print it out
@@ -73,6 +72,11 @@ PerformHttpRequest( "https://wolfknight98.github.io/wk_wars2x_web/version.txt",
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" )
print( " || ^1There was an error getting the latest version information.\n^0 ||\n \\\\\n" )
end
-- Warn the console if the resource has been renamed, as this will cause issues with the resource's functionality.
if ( GetCurrentResourceName() ~= "wk_wars2x" ) then
print( "^1ERROR: Resource name is not wk_wars2x, expect there to be issues with the resource. To ensure there are no issues, please leave the resource name as wk_wars2x^0\n\n" )
end
end )