From d491dc50e4686855cf5e649ea62816f0a29b2bbe Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 5 Mar 2020 19:40:37 +0000 Subject: [PATCH] 1.0.0! - Added a server export to toggle plate lock on a client - Removed old and redundant code - Added the licence to the top of every file - Added a small section at the bottom of config.lua to set the default UI element scale, as well as the safezone - Changed the height of the UI settings box to stop the slider and close button from overlapping - Added the ability to disable server console messages - Formatted all code to tab size 4! --- cl_plate_reader.lua | 255 +++++++------ cl_radar.lua | 323 ++++++++-------- cl_utils.lua | 29 +- config.lua | 166 +++++--- fxmanifest.lua | 51 ++- nui/radar.css | 735 ++++++++++++++++++----------------- nui/radar.html | 205 +++++----- nui/radar.js | 888 +++++++++++++++++++++++-------------------- sv_exports.lua | 50 +++ sv_saving.lua | 39 +- sv_version_check.lua | 31 +- 11 files changed, 1569 insertions(+), 1203 deletions(-) create mode 100644 sv_exports.lua diff --git a/cl_plate_reader.lua b/cl_plate_reader.lua index c83e1c8..8043c88 100644 --- a/cl_plate_reader.lua +++ b/cl_plate_reader.lua @@ -1,9 +1,34 @@ ---[[----------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- READER = {} @@ -15,32 +40,32 @@ READER = {} ----------------------------------------------------------------------------------]]-- READER.vars = { - -- Whether or not the plate reader's UI is visible + -- Whether or not the plate reader's UI is visible displayed = false, -- Whether or not the plate reader should be hidden, e.g. the display is active but the player then steps -- out of their vehicle - hidden = false, + hidden = false, - -- The BOLO plate - boloPlate = "", - - -- Cameras, this table contains all of the data needed for operation of the front and rear plate reader - cams = { - -- Variables for the front camera - ["front"] = { - plate = "", -- The current plate caught by the reader - index = "", -- The index of the current plate - locked = false -- If the reader is locked - }, + -- The BOLO plate + boloPlate = "", + + -- Cameras, this table contains all of the data needed for operation of the front and rear plate reader + cams = { + -- Variables for the front camera + ["front"] = { + plate = "", -- The current plate caught by the reader + index = "", -- The index of the current plate + locked = false -- If the reader is locked + }, - -- Variables for the rear camera - ["rear"] = { - plate = "", -- The current plate caught by the reader - index = "", -- The index of the current plate - locked = false -- If the reader is locked - } - } + -- Variables for the rear camera + ["rear"] = { + plate = "", -- The current plate caught by the reader + index = "", -- The index of the current plate + locked = false -- If the reader is locked + } + } } -- Gets the display state @@ -69,75 +94,85 @@ end -- Returns the stored plate for the given reader function READER:GetPlate( cam ) - return self.vars.cams[cam].plate + 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 + 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 + 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 + self.vars.cams[cam].index = index end -- Returns the bolo plate function READER:GetBoloPlate() - return self.vars.boloPlate + return self.vars.boloPlate end -- Sets the bolo plate to the given plate function READER:SetBoloPlate( plate ) - self.vars.boloPlate = plate - UTIL:Notify( "BOLO plate set to: " .. plate ) + self.vars.boloPlate = plate + UTIL:Notify( "BOLO plate set to: " .. plate ) end -- Returns if the given reader is locked function READER:GetCamLocked( cam ) - return self.vars.cams[cam].locked + return self.vars.cams[cam].locked end -- Locks the given reader -function READER:LockCam( cam, playAudio, isBolo ) - -- Check that plate readers can actually be locked - if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then - -- Toggle the lock state - self.vars.cams[cam].locked = not self.vars.cams[cam].locked +function READER:LockCam( cam, playBeep, isBolo ) + -- Check that plate readers can actually be locked + if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) 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 } ) + -- 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 - if ( playAudio ) then - SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "plateAudio" ) } ) - end - - TriggerEvent( "wk:onPlateLocked", cam, self:GetPlate( cam ), self:GetIndex( cam ) ) + if ( self:GetCamLocked( cam ) ) then + if ( playBeep ) then + SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "plateAudio" ) } ) + end + + if ( isBolo ) then + SendNUIMessage( { _type = "audio", name = "plate_hit", vol = RADAR:GetSettingValue( "plateAudio" ) } ) + end + + -- 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 - end + end end -- Returns if the plate reader system can perform tasks function READER:CanPerformMainTask() - return self.vars.displayed and not self.vars.hidden + return self.vars.displayed and not self.vars.hidden end -- Returns if the given relative position value is for front or rear function READER:GetCamFromNum( relPos ) - if ( relPos == 1 ) then - return "front" - elseif ( relPos == -1 ) then - return "rear" - end + if ( relPos == 1 ) then + return "front" + elseif ( relPos == -1 ) then + return "rear" + end end +RegisterNetEvent( "wk:togglePlateLock" ) +AddEventHandler( "wk:togglePlateLock", function( cam, beep, bolo ) + READER:LockCam( cam, beep, bolo ) +end ) + -- Runs when the "Toggle Display" button is pressed on the plate reder box RegisterNUICallback( "togglePlateReaderDisplay", function() -- Toggle the display state @@ -146,85 +181,85 @@ 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 ) + -- Set the BOLO plate + READER:SetBoloPlate( plate ) end ) -- 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 - if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then - -- Loop through front (1) and rear (-1) - for i = 1, -1, -2 do - -- Get the world position of the player's vehicle - local pos = GetEntityCoords( PLY.veh ) + -- Check that the system can actually run + if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then + -- Loop through front (1) and rear (-1) + for i = 1, -1, -2 do + -- Get the world position of the player's vehicle + 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 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 ) + -- Get the end position 50m 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 ) + -- Run the ray trace to get a vehicle + local veh = UTIL:GetVehicleInDirection( PLY.veh, start, offset ) - -- Get the plate reader text for front/rear - 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 - -- Get the heading of the player's vehicle and the hit vehicle - local ownH = UTIL:Round( GetEntityHeading( PLY.veh ), 0 ) - local tarH = UTIL:Round( GetEntityHeading( veh ), 0 ) + -- Get the plate reader text for front/rear + 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 + -- Get the heading of the player's vehicle and the hit vehicle + local ownH = UTIL:Round( GetEntityHeading( PLY.veh ), 0 ) + local tarH = UTIL:Round( GetEntityHeading( veh ), 0 ) - -- Get the relative direction between the player's vehicle and the hit vehicle - local dir = UTIL:GetEntityRelativeDirection( ownH, tarH ) + -- Get the relative direction between the player's vehicle and the hit vehicle + local dir = UTIL:GetEntityRelativeDirection( ownH, tarH ) - -- Only run the rest of the plate check code if we can see the front or rear of the vehicle - if ( dir > 0 ) then - -- Get the licence plate text from the vehicle - local plate = GetVehicleNumberPlateText( veh ) + -- Only run the rest of the plate check code if we can see the front or rear of the vehicle + if ( dir > 0 ) then + -- Get the licence plate text from the vehicle + local plate = GetVehicleNumberPlateText( veh ) - -- Get the licence plate index from the vehicle - local index = GetVehicleNumberPlateTextIndex( veh ) + -- Get the licence plate index from the vehicle + 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 - -- Set the plate for the current reader - self:SetPlate( cam, plate ) + -- 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 + -- Set the plate for the current reader + self:SetPlate( cam, plate ) - -- Set the plate index for the current reader - self:SetIndex( cam, index ) + -- Set the plate index for the current reader + self:SetIndex( cam, index ) - -- Automatically lock the plate if the scanned plate matches the BOLO - if ( plate == self:GetBoloPlate() ) then - self:LockCam( cam, false, true ) + -- Automatically lock the plate if the scanned plate matches the BOLO + if ( plate == self:GetBoloPlate() ) then + self:LockCam( cam, false, true ) - SendNUIMessage( { _type = "audio", name = "plate_hit", vol = RADAR:GetSettingValue( "plateAudio" ) } ) - end + -- SendNUIMessage( { _type = "audio", name = "plate_hit", vol = RADAR:GetSettingValue( "plateAudio" ) } ) + end - -- Send the plate information to the NUI side to update the UI - SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } ) + -- Send the plate information to the NUI side to update the UI + SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } ) - -- Trigger the event so developers can hook into the scanner - TriggerEvent( "wk:onPlateScanned", cam, plate, index ) - end - end - end - end - end + -- Trigger the event so developers can hook into the scanner every time a plate is scanned + TriggerServerEvent( "wk:onPlateScanned", cam, plate, index ) + end + end + end + end + end end -- Main thread Citizen.CreateThread( function() - while ( true ) do - -- Run the main plate reader function - READER:Main() + while ( true ) do + -- Run the main plate reader function + READER:Main() - -- Wait half a second - Citizen.Wait( 500 ) - end + -- Wait half a second + Citizen.Wait( 500 ) + end end ) -- This function is pretty much straight from WraithRS, it does the job so I didn't see the point in not @@ -244,11 +279,11 @@ end Citizen.CreateThread( function() Citizen.Wait( 100 ) - while ( true ) do - -- Run the check + while ( true ) do + -- Run the check READER:RunDisplayValidationCheck() - -- Wait half a second + -- Wait half a second Citizen.Wait( 500 ) end end ) \ No newline at end of file diff --git a/cl_radar.lua b/cl_radar.lua index b415ec7..564a1be 100644 --- a/cl_radar.lua +++ b/cl_radar.lua @@ -1,9 +1,34 @@ ---[[---------------------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- -- Cache some of the main Lua functions and libraries local next = next @@ -23,7 +48,7 @@ Citizen.SetTimeout( 1000, function() local name = GetCurrentResourceName() -- Print a little message in the client's console - print( "WK_WARS2X: Sending resource name (" .. name .. ") to JavaScript side." ) + print( "[wk_wars2x]: Sending resource name (" .. name .. ") to JavaScript side." ) -- Send a message through the NUI system to the JavaScript file to give the name of the resource SendNUIMessage( { _type = "updatePathName", pathName = name } ) @@ -51,6 +76,12 @@ AddEventHandler( "wk:loadUiData", function( data ) SendNUIMessage( { _type = "loadUiSettings", data = data } ) end ) +RegisterNetEvent( "wk:setUiDefaults" ) +AddEventHandler( "wk:setUiDefaults", function() + SendNUIMessage( { _type = "setUiDefaults", data = CONFIG.uiDefaults } ) +end ) + + --[[---------------------------------------------------------------------------------- Player info variables ----------------------------------------------------------------------------------]]-- @@ -116,10 +147,10 @@ RADAR.vars = ["beep"] = CONFIG.menuDefaults["beep"], -- The volume of the verbal lock confirmation - ["voice"] = CONFIG.menuDefaults["voice"], - - -- The volume of the plate reader audio - ["plateAudio"] = CONFIG.menuDefaults["plateAudio"], + ["voice"] = CONFIG.menuDefaults["voice"], + + -- The volume of the plate reader audio + ["plateAudio"] = CONFIG.menuDefaults["plateAudio"], -- The speed unit used in conversions ["speedType"] = CONFIG.menuDefaults["speedType"] @@ -134,8 +165,8 @@ RADAR.vars = { displayText = { "¦SL", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = -1, settingText = "same" }, { displayText = { "¦OP", "SEn" }, optionsText = { "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = -1, 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 = -1, 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 = -1, settingText = "voice" }, - { displayText = { "PLt", "AUd" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = -1, settingText = "plateAudio" }, + { displayText = { "VOI", "CE¦" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = -1, settingText = "voice" }, + { displayText = { "PLt", "AUd" }, optionsText = { "Off", "¦1¦", "¦2¦", "¦3¦", "¦4¦", "¦5¦" }, options = { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }, optionIndex = -1, settingText = "plateAudio" }, { displayText = { "Uni", "tS¦" }, optionsText = { "USA", "INT" }, options = { "mph", "kmh" }, optionIndex = -1, settingText = "speedType" } }, @@ -158,6 +189,7 @@ RADAR.vars = lockedType = nil -- The locked type, 1 = strongest, 2 = fastest }, + -- Variables for the rear antenna [ "rear" ] = { xmit = false, -- Whether the antenna is transmitting or in hold mode = 0, -- Current antenna mode, 0 = none, 1 = same, 2 = opp, 3 = same and opp @@ -204,11 +236,11 @@ RADAR.vars = threadWaitTime = 500, -- Key lock, when true, prevents any of the radar's key events from working, like the ELS key lock - keyLock = false, - - -- Full keyboard, when true, the keybinds for the radar will be set to the keys on the numpad, when false, the - -- keybinds for the radar will be set to the number keys above WASD - fullKeyboard = true + keyLock = false, + + -- Full keyboard, when true, the keybinds for the radar will be set to the keys on the numpad, when false, the + -- keybinds for the radar will be set to the number keys above WASD + fullKeyboard = true } -- Speed conversion values @@ -377,28 +409,6 @@ function RADAR:OpenRemote() end 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() - -- Iterate through each of the internal settings - for k, v in pairs( self.vars.settings ) do - -- Iterate through all of the menu options - for i, t in pairs( self.vars.menuOptions ) do - -- If the current menu option is the same as the current setting - if ( t.settingText == k ) then - -- Iterate through the option values of the current menu option - for oi, ov in pairs( t.options ) do - -- If the value of the current option set in the config matches the current value of - -- the option value, then we update the option index variable - if ( v == ov ) then - t.optionIndex = oi - end - end - end - end - end -end - -- Returns if the fast limit option should be available for the radar function RADAR:IsFastLimitAllowed() return CONFIG.allow_fast_limit @@ -462,28 +472,28 @@ end -- Toggles between the full and small keybinds function RADAR:ToggleFullKeyboard() - -- Check the player state is valid - if ( PLY:VehicleStateValid() ) then - -- Toggle the full keyboard state - self.vars.fullKeyboard = not self.vars.fullKeyboard + -- Check the player state is valid + if ( PLY:VehicleStateValid() ) then + -- Toggle the full keyboard state + self.vars.fullKeyboard = not self.vars.fullKeyboard - -- Tell the NUI side to display the keybind message - SendNUIMessage( { _type = "displayKeybindChange", state = self:GetFullKeyboardState() } ) - end + -- Tell the NUI side to display the keybind message + SendNUIMessage( { _type = "displayKeybindChange", state = self:GetFullKeyboardState() } ) + end end -- Returns the full keyboard state function RADAR:GetFullKeyboardState() - return self.vars.fullKeyboard + return self.vars.fullKeyboard end -- Returns which keybind set to use function RADAR:GetKeybindType() - if ( self:GetFullKeyboardState() ) then - return "full" - else - return "small" - end + if ( self:GetFullKeyboardState() ) then + return "full" + else + return "small" + end end @@ -594,6 +604,28 @@ function RADAR:SendMenuUpdate() SendNUIMessage( { _type = "menu", text = self:GetMenuOptionDisplayText(), option = self:GetMenuOptionText() } ) 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() + -- Iterate through each of the internal settings + for k, v in pairs( self.vars.settings ) do + -- Iterate through all of the menu options + for i, t in pairs( self.vars.menuOptions ) do + -- If the current menu option is the same as the current setting + if ( t.settingText == k ) then + -- Iterate through the option values of the current menu option + for oi, ov in pairs( t.options ) do + -- If the value of the current option set in the config matches the current value of + -- the option value, then we update the option index variable + if ( v == ov ) then + t.optionIndex = oi + end + end + end + end + end +end + --[[---------------------------------------------------------------------------------- Radar basics functions @@ -991,19 +1023,19 @@ function RADAR:SetAntennaSpeedLock( ant, speed, dir, lockType ) 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" ) } ) - - -- Great Scott! - if ( speed == "¦88" and self:GetSettingValue( "speedType" ) == "mph" ) then - math.randomseed( GetGameTimer() ) + SendNUIMessage( { _type = "lockAudio", ant = ant, dir = dir, vol = self:GetSettingValue( "voice" ) } ) + + -- Great Scott! + if ( speed == "¦88" and self:GetSettingValue( "speedType" ) == "mph" ) then + math.randomseed( GetGameTimer() ) - local chance = math.random() - - -- 15% chance - if ( chance <= 0.15 ) then - SendNUIMessage( { _type = "audio", name = "speed_alert", vol = self:GetSettingValue( "beep" ) } ) - end - end + local chance = math.random() + + -- 15% chance + if ( chance <= 0.15 ) then + SendNUIMessage( { _type = "audio", name = "speed_alert", vol = self:GetSettingValue( "beep" ) } ) + end + end end end @@ -1110,28 +1142,6 @@ 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 - detection. - --- 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 --- check for ray traces of different types, e.g. same or opp. -function RADAR:HasVehicleAlreadyBeenHit( key ) - return self.vars.tempVehicleIDs[key] -end - --- Returns if a vehicle has already been hit by a ray trace -function RADAR:SetVehicleHasBeenHit( key ) - self.vars.tempVehicleIDs[key] = true -end - --- Resets the temporary vehicle ids table -function RADAR:ResetTempVehicleIDs() - self.vars.tempVehicleIDs = {} -end -]] - --[[---------------------------------------------------------------------------------- Radar dynamic sphere radius functions @@ -1351,74 +1361,74 @@ end ) -- Runs when the user presses any of the antenna mode buttons on the remote RegisterNUICallback( "setAntennaMode", function( data ) - -- 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" ) } ) - 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 ) } ) - - -- Play a beep - SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } ) - end ) - end - end + -- 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" ) } ) + 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 ) } ) + + -- Play a beep + SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } ) + end ) + end + end end ) -- Runs when the user presses either of the XMIT/HOLD buttons on the remote RegisterNUICallback( "toggleAntenna", function( data ) - -- 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 - if ( RADAR:IsMenuOpen() ) then - -- Change the menu option based on which button is pressed - RADAR:ChangeMenuOption( data.value ) - - -- Play a beep noise - 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 ) } ) - - -- 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 ) - end - end + -- 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 + if ( RADAR:IsMenuOpen() ) then + -- Change the menu option based on which button is pressed + RADAR:ChangeMenuOption( data.value ) + + -- Play a beep noise + 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 ) } ) + + -- 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 ) + end + end end ) -- Runs when the user presses the menu button on the remote control RegisterNUICallback( "menu", function() - -- 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 - if ( RADAR:IsMenuOpen() ) then - -- As the menu is already open, we then iterate to the next option in the settings list - RADAR:ChangeMenuIndex() - else - -- Set the menu state to open, which will prevent anything else within the radar from working - RADAR:SetMenuState( true ) - - -- Send an update to the NUI side - RADAR:SendMenuUpdate() - end + -- 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 + if ( RADAR:IsMenuOpen() ) then + -- As the menu is already open, we then iterate to the next option in the settings list + RADAR:ChangeMenuIndex() + else + -- Set the menu state to open, which will prevent anything else within the radar from working + RADAR:SetMenuState( true ) + + -- Send an update to the NUI side + RADAR:SendMenuUpdate() + end - -- Play the standard audio beep - SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } ) - end + -- Play the standard audio beep + SendNUIMessage( { _type = "audio", name = "beep", vol = RADAR:GetSettingValue( "beep" ) } ) + end end ) -- Runs when the JavaScript side sends the UI data for saving @@ -1600,8 +1610,6 @@ function RADAR:Main() -- Send the update to the NUI side SendNUIMessage( { _type = "update", speed = data.patrolSpeed, antennas = data.antennas } ) - - -- self:ResetTempVehicleIDs() end end @@ -1614,10 +1622,10 @@ Citizen.CreateThread( function() RADAR:CacheNumRays() -- 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() + 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 @@ -1684,8 +1692,8 @@ end ) function RunControlManager() -- Make sure only the keyboard works if ( IsInputDisabled( 0 ) ) then - if ( not RADAR:GetKeyLockState() ) then - local keyType = RADAR:GetKeybindType() + if ( not RADAR:GetKeyLockState() ) then + local keyType = RADAR:GetKeybindType() -- Opens the remote control if ( IsDisabledControlJustPressed( 1, CONFIG.keys.remote_control ) ) then @@ -1716,18 +1724,13 @@ function RunControlManager() -- Toggles the key lock state if ( IsDisabledControlJustPressed( 1, CONFIG.keys.key_lock ) ) then RADAR:ToggleKeyLock() - end - - -- Toggles between the keybind types - if ( IsDisabledControlJustPressed( 1, CONFIG.keys.switch_keys ) ) then + end + + -- Toggles between the keybind types + if ( IsDisabledControlJustPressed( 1, CONFIG.keys.switch_keys ) ) then RADAR:ToggleFullKeyboard() - end + end end - - -- Shortcut to restart the resource - --[[ if ( IsDisabledControlJustPressed( 1, 167 ) ) then - ExecuteCommand( "restart wk_wars2x" ) - end ]] end -- Control manager diff --git a/cl_utils.lua b/cl_utils.lua index e84e2f5..a59af59 100644 --- a/cl_utils.lua +++ b/cl_utils.lua @@ -1,9 +1,34 @@ ---[[----------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- UTIL = {} diff --git a/config.lua b/config.lua index 757173f..e930ef5 100644 --- a/config.lua +++ b/config.lua @@ -1,9 +1,34 @@ ---[[------------------------------------------------------------------------ +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- -- Do not touch this CONFIG = {} @@ -16,83 +41,100 @@ CONFIG.allow_fast_limit = true -- Sets all of the controls CONFIG.keys = { - -- Remote control key - -- The default key to open the remote control is 166 (F5 - INPUT_SELECT_CHARACTER_MICHAEL) - remote_control = 166, + -- Remote control key + -- The default key to open the remote control is 166 (F5 - INPUT_SELECT_CHARACTER_MICHAEL) + remote_control = 166, - -- Radar key lock key - -- The default key to enable/disable the radar key lock is 182 (L - INPUT_CELLPHONE_CAMERA_FOCUS_LOCK) - key_lock = 182, + -- Radar key lock key + -- The default key to enable/disable the radar key lock is 182 (L - INPUT_CELLPHONE_CAMERA_FOCUS_LOCK) + key_lock = 182, - -- Radar keybinds switch - -- The default to key to switch the bind set is (K - INPUT_REPLAY_SHOWHOTKEY) - switch_keys = 311, + -- Radar keybinds switch + -- The default to key to switch the bind set is (K - INPUT_REPLAY_SHOWHOTKEY) + switch_keys = 311, - -- Keys for a full size keyboard - [ "full" ] = { - -- Radar front antenna lock/unlock Key - -- The default full keyboard key to lock/unlock the front antenna is 111 (Numpad 8 - INPUT_VEH_FLY_PITCH_UP_ONLY) - front_lock = 111, + -- Keys for a full size keyboard + [ "full" ] = { + -- Radar front antenna lock/unlock Key + -- The default full keyboard key to lock/unlock the front antenna is 111 (Numpad 8 - INPUT_VEH_FLY_PITCH_UP_ONLY) + front_lock = 111, - -- Radar rear antenna lock/unlock Key - -- The default full keyboard key to lock/unlock the rear antenna is 112 (Numpad 5 - INPUT_VEH_FLY_PITCH_DOWN_ONLY) - rear_lock = 112, + -- Radar rear antenna lock/unlock Key + -- The default full keyboard key to lock/unlock the rear antenna is 112 (Numpad 5 - INPUT_VEH_FLY_PITCH_DOWN_ONLY) + rear_lock = 112, - -- Plate reader front lock/unlock Key - -- The default full keyboard key to lock/unlock the front plate reader is 118 (Numpad 9 - INPUT_VEH_FLY_SELECT_TARGET_RIGHT) - plate_front_lock = 118, + -- Plate reader front lock/unlock Key + -- The default full keyboard key to lock/unlock the front plate reader is 118 (Numpad 9 - INPUT_VEH_FLY_SELECT_TARGET_RIGHT) + plate_front_lock = 118, - -- Plate reader rear lock/unlock Key - -- The default full keyboard key to lock/unlock the rear plate reader is 109 (Numpad 6 - INPUT_VEH_FLY_ROLL_RIGHT_ONLY) - plate_rear_lock = 109 - }, + -- Plate reader rear lock/unlock Key + -- The default full keyboard key to lock/unlock the rear plate reader is 109 (Numpad 6 - INPUT_VEH_FLY_ROLL_RIGHT_ONLY) + plate_rear_lock = 109 + }, - -- Keys for smaller keyboards - [ "small" ] = { - -- Radar front antenna lock/unlock Key - -- The default small keyboard key to lock/unlock the front antenna is 157 (1 - INPUT_SELECT_WEAPON_UNARMED) - front_lock = 157, + -- Keys for smaller keyboards + [ "small" ] = { + -- Radar front antenna lock/unlock Key + -- The default small keyboard key to lock/unlock the front antenna is 157 (1 - INPUT_SELECT_WEAPON_UNARMED) + front_lock = 157, - -- Radar rear antenna lock/unlock Key - -- The default small keyboard key to lock/unlock the rear antenna is 158 (2 - INPUT_SELECT_WEAPON_MELEE) - rear_lock = 158, + -- Radar rear antenna lock/unlock Key + -- The default small keyboard key to lock/unlock the rear antenna is 158 (2 - INPUT_SELECT_WEAPON_MELEE) + rear_lock = 158, - -- Plate reader front lock/unlock Key - -- The default small keyboard key to lock/unlock the front plate reader is 160 (3 - INPUT_SELECT_WEAPON_SHOTGUN) - plate_front_lock = 160, + -- Plate reader front lock/unlock Key + -- The default small keyboard key to lock/unlock the front plate reader is 160 (3 - INPUT_SELECT_WEAPON_SHOTGUN) + plate_front_lock = 160, - -- Plate reader rear lock/unlock Key - -- The default small keyboard key to lock/unlock the rear plate reader is 164 (4 - INPUT_SELECT_WEAPON_HEAVY) - plate_rear_lock = 164 - } + -- Plate reader rear lock/unlock Key + -- The default small keyboard key to lock/unlock the rear plate reader is 164 (4 - INPUT_SELECT_WEAPON_HEAVY) + plate_rear_lock = 164 + } } -- Here you can change the default values for the operator menu, do note, if any of these values are not -- one of the options listed, the script will not work. CONFIG.menuDefaults = { - -- Should the system calculate and display faster targets - -- Options: true or false - ["fastDisplay"] = true, + -- Should the system calculate and display faster targets + -- Options: true or false + ["fastDisplay"] = true, - -- Sensitivity for each radar mode, this changes how far the antennas will detect vehicles - -- Options: 0.2, 0.4, 0.6, 0.8, 1.0 - ["same"] = 0.6, - ["opp"] = 0.6, + -- Sensitivity for each radar mode, this changes how far the antennas will detect vehicles + -- Options: 0.2, 0.4, 0.6, 0.8, 1.0 + ["same"] = 0.6, + ["opp"] = 0.6, - -- The volume of the audible beep - -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 - ["beep"] = 0.6, - - -- The volume of the verbal lock confirmation - -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 - ["voice"] = 0.6, - - -- The volume of the plate reader audio - -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 - ["plateAudio"] = 0.6, + -- The volume of the audible beep + -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 + ["beep"] = 0.6, + + -- The volume of the verbal lock confirmation + -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 + ["voice"] = 0.6, + + -- The volume of the plate reader audio + -- Options: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 + ["plateAudio"] = 0.6, - -- The speed unit used in conversions - -- Options: mph or kmh - ["speedType"] = "mph" + -- The speed unit used in conversions + -- Options: mph or kmh + ["speedType"] = "mph" +} + +-- Here you can change the default scale of the UI elements, as well as the safezone size +CONFIG.uiDefaults = +{ + -- The default scale of the UI elements. + -- Options: 0.25 - 2.5 + scale = + { + radar = 1.5, + remote = 1.5, + plateReader = 1.5 + }, + + -- The safezone size, must be a multiple of 5. + -- Options: 0 - 100 + safezone = 20 } \ No newline at end of file diff --git a/fxmanifest.lua b/fxmanifest.lua index 4bc2aa4..fb189b8 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,9 +1,34 @@ ---[[----------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- -- Define the FX Server version and game type fx_version "adamant" @@ -13,19 +38,19 @@ game "gta5" name "Wraith ARS 2X" description "Police radar and plate reader system for FiveM" author "WolfKnight" -version "pre-release" +version "1.0.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", - "nui/fonts/*.ttf", - "nui/fonts/Segment7Standard.otf", - "nui/sounds/*.ogg" + "nui/radar.html", + "nui/radar.css", + "nui/jquery-3.4.1.min.js", + "nui/radar.js", + "nui/images/*.png", + "nui/images/plates/*.png", + "nui/fonts/*.ttf", + "nui/fonts/Segment7Standard.otf", + "nui/sounds/*.ogg" } -- Set the NUI page @@ -34,6 +59,8 @@ ui_page "nui/radar.html" -- Run the server scripts server_script "sv_version_check.lua" server_script "sv_saving.lua" +server_script "sv_exports.lua" +server_export "TogglePlateLock" -- Run the client scripts client_script "config.lua" diff --git a/nui/radar.css b/nui/radar.css index e92e4c7..b2520e1 100644 --- a/nui/radar.css +++ b/nui/radar.css @@ -1,3 +1,35 @@ +/*----------------------------------------------------------------------------------------- + + 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 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. + +-----------------------------------------------------------------------------------------*/ + @font-face { font-family: "Seg-7"; src: url( "fonts/Segment7Standard.otf" ); @@ -14,30 +46,30 @@ } @font-face { - font-family: "Plate-Font"; - src: url( "fonts/plate-font.ttf" ); + font-family: "Plate-Font"; + src: url( "fonts/plate-font.ttf" ); } @font-face { - font-family: "Plate-Font-Hilite"; - src: url( "fonts/plate-font-hilite.ttf" ); + font-family: "Plate-Font-Hilite"; + src: url( "fonts/plate-font-hilite.ttf" ); } @font-face { - font-family: "Plate-Font-Lolite"; - src: url( "fonts/plate-font-lolite.ttf" ); + font-family: "Plate-Font-Lolite"; + src: url( "fonts/plate-font-lolite.ttf" ); } @font-face { - font-family: "Plate-Font-Shadow"; - src: url( "fonts/plate-font-Shadow.ttf" ); + font-family: "Plate-Font-Shadow"; + src: url( "fonts/plate-font-Shadow.ttf" ); } * { font-family: 'Heebo', Verdana, Geneva, Tahoma, sans-serif; font-size: 13px; - box-sizing: border-box; - user-select: none; + box-sizing: border-box; + user-select: none; } body { @@ -52,18 +84,18 @@ button:focus { outline: none; } height: 230px; position: absolute; - margin: auto; - - top: calc( ( 100% - 10px ) - 230px ); - left: calc( ( 100% - 10px ) - 715px ); + margin: auto; + + top: calc( ( 100% - 10px ) - 230px ); + left: calc( ( 100% - 10px ) - 715px ); background-image: url( "images/frame.png" ); /* Settings for scaling */ transform: scale( 1.0 ); - transform-origin: 0 0; - - transition: transform 0.5s; + transform-origin: 0 0; + + transition: transform 0.5s; z-index: 2; } @@ -117,14 +149,14 @@ button:focus { outline: none; } transform: translateX( -1px ); background-image: url( "images/bg_right.png" ); background-repeat: no-repeat; - } - + } + .plate_blue { - color: rgb(0, 0, 163); + color: rgb(0, 0, 163); } .plate_yellow { - color: rgb(255, 255, 0); + color: rgb(255, 255, 0); } .arrow { @@ -247,7 +279,10 @@ button:focus { outline: none; } border: 2px solid rgb( 0, 0, 0 ); margin: auto 0; + + /* If you would like your strong target window to be solid rather than have a gradient, swap the comment for the 2 lines below */ background-color: rgb( 61, 18, 0 ); + /* background: linear-gradient( to bottom, rgb( 52, 13, 1 ), rgb( 57, 16, 0 ) 40%, rgb( 65, 25, 4 ) 85% ); */ } #radar .speeds_container .display p { grid-row-start: 1; @@ -266,7 +301,10 @@ button:focus { outline: none; } #radar .speeds_container .fast { height: 60px; + + /* If you would like your fast target window to be solid rather than have a gradient, swap the comment for the 2 lines below */ background-color: rgb( 50, 0, 0 ); + /* background: linear-gradient( to bottom, rgb( 40, 0, 0 ), rgb( 45, 0, 0 ) 40%, rgb( 50, 0, 0 ) 85% ); */ } #radar .speeds_container .fast p { font-size: 60px; @@ -326,6 +364,7 @@ button:focus { outline: none; } } #radar .patrol_and_logo_container .display { + /* If you would like your patrol speed window to be solid rather than have a gradient, swap the comment for the 2 lines below */ background-color: rgb( 0, 57, 35 ); /* background: linear-gradient( to bottom, rgb( 0, 40, 29 ), rgb( 0, 46, 32 ) 40%, rgb( 1, 64, 27 ) 85% ); */ } @@ -372,8 +411,8 @@ button:focus { outline: none; } height: 800px; position: absolute; - top: calc( 50% - ( 800px / 2 ) ); - left: calc( 50% - ( 315px / 2 ) ); + top: calc( 50% - ( 800px / 2 ) ); + left: calc( 50% - ( 315px / 2 ) ); margin: auto; padding: 65px 30px 50px 30px; @@ -383,15 +422,15 @@ button:focus { outline: none; } align-items: center; color: white; - background-image: url( "images/rc_bg.png" ); - - transition: transform 0.5s; - - /* Settings for scaling */ + background-image: url( "images/rc_bg.png" ); + + transition: transform 0.5s; + + /* Settings for scaling */ transform: scale( 1.0 ); transform-origin: 0 0; - z-index: 3; + z-index: 3; } /* Button template classes */ #rc button { @@ -567,8 +606,8 @@ button:focus { outline: none; } } #rc .plate_reader_and_help_container .help { - padding: 0 10px; - font-size: 15px; + padding: 0 10px; + font-size: 15px; } #rc .light { @@ -587,250 +626,250 @@ button:focus { outline: none; } #rc .blue { background-color: rgb( 84, 210, 255 ); - } - + } + #plateReaderFrame { - width: 500px; - height: 200px; + width: 500px; + height: 200px; - position: absolute; - margin: auto; + position: absolute; + margin: auto; - top: calc( 50% - ( 200px / 2 ) ); - left: calc( 50% - ( 500px / 2 ) ); + top: calc( 50% - ( 200px / 2 ) ); + left: calc( 50% - ( 500px / 2 ) ); - background-image: url( "images/pr_frame.png" ); + background-image: url( "images/pr_frame.png" ); - transition: transform 0.5s; + transition: transform 0.5s; - /* Settings for scaling */ + /* Settings for scaling */ transform: scale( 1.0 ); transform-origin: 0 0; - z-index: 1; + z-index: 1; } - #plateReaderFrame .frame_border { - width: 465px; - height: 175px; + #plateReaderFrame .frame_border { + width: 465px; + height: 175px; - position: absolute; - margin: auto; - top: 0; - right: 0; - bottom: 0; - left: 0; + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; - background-color: rgb( 20, 22, 18 ); + background-color: rgb( 20, 22, 18 ); - border-radius: 5px; - } + border-radius: 5px; + } #plateReader { - width: 460px; - height: 170px; - - position: absolute; - margin: auto; - top: 0; - right: 0; - bottom: 0; - left: 0; - - background-image: url( "images/pr_bg.png" ); - - box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 ); - - display: grid; - grid-template-rows: 30px 1fr 30px; - align-content: center; -} - #plateReader .labels { - display: grid; - grid-template-columns: 1fr 1fr; - align-content: center; - } - #plateReader .labels .title { - color: rgb( 255, 255, 255 ); - } - - #plateReader .labels p { - margin: 0; - text-align: center; - font-size: 18px; - } - - #plateReader .plates { - width: 100%; - height: 100%; - - display: grid; - grid-template-columns: 1fr 1fr; - align-content: center; - justify-items: center; - } - #plateReader .plates .plate_container { - width: 90%; - height: 100%; - - display: grid; - grid-template-columns: 1fr; - justify-content: center; - } - #plateReader .plates .plate_container .plate { - display: block; - max-width: 100%; - height: auto; - grid-column: 1; - grid-row: 1; - } - - #plateReader .plates .plate_container .text_container { - grid-column: 1; - grid-row: 1; - - display: grid; - grid-template-columns: 1fr; - justify-content: center; - } - #plateReader .plates .plate_container .text_container p { - display: block; - font-family: "Plate-Font"; - font-size: 58px; - text-align: center; - letter-spacing: -3px; - padding-top: 5px; - margin: 0; - grid-column: 1; - grid-row: 1; - } - - #plateReader .plates .plate_container .text_container .hilite { - font-family: "Plate-Font-Hilite"; - color: rgb( 93, 65, 255 ); - } - - #plateReader .plates .plate_container .text_container .lolite { - font-family: "Plate-Font-Lolite"; - color: rgb( 255, 255, 255 ); - } - - #plateReader .plates .plate_container .text_container .shadow { - font-family: "Plate-Font-Shadow"; - color: rgb( 100, 100, 100 ); - } - -.plate_hit { - animation: plate_flash linear 0.6s infinite; -} - -@keyframes plate_flash { - 0% { opacity: 1.0; } - 50% { opacity: 0.0; } - 100% { opacity: 1.0; } -} - -#plateReaderBox { - width: 225px; - height: 300px; - - position: absolute; - margin: auto; - top: 0; - right: 0; - bottom: 0; - left: 0; - - background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) ); - border: 3px solid rgb( 0, 0, 0 ); - - z-index: 4; -} - #plateReaderBox .title { - text-align: center; - font-size: 20px; - padding: 5px 0; - margin: 0 auto; - color: rgb( 255, 255, 255 ); - background-color: rgb( 20, 22, 18 ); - } - - #plateReaderBox .header { - width: 100%; - } - - #plateReaderBox .container { - width: 100%; - height: 200px; - - display: grid; - grid-template-rows: 60px 70px 60px; - align-items: center; - justify-items: center; - } - #plateReaderBox .container .btn { - width: 140px; - height: 35px; - border-radius: 10px; - font-size: 16px; - border: none; - } - #plateReaderBox .container .btn:hover { - background-color: rgb( 255, 255, 255 ); - } - - #plateReaderBox .container .btn:active { - background-color: rgb( 190, 190, 190 ); - padding: 0; - } - - #plateReaderBox .container .plate_input { - width: 75%; - height: 50px; - font-family: "Plate-Font"; - text-align: center; - font-size: 38px; - text-transform: uppercase; - padding: 0; - padding-bottom: 15px; - margin-bottom: -15px; - } - - #plateReaderBox .close { - width: 80px; - height: 20px; - - position: absolute; - left: 0; - right: 0; - bottom: 10px; - margin: auto; - - border-radius: 10px; - border: none; - background-color: rgb( 225, 225, 225 ); - } - #plateReaderBox .close:hover { - background-color: rgb( 255, 255, 255 ); - } - - #plateReaderBox .close:active { - background-color: rgb( 190, 190, 190 ); - padding: 0; - } - -#uiSettingsBox { - width: 250px; - height: 375px; + width: 460px; + height: 170px; position: absolute; margin: auto; top: 0; right: 0; bottom: 0; - left: 0; - - background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) ); - border: 3px solid rgb( 0, 0, 0 ); + left: 0; + + background-image: url( "images/pr_bg.png" ); + + box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 ); + + display: grid; + grid-template-rows: 30px 1fr 30px; + align-content: center; +} + #plateReader .labels { + display: grid; + grid-template-columns: 1fr 1fr; + align-content: center; + } + #plateReader .labels .title { + color: rgb( 255, 255, 255 ); + } + + #plateReader .labels p { + margin: 0; + text-align: center; + font-size: 18px; + } + + #plateReader .plates { + width: 100%; + height: 100%; + + display: grid; + grid-template-columns: 1fr 1fr; + align-content: center; + justify-items: center; + } + #plateReader .plates .plate_container { + width: 90%; + height: 100%; + + display: grid; + grid-template-columns: 1fr; + justify-content: center; + } + #plateReader .plates .plate_container .plate { + display: block; + max-width: 100%; + height: auto; + grid-column: 1; + grid-row: 1; + } + + #plateReader .plates .plate_container .text_container { + grid-column: 1; + grid-row: 1; + + display: grid; + grid-template-columns: 1fr; + justify-content: center; + } + #plateReader .plates .plate_container .text_container p { + display: block; + font-family: "Plate-Font"; + font-size: 58px; + text-align: center; + letter-spacing: -3px; + padding-top: 5px; + margin: 0; + grid-column: 1; + grid-row: 1; + } + + #plateReader .plates .plate_container .text_container .hilite { + font-family: "Plate-Font-Hilite"; + color: rgb( 93, 65, 255 ); + } + + #plateReader .plates .plate_container .text_container .lolite { + font-family: "Plate-Font-Lolite"; + color: rgb( 255, 255, 255 ); + } + + #plateReader .plates .plate_container .text_container .shadow { + font-family: "Plate-Font-Shadow"; + color: rgb( 100, 100, 100 ); + } + +.plate_hit { + animation: plate_flash linear 0.6s infinite; +} + +@keyframes plate_flash { + 0% { opacity: 1.0; } + 50% { opacity: 0.0; } + 100% { opacity: 1.0; } +} + +#plateReaderBox { + width: 225px; + height: 300px; + + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + + background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) ); + border: 3px solid rgb( 0, 0, 0 ); + + z-index: 4; +} + #plateReaderBox .title { + text-align: center; + font-size: 20px; + padding: 5px 0; + margin: 0 auto; + color: rgb( 255, 255, 255 ); + background-color: rgb( 20, 22, 18 ); + } + + #plateReaderBox .header { + width: 100%; + } + + #plateReaderBox .container { + width: 100%; + height: 200px; + + display: grid; + grid-template-rows: 60px 70px 60px; + align-items: center; + justify-items: center; + } + #plateReaderBox .container .btn { + width: 140px; + height: 35px; + border-radius: 10px; + font-size: 16px; + border: none; + } + #plateReaderBox .container .btn:hover { + background-color: rgb( 255, 255, 255 ); + } + + #plateReaderBox .container .btn:active { + background-color: rgb( 190, 190, 190 ); + padding: 0; + } + + #plateReaderBox .container .plate_input { + width: 75%; + height: 50px; + font-family: "Plate-Font"; + text-align: center; + font-size: 38px; + text-transform: uppercase; + padding: 0; + padding-bottom: 15px; + margin-bottom: -15px; + } + + #plateReaderBox .close { + width: 80px; + height: 20px; + + position: absolute; + left: 0; + right: 0; + bottom: 10px; + margin: auto; + + border-radius: 10px; + border: none; + background-color: rgb( 225, 225, 225 ); + } + #plateReaderBox .close:hover { + background-color: rgb( 255, 255, 255 ); + } + + #plateReaderBox .close:active { + background-color: rgb( 190, 190, 190 ); + padding: 0; + } + +#uiSettingsBox { + width: 250px; + height: 400px; + + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + + background: linear-gradient( to bottom, rgb( 70, 70, 70 ), rgb( 45, 45, 45 ) ); + border: 3px solid rgb( 0, 0, 0 ); z-index: 3; } @@ -845,20 +884,20 @@ button:focus { outline: none; } #uiSettingsBox .header { width: 100%; - } - - #uiSettingsBox .scaling_container { - height: 225px; - display: grid; - grid-template-rows: 1fr 1fr 1fr; - } + } + + #uiSettingsBox .scaling_container { + height: 225px; + display: grid; + grid-template-rows: 1fr 1fr 1fr; + } #uiSettingsBox .scaling { height: 70px; - - display: grid; - grid-template-columns: 1fr 2fr 1fr; - place-items: center center; + + display: grid; + grid-template-columns: 1fr 2fr 1fr; + place-items: center center; } #uiSettingsBox .scaling p { font-size: 18px; @@ -890,60 +929,60 @@ button:focus { outline: none; } #uiSettingsBox .scaling .plus { clip-path: polygon( 0 35%, 35% 35%, 35% 0, 65% 0, 65% 35%, 100% 35%, 100% 65%, 65% 65%, 65% 100%, 35% 100%, 35% 65%, 0 65% ); - } - - #uiSettingsBox .safezone_container { - width: 85%; - margin: 0 auto; - } - #uiSettingsBox .safezone_container p, - #uiSettingsBox .safezone_container span { - font-size: 18px; + } + + #uiSettingsBox .safezone_container { + width: 85%; + margin: 0 auto; + } + #uiSettingsBox .safezone_container p, + #uiSettingsBox .safezone_container span { + font-size: 18px; margin: 0 auto; text-align: center; color: rgb( 255, 255, 255 ); - } + } - #uiSettingsBox .safezone_container .slider { - width: 100%; - height: 10px; - margin: 10px 0; + #uiSettingsBox .safezone_container .slider { + width: 100%; + height: 10px; + margin: 10px 0; - border-radius: 5px; + border-radius: 5px; - -webkit-appearance: none; + -webkit-appearance: none; - background-color: rgb( 180, 180, 180 ); - } + background-color: rgb( 180, 180, 180 ); + } - #uiSettingsBox .safezone_container .slider:focus { - outline: none; - } - #uiSettingsBox .safezone_container .slider::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 15px; - height: 25px; - background: rgb( 84, 210, 255 ); - cursor: pointer; - } - - #uiSettingsBox .safezone_container .slider::-moz-range-thumb { - width: 15px; - height: 25px; - background: rgb( 84, 210, 255 ); - cursor: pointer; - } + #uiSettingsBox .safezone_container .slider:focus { + outline: none; + } + #uiSettingsBox .safezone_container .slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 15px; + height: 25px; + background: rgb( 84, 210, 255 ); + cursor: pointer; + } + + #uiSettingsBox .safezone_container .slider::-moz-range-thumb { + width: 15px; + height: 25px; + background: rgb( 84, 210, 255 ); + cursor: pointer; + } #uiSettingsBox .close { width: 80px; height: 20px; - position: absolute; - left: 0; - right: 0; - bottom: 30px; - margin: auto; + position: absolute; + left: 0; + right: 0; + bottom: 30px; + margin: auto; border-radius: 10px; border: none; @@ -956,61 +995,61 @@ button:focus { outline: none; } #uiSettingsBox .close:active { background-color: rgb( 190, 190, 190 ); padding: 0; - } + } #keyLockLabel, #keyBindsLabel { - position: absolute; - left: 0; - right: 0; - bottom: 350px; + position: absolute; + left: 0; + right: 0; + bottom: 350px; - text-align: center; - font-size: 30px; + text-align: center; + font-size: 30px; - color: rgb(255, 255, 255); - text-shadow: 3px 2px 5px rgb( 0, 0, 0 ); + color: rgb(255, 255, 255); + text-shadow: 3px 2px 5px rgb( 0, 0, 0 ); - z-index: 5; + z-index: 5; } - #keyBindsLabel { - bottom: 300px; - } + #keyBindsLabel { + bottom: 300px; + } - #keyLockLabel span, #keyBindsLabel span { - font-size: 30px; - } + #keyLockLabel span, #keyBindsLabel span { + font-size: 30px; + } #helpWindow { - width: 75%; - height: 90%; + width: 75%; + height: 90%; - position: absolute; - margin: auto; - top: 0; - right: 0; - bottom: 0; - left: 0; + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; - display: grid; - grid-template-rows: 90% 10%; - justify-items: center; + display: grid; + grid-template-rows: 90% 10%; + justify-items: center; - z-index: 6; + z-index: 6; } - #helpWindow iframe { - width: 100%; - height: 100%; + #helpWindow iframe { + width: 100%; + height: 100%; - display: block; - } + display: block; + } - #helpWindow .close { + #helpWindow .close { width: 150px; - height: 50px; - - margin: auto; + height: 50px; + + margin: auto; - font-size: 18px; + font-size: 18px; border-radius: 10px; border: none; @@ -1023,10 +1062,10 @@ button:focus { outline: none; } #helpWindow .close:active { background-color: rgb( 190, 190, 190 ); padding: 0; - } + } @media ( max-width: 1024px ) { - #helpWindow { - width: 80%; - } + #helpWindow { + width: 80%; + } } \ No newline at end of file diff --git a/nui/radar.html b/nui/radar.html index c15d446..37c1194 100644 --- a/nui/radar.html +++ b/nui/radar.html @@ -1,3 +1,35 @@ + + @@ -6,7 +38,7 @@ -
+
@@ -160,63 +192,63 @@ -
- -
-
+
+ +
+
-
-
-

FRONT

-

REAR

-
+
+
+

FRONT

+

REAR

+
-
-
- - -
-

-

-

-

-
-
+
+
+ + +
+

+

+

+

+
+
-
- +
+ -
-

-

-

-

-
-
-
+
+

+

+

+

+
+
+
-
-

LOCKED

-

LOCKED

-
-
-
+
+

LOCKED

+

LOCKED

+
+
+
-
-
+
+

Plate Reader

-
+
-
- +
+ - + - -
+ +
- -
+ +
@@ -224,59 +256,58 @@
-
-
+
+
-
-

Radar Scale

-

1.00x

-
+
+

Radar Scale

+

1.00x

+
-
-
+
+
-
-
+
+
-
-

Remote Scale

-

1.00x

-
+
+

Remote Scale

+

1.00x

+
-
-
+
+
-
-
+
+
-
-

Reader Scale

-

1.00x

-
+
+

Reader Scale

+

1.00x

+
-
-
-
- -
-

Safezone: 0px

- -
+
+
+
+ +
+

Safezone: 0px

+ +
-
- -

Radar key lock

-

Radar keybinds set for a

+ + +

Radar key lock

+

Radar keybinds set for a

-
- - -
+
+ + +
- - + \ No newline at end of file diff --git a/nui/radar.js b/nui/radar.js index 5042c7c..c82aeaa 100644 --- a/nui/radar.js +++ b/nui/radar.js @@ -1,12 +1,34 @@ -/*------------------------------------------------------------------------- +/*----------------------------------------------------------------------------------------- Wraith ARS 2X Created by WolfKnight - - This JS file takes inspiration from RandomSean's RS9000 JS file, so - thanks to him! --------------------------------------------------------------------------*/ + For discussions, information on future updates, and more, join + my Discord: https://discord.gg/fD4e6WD + + MIT License + + Copyright (c) 2020 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. + +-----------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Variables @@ -17,37 +39,37 @@ var uiEdited = false; // All of the audio file names const audioNames = { - // Beeps + // Beeps beep: "beep.ogg", xmit_on: "xmit_on.ogg", xmit_off: "xmit_off.ogg", - done: "done.ogg", - - // Verbal lock - front: "front.ogg", - rear: "rear.ogg", - closing: "closing.ogg", - away: "away.ogg", + done: "done.ogg", + + // Verbal lock + front: "front.ogg", + rear: "rear.ogg", + closing: "closing.ogg", + away: "away.ogg", - // Plate reader - plate_hit: "plate_hit.ogg", + // Plate reader + plate_hit: "plate_hit.ogg", - // Hmm - speed_alert: "speed_alert.ogg" + // Hmm + speed_alert: "speed_alert.ogg" } // Defines which audio needs to play for which direction const lockAudio = { - front: { - 1: "away", - 2: "closing" - }, + front: { + 1: "away", + 2: "closing" + }, - rear: { - 1: "closing", - 2: "away" - } + rear: { + 1: "closing", + 2: "away" + } } // Setup the main const element structure, this way we can easily access elements without having the mess @@ -55,76 +77,76 @@ const lockAudio = const elements = { radar: $( "#radarFrame" ), - remote: $( "#rc" ), - plateReader: $( "#plateReaderFrame" ), + remote: $( "#rc" ), + plateReader: $( "#plateReaderFrame" ), pwrBtn: $( "#pwrBtn" ), uiSettingsBtn: $( "#uiSettings" ), uiSettingsBox: $( "#uiSettingsBox" ), - closeUiBtn: $( "#closeUiSettings" ), - - plateReaderBtn: $( "#plateReaderBtn" ), - plateReaderBox: $( "#plateReaderBox" ), - boloText: $( "#boloText" ), - setBoloBtn: $( "#setBoloPlate" ), - closePrBtn: $( "#closePlateReaderSettings" ), + closeUiBtn: $( "#closeUiSettings" ), + + plateReaderBtn: $( "#plateReaderBtn" ), + plateReaderBox: $( "#plateReaderBox" ), + boloText: $( "#boloText" ), + setBoloBtn: $( "#setBoloPlate" ), + closePrBtn: $( "#closePlateReaderSettings" ), - openHelp: $( "#helpBtn" ), - helpWindow: $( "#helpWindow" ), - helpWeb: $( "#helpWeb" ), - closeHelp: $( "#closeHelp" ), + openHelp: $( "#helpBtn" ), + helpWindow: $( "#helpWindow" ), + helpWeb: $( "#helpWeb" ), + closeHelp: $( "#closeHelp" ), radarScaling: { increase: $( "#radarIncreaseScale" ), decrease: $( "#radarDecreaseScale" ), display: $( "#radarScaleDisplay" ) - }, + }, - remoteScaling: { - increase: $( "#remoteIncreaseScale" ), + remoteScaling: { + increase: $( "#remoteIncreaseScale" ), decrease: $( "#remoteDecreaseScale" ), display: $( "#remoteScaleDisplay" ) - }, + }, - plateReaderScaling: { - increase: $( "#readerIncreaseScale" ), + plateReaderScaling: { + increase: $( "#readerIncreaseScale" ), decrease: $( "#readerDecreaseScale" ), display: $( "#readerScaleDisplay" ) - }, + }, - plates: { - front: { - plate: $( "#frontPlate" ), - text: $( "#frontPlateText" ), - fill: $( "#frontPlateTextFill" ), - lolite: $( "#frontPlateTextLolite" ), - img: $( "#frontPlateImg" ), - lock: $( "#frontPlateLock" ) - }, + plates: { + front: { + plate: $( "#frontPlate" ), + text: $( "#frontPlateText" ), + fill: $( "#frontPlateTextFill" ), + lolite: $( "#frontPlateTextLolite" ), + img: $( "#frontPlateImg" ), + lock: $( "#frontPlateLock" ) + }, - rear: { - plate: $( "#rearPlate" ), - text: $( "#rearPlateText" ), - fill: $( "#rearPlateTextFill" ), - lolite: $( "#rearPlateTextLolite" ), - img: $( "#rearPlateImg" ), - lock: $( "#rearPlateLock" ) - } - }, + rear: { + plate: $( "#rearPlate" ), + text: $( "#rearPlateText" ), + fill: $( "#rearPlateTextFill" ), + lolite: $( "#rearPlateTextLolite" ), + img: $( "#rearPlateImg" ), + lock: $( "#rearPlateLock" ) + } + }, - safezoneSlider: $( "#safezone" ), - safezoneDisplay: $( "#safezoneDisplay" ), - - keyLock: { - label: $( "#keyLockLabel" ), - stateLabel: $( "#keyLockStateLabel" ) - }, + safezoneSlider: $( "#safezone" ), + safezoneDisplay: $( "#safezoneDisplay" ), + + keyLock: { + label: $( "#keyLockLabel" ), + stateLabel: $( "#keyLockStateLabel" ) + }, - keyBinds: { - label: $( "#keyBindsLabel" ), - stateLabel: $( "#keyBindsStateLabel" ) - }, + keyBinds: { + label: $( "#keyBindsLabel" ), + stateLabel: $( "#keyBindsStateLabel" ) + }, patrolSpeed: $( "#patrolSpeed" ), @@ -209,24 +231,24 @@ elements.helpWindow.hide(); // Sets the action for the "UI SETTINGS" button on the remote to open the UI settings box 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() { - 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() { - setEleVisible( elements.helpWindow, true ); - loadHelp( true ); + setEleVisible( elements.helpWindow, 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() { - setEleVisible( elements.helpWindow, false ); - loadHelp( false ); + setEleVisible( elements.helpWindow, false ); + loadHelp( false ); } ) @@ -236,20 +258,20 @@ elements.closeHelp.click( function() { // Sets the visibility of an element to the given state function setEleVisible( ele, state ) { - state ? ele.fadeIn() : ele.fadeOut(); + state ? ele.fadeIn() : ele.fadeOut(); } // Changes the class of the given element so it looks lit up function setLight( ant, cat, item, state ) { - // Grab the obj element from the elements table + // Grab the obj element from the elements table let obj = elements.antennas[ant][cat][item]; - // Either add the active class or remove it + // Either add the active class or remove it if ( state ) { - obj.addClass( cat == "dirs" ? "active_arrow" : "active" ); + obj.addClass( cat == "dirs" ? "active_arrow" : "active" ); } else { - obj.removeClass( cat == "dirs" ? "active_arrow" : "active" ); + obj.removeClass( cat == "dirs" ? "active_arrow" : "active" ); } } @@ -257,16 +279,16 @@ function setLight( ant, cat, item, state ) // when the state is false function setAntennaXmit( ant, state ) { - // Set the light state of the antenna's XMIT icon + // Set the light state of the antenna's XMIT icon setLight( ant, "modes", "xmit", state ); - // Clear the antenna's directional arrows and speeds, display "HLd" in the fast box + // Clear the antenna's directional arrows and speeds, display "HLd" in the fast box if ( !state ) { clearDirs( ant ); elements.antennas[ant].targetSpeed.html( "¦¦¦" ); - elements.antennas[ant].fastSpeed.html( "HLd" ); - - // Blank the fast box when the antenna is set to transmit + elements.antennas[ant].fastSpeed.html( "HLd" ); + + // Blank the fast box when the antenna is set to transmit } else { elements.antennas[ant].fastSpeed.html( "¦¦¦" ); } @@ -275,86 +297,86 @@ function setAntennaXmit( ant, state ) // Sets the mode lights for the given antenna function setAntennaMode( ant, mode ) { - // 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 + // 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 ); } // Sets the fast light for the given antenna function setAntennaFastMode( ant, state ) { - // Lighten or dull the fast led based on the given state + // Lighten or dull the fast led based on the given state setLight( ant, "fast", "fastLabel", state ); } // Sets the lock light for the given antenna function setAntennaLock( ant, state ) { - // Lighten or dull the lock led based on the given state - setLight( ant, "fast", "lockLabel", state ); + // Lighten or dull the lock led based on the given state + setLight( ant, "fast", "lockLabel", state ); } // Sets the directional arrows light for the given antenna function setAntennaDirs( ant, dir, fastDir ) { - // Target forward - setLight( ant, "dirs", "fwd", dir == dirs.closing ); - - // Target backward + // Target forward + setLight( ant, "dirs", "fwd", dir == dirs.closing ); + + // Target backward setLight( ant, "dirs", "bwd", dir == dirs.away ); - // Fast forward - setLight( ant, "dirs", "fwdFast", fastDir == dirs.closing ); - - // Fast backward + // Fast forward + setLight( ant, "dirs", "fwdFast", fastDir == dirs.closing ); + + // Fast backward setLight( ant, "dirs", "bwdFast", fastDir == dirs.away ); } // sets the plate lock light for the given plate reader function setPlateLock( cam, state, isBolo ) { - // Get the plate reader lock object - let obj = elements.plates[cam]; + // Get the plate reader lock object + let obj = elements.plates[cam]; - // Add or remove the active class + // Add or remove the active class if ( state ) { - obj.lock.addClass( "active" ); + obj.lock.addClass( "active" ); - // Only flash the plate if it was a BOLO plate - if ( isBolo ) { - // Make the hit plate flash for 3 seconds, acts as a visual aid - obj.plate.addClass( "plate_hit" ); + // Only flash the plate if it was a BOLO plate + if ( isBolo ) { + // Make the hit plate flash for 3 seconds, acts as a visual aid + obj.plate.addClass( "plate_hit" ); - setTimeout( function() { - obj.plate.removeClass( "plate_hit" ); - }, 3000 ); - } + setTimeout( function() { + obj.plate.removeClass( "plate_hit" ); + }, 3000 ); + } } else { - obj.lock.removeClass( "active" ); + obj.lock.removeClass( "active" ); } } // Sets the license text and plate image of the given plate reader function setPlate( cam, plate, index ) { - // Get the plate items - let pl = elements.plates[cam]; + // Get the plate items + let pl = elements.plates[cam]; - // Change the plate image - pl.img.attr( "src", "images/plates/" + index + ".png" ); + // Change the plate image + pl.img.attr( "src", "images/plates/" + index + ".png" ); - // Change the plate text colour depending on the plate itself - ( index == 1 || index == 2 ) ? pl.fill.removeClass( "plate_blue" ).addClass( "plate_yellow" ) : pl.fill.removeClass( "plate_yellow" ).addClass( "plate_blue" ); - - // If the plate is black or blue then we hide the lolite effect - ( index == 1 || index == 2 ) ? pl.lolite.hide() : pl.lolite.show(); + // Change the plate text colour depending on the plate itself + ( index == 1 || index == 2 ) ? pl.fill.removeClass( "plate_blue" ).addClass( "plate_yellow" ) : pl.fill.removeClass( "plate_yellow" ).addClass( "plate_blue" ); + + // If the plate is black or blue then we hide the lolite effect + ( index == 1 || index == 2 ) ? pl.lolite.hide() : pl.lolite.show(); - // Update all of the p elements with the new plate - pl.text.find( "p" ).each( function( i, obj ) { - $( this ).html( plate ); - } ); + // Update all of the p elements with the new plate + pl.text.find( "p" ).each( function( i, obj ) { + $( this ).html( plate ); + } ); } @@ -364,13 +386,13 @@ function setPlate( cam, plate, index ) // Clears the same, opp, fast, and lock leds for the given antenna function clearModes( ant ) { - // Iterate through the modes and clear them + // Iterate through the modes and clear them for ( let i in elements.antennas[ant].modes ) { elements.antennas[ant].modes[i].removeClass( "active" ); } - // Iterate through the fast leds and clear them + // Iterate through the fast leds and clear them for ( let a in elements.antennas[ant].fast ) { elements.antennas[ant].fast[a].removeClass( "active" ); @@ -380,7 +402,7 @@ function clearModes( ant ) // Clears the directional arrows for the given antenna function clearDirs( ant ) { - // Iterate through the directional arrows and clear them + // Iterate through the directional arrows and clear them for ( let i in elements.antennas[ant].dirs ) { elements.antennas[ant].dirs[i].removeClass( "active_arrow" ); @@ -390,26 +412,26 @@ function clearDirs( ant ) // Clears all of the elements of the given antenna function clearAntenna( ant ) { - // Clear the modes - clearModes( ant ); - - // Clear the directional arrows + // Clear the modes + clearModes( ant ); + + // Clear the directional arrows clearDirs( ant ); - // Blank the target speed box - elements.antennas[ant].targetSpeed.html( "¦¦¦" ); - - // Blank the fast speed box + // Blank the target speed box + elements.antennas[ant].targetSpeed.html( "¦¦¦" ); + + // Blank the fast speed box elements.antennas[ant].fastSpeed.html( "¦¦¦" ); } // Clears all the elements on the radar's UI function clearEverything() { - // Blank the patrol speed + // Blank the patrol speed elements.patrolSpeed.html( "¦¦¦" ); - // Blank both the antennas + // Blank both the antennas for ( let i in elements.antennas ) { clearAntenna( i ); @@ -423,23 +445,23 @@ function clearEverything() // Simulates the radar unit powering up by lighting all of the elements function poweringUp() { - // Set the patrol speed container to be fully lit + // Set the patrol speed container to be fully lit elements.patrolSpeed.html( "888" ); - // Iterate through the front and rear antenna elements + // Iterate through the front and rear antenna elements for ( let i of [ "front", "rear" ] ) { - // Get the antenna object to shorten the target reference + // Get the antenna object to shorten the target reference let e = elements.antennas[i]; - // Set the target and fast speed box to be fully lit + // Set the target and fast speed box to be fully lit e.targetSpeed.html( "888" ); e.fastSpeed.html( "888" ); - // Iterate through the rest of the antenna's elements + // Iterate through the rest of the antenna's elements for ( let a of [ "dirs", "modes", "fast" ] ) { - // Iterate through the objects for the current category and add the active class + // Iterate through the objects for the current category and add the active class for ( let obj in e[a] ) { a == "dirs" ? e[a][obj].addClass( "active_arrow" ) : e[a][obj].addClass( "active" ); @@ -451,14 +473,14 @@ function poweringUp() // Simulates the 'fully powered' state of the radar unit function poweredUp() { - // Completely clear everything + // Completely clear everything clearEverything(); - // Activate the 'fast' led for both antennas, and make sure the xmit led is off + // Activate the 'fast' led for both antennas, and make sure the xmit led is off for ( let ant of [ "front", "rear" ] ) { - // Even though the clearEverything() function is called above, we run this so the fast window - // displays 'HLd' + // Even though the clearEverything() function is called above, we run this so the fast window + // displays 'HLd' setAntennaXmit( ant, false ); setAntennaFastMode( ant, true ); } @@ -477,29 +499,29 @@ function radarPower( state ) // Plays the given audio file name from the audioNames list at the given volume function playAudio( name, vol ) { - // Create the new audio object - let audio = new Audio( "sounds/" + audioNames[name] ); - - // Set the volume - audio.volume = vol; - - // Play the audio clip + // Create the new audio object + let audio = new Audio( "sounds/" + audioNames[name] ); + + // Set the volume + audio.volume = vol; + + // Play the audio clip 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 ) { - // Play the front/rear sound - playAudio( ant, vol ); + // Play the front/rear sound + playAudio( ant, vol ); - // If the vehicle was closing or away, play that sound too - if ( dir > 0 ) - { - setTimeout( function() { - playAudio( lockAudio[ant][dir], vol ); - }, 500 ); - } + // If the vehicle was closing or away, play that sound too + if ( dir > 0 ) + { + setTimeout( function() { + playAudio( lockAudio[ant][dir], vol ); + }, 500 ); + } } @@ -509,22 +531,22 @@ function playLockAudio( ant, dir, vol ) // Updates patrol speed as well as the speeds and directional arrows for the given antenna function updateDisplays( ps, ants ) { - // Update the patrol speed + // Update the patrol speed elements.patrolSpeed.html( ps ); - // Iterate through the antenna data + // Iterate through the antenna data for ( let ant in ants ) { - // Make sure there is actually data for the current antenna data + // Make sure there is actually data for the current antenna data if ( ants[ant] != null ) { - // Grab the antenna element from the elements table + // Grab the antenna element from the elements table let e = elements.antennas[ant]; - // Update the target and fast speeds + // Update the target and fast speeds e.targetSpeed.html( ants[ant][0].speed ); e.fastSpeed.html( ants[ant][1].speed ); - // Update the directional arrows + // Update the directional arrows setAntennaDirs( ant, ants[ant][0].dir, ants[ant][1].dir ); } } @@ -537,7 +559,7 @@ function settingUpdate( ants ) { setAntennaXmit( ant, ants[ant].xmit ); setAntennaMode( ant, ants[ant].mode ); - setAntennaFastMode( ant, ants[ant].fast ); + setAntennaFastMode( ant, ants[ant].fast ); setAntennaLock( ant, ants[ant].speedLocked ); } } @@ -549,44 +571,44 @@ function settingUpdate( ants ) // Displays the given option text and current option value on the radar function menu( optionText, option ) { - // Clear everything + // Clear everything clearEverything(); - // Set the target and fast box to the option text + // Set the target and fast box to the option text elements.antennas.front.targetSpeed.html( optionText[0] ); elements.antennas.front.fastSpeed.html( optionText[1] ); - // Set the patrol speed to the value + // Set the patrol speed to the value elements.patrolSpeed.html( option ); } // Makes the key lock label fade in then fade out after 2 seconds function displayKeyLock( state ) { - // Set the state label text to enabled or disabled - elements.keyLock.stateLabel.html( state ? "enabled" : "disabled" ); + // Set the state label text to enabled or disabled + elements.keyLock.stateLabel.html( state ? "enabled" : "disabled" ); - // Fade in the label - elements.keyLock.label.fadeIn(); + // Fade in the label + elements.keyLock.label.fadeIn(); - // Make the label fade out after 2 seconds - setTimeout( function() { - elements.keyLock.label.fadeOut(); - }, 2000 ); + // Make the label fade out after 2 seconds + setTimeout( function() { + elements.keyLock.label.fadeOut(); + }, 2000 ); } function displayKeybindState( state ) { // Set the state label text to enabled or disabled - elements.keyBinds.stateLabel.html( state ? "full keyboard" : "small keyboard" ); + elements.keyBinds.stateLabel.html( state ? "full keyboard" : "small keyboard" ); - // Fade in the label - elements.keyBinds.label.fadeIn(); + // Fade in the label + elements.keyBinds.label.fadeIn(); - // Make the label fade out after 2 seconds - setTimeout( function() { - elements.keyBinds.label.fadeOut(); - }, 2000 ); + // Make the label fade out after 2 seconds + setTimeout( function() { + elements.keyBinds.label.fadeOut(); + }, 2000 ); } // This function is used to send data back through to the LUA side @@ -601,133 +623,162 @@ function sendData( name, data ) { // Sets the ui edited variable to the given state, this is used in the UI save system function setUiHasBeenEdited( state ) { - uiEdited = state; + uiEdited = state; } // Returns if the UI has been edited function hasUiBeenEdited() { - return uiEdited; + return uiEdited; } // Gathers the UI data and sends it to the Lua side function sendSaveData() { - // Make sure we only collect and send the UI data if it has been edited - if ( hasUiBeenEdited() ) { - let data = - { - remote: { - left: elements.remote.css( "left" ), - top: elements.remote.css( "top" ), - scale: remoteScale - }, + // Make sure we only collect and send the UI data if it has been edited + if ( hasUiBeenEdited() ) { + let data = + { + remote: { + left: elements.remote.css( "left" ), + top: elements.remote.css( "top" ), + scale: remoteScale + }, - radar: { - left: elements.radar.css( "left" ), - top: elements.radar.css( "top" ), - scale: radarScale - }, + radar: { + left: elements.radar.css( "left" ), + top: elements.radar.css( "top" ), + scale: radarScale + }, - plateReader: { - left: elements.plateReader.css( "left" ), - top: elements.plateReader.css( "top" ), - scale: readerScale - }, + plateReader: { + left: elements.plateReader.css( "left" ), + top: elements.plateReader.css( "top" ), + scale: readerScale + }, - safezone: safezone - } + safezone: safezone + } - // Send the data - sendData( "saveUiData", data ); - } + // Send the data + sendData( "saveUiData", data ); + } } // Loads the UI settings -function loadUiSettings( data ) +function loadUiSettings( data, isSave ) { - // Iterate through "remote", "radar" and "plateReader" - for ( let setting of [ "remote", "radar", "plateReader" ] ) - { - // Iterate through the settings - for ( let i of [ "left", "top" ] ) - { - // Update the position of the current element - elements[setting].css( i, data[setting][i] ); - } + // Iterate through "remote", "radar" and "plateReader" + for ( let setting of [ "remote", "radar", "plateReader" ] ) + { + let ele = elements[setting]; - // Set the scale and update the display - setScaleAndDisplay( elements[setting], data[setting].scale, elements[setting + "Scaling"].display ); - } + if ( isSave ) { + // Iterate through the settings + for ( let i of [ "left", "top" ] ) + { + // Update the position of the current element + ele.css( i, data[setting][i] ); + } + + // Set the scale and update the display + setScaleAndDisplay( ele, data[setting].scale, elements[setting + "Scaling"].display ); + } else { + // Set the scale and update the display + setScaleAndDisplay( ele, data.scale[setting], elements[setting + "Scaling"].display ); - // Update the remote, radar and reader scale variables - remoteScale = data.remote.scale; - radarScale = data.radar.scale; - readerScale = data.plateReader.scale; + // Get the scaled width and height of the current element + let w = ( ele.outerWidth() * data.scale[setting] ); + let h = ( ele.outerHeight() * data.scale[setting] ); - // Set the safezone and update the display - elements.safezoneSlider.val( data.safezone ); - elements.safezoneSlider.trigger( "input" ); + // The position of the element then needs to be updated. + switch ( setting ) { + case "remote": + ele.css( "left", "calc( 50% - " + w / 2 + "px )" ); + ele.css( "top", "calc( 50% - " + h / 2 + "px )" ); + break; + case "radar": + ele.css( "left", "calc( ( 100% - " + data.safezone + "px ) - " + w + "px )" ); + ele.css( "top", "calc( ( 100% - " + data.safezone + "px ) - " + h + "px )" ); + break; + case "plateReader": + ele.css( "left", "calc( ( 100% - " + data.safezone + "px ) - " + w + "px )" ); + ele.css( "top", "calc( 50% - " + h / 2 + "px )" ); + break; + default: + break; + } + } + } + + // Update the remote, radar and reader scale variables + remoteScale = isSave ? data.remote.scale : data.scale.remote; + radarScale = isSave ? data.radar.scale : data.scale.radar; + readerScale = isSave ? data.plateReader.scale : data.scale.plateReader; + + // Set the safezone and update the display + elements.safezoneSlider.val( data.safezone ); + elements.safezoneSlider.trigger( "input" ); } // Sets the on click function for the set BOLO plate button elements.setBoloBtn.click( function() { - // Grab the value of the text input box - let plate = elements.boloText.val().toUpperCase(); + // Grab the value of the text input box + let plate = elements.boloText.val().toUpperCase(); - // Gets the amount of whitespace there should be - let spaceAmount = 8 - plate.length; + // Gets the amount of whitespace there should be + let spaceAmount = 8 - plate.length; - if ( spaceAmount > 0 ) - { - // Splits the amount in half - let split = spaceAmount / 2; + if ( spaceAmount > 0 ) + { + // Splits the amount in half + let split = spaceAmount / 2; - // Calculates how many whitespace characters there should be at the start and end of the string. As GTA - // formats a licence plate string by padding it, with the end of the string being biased compared to - // the start of the string. - let startSpace = Math.floor( split ); - let endSpace = Math.ceil( split ); + // Calculates how many whitespace characters there should be at the start and end of the string. As GTA + // formats a licence plate string by padding it, with the end of the string being biased compared to + // the start of the string. + let startSpace = Math.floor( split ); + let endSpace = Math.ceil( split ); - // Add the padding to the string - let text = plate.padStart( plate.length + startSpace ); - text = text.padEnd( text.length + endSpace ); + // Add the padding to the string + let text = plate.padStart( plate.length + startSpace ); + text = text.padEnd( text.length + endSpace ); - // Send the plate to the Lua side - sendData( "setBoloPlate", text ); - } else { - sendData( "setBoloPlate", plate ); - } + // Send the plate to the Lua side + sendData( "setBoloPlate", text ); + } else { + sendData( "setBoloPlate", plate ); + } } ) // Checks what the user is typing into the plate box function checkPlateInput( event ) { - // 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 ); + // 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 ) { - event.preventDefault(); - } + // If the key is not valid, prevent the key from being input into the box + if ( !valid ) { + 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 ) { - if ( state ) { - elements.helpWeb.attr( "src", "https://wolfknight98.github.io/wk_wars2x_web/manual.pdf" ); - } else { - elements.helpWeb.attr( "src", "about:blank" ); - } + if ( state ) { + elements.helpWeb.attr( "src", "https://wolfknight98.github.io/wk_wars2x_web/manual.pdf" ); + } else { + elements.helpWeb.attr( "src", "about:blank" ); + } } /*------------------------------------------------------------------------------------ - 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. + 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 remoteMoving = false; @@ -747,192 +798,192 @@ var safezone = 0; // Close the UI settings window when the 'Close' button is pressed elements.closeUiBtn.click( function() { - setEleVisible( elements.uiSettingsBox, false ); + setEleVisible( elements.uiSettingsBox, false ); } ) // Close the plate reader settings window when the 'Close' button is pressed elements.closePrBtn.click( function() { - setEleVisible( elements.plateReaderBox, false ); + setEleVisible( elements.plateReaderBox, false ); } ) // Set the remote scale buttons to change the remote's scale elements.remoteScaling.increase.click( function() { - remoteScale = changeEleScale( elements.remote, remoteScale, 0.05, elements.remoteScaling.display ); + remoteScale = changeEleScale( elements.remote, remoteScale, 0.05, elements.remoteScaling.display ); } ) elements.remoteScaling.decrease.click( function() { - remoteScale = changeEleScale( elements.remote, remoteScale, -0.05, elements.remoteScaling.display ); + remoteScale = changeEleScale( elements.remote, remoteScale, -0.05, elements.remoteScaling.display ); } ) // Set the radar scale buttons to change the radar's scale elements.radarScaling.increase.click( function() { - radarScale = changeEleScale( elements.radar, radarScale, 0.05, elements.radarScaling.display ); + radarScale = changeEleScale( elements.radar, radarScale, 0.05, elements.radarScaling.display ); } ) elements.radarScaling.decrease.click( function() { - radarScale = changeEleScale( elements.radar, radarScale, -0.05, elements.radarScaling.display ); + radarScale = changeEleScale( elements.radar, radarScale, -0.05, elements.radarScaling.display ); } ) // Set the reader scale buttons to change the reader's scale elements.plateReaderScaling.increase.click( function() { - readerScale = changeEleScale( elements.plateReader, readerScale, 0.05, elements.plateReaderScaling.display ); + readerScale = changeEleScale( elements.plateReader, readerScale, 0.05, elements.plateReaderScaling.display ); } ) elements.plateReaderScaling.decrease.click( function() { - readerScale = changeEleScale( elements.plateReader, readerScale, -0.05, elements.plateReaderScaling.display ); + readerScale = changeEleScale( elements.plateReader, readerScale, -0.05, elements.plateReaderScaling.display ); } ) // Remote mouse down and up event elements.remote.mousedown( function( event ) { - remoteMoving = true; + remoteMoving = true; - let offset = $( this ).offset(); + let offset = $( this ).offset(); - remoteOffset = getOffset( offset, event.clientX, event.clientY ); + remoteOffset = getOffset( offset, event.clientX, event.clientY ); } ) // Radar mouse down and up event elements.radar.mousedown( function( event ) { - radarMoving = true; + radarMoving = true; - let offset = $( this ).offset(); + let offset = $( this ).offset(); - radarOffset = getOffset( offset, event.clientX, event.clientY ); + radarOffset = getOffset( offset, event.clientX, event.clientY ); } ) // Plate reader mouse down and up event elements.plateReader.mousedown( function( event ) { - readerMoving = true; + readerMoving = true; - let offset = $( this ).offset(); + let offset = $( this ).offset(); - readerOffset = getOffset( offset, event.clientX, event.clientY ); + readerOffset = getOffset( offset, event.clientX, event.clientY ); } ) $( document ).mouseup( function( event ) { - // Reset the remote and radar moving variables - remoteMoving = false; - radarMoving = false; - readerMoving = false; + // Reset the remote and radar moving variables + remoteMoving = false; + radarMoving = false; + readerMoving = false; } ) $( document ).mousemove( function( event ) { - let x = event.clientX; - let y = event.clientY; + let x = event.clientX; + let y = event.clientY; - if ( remoteMoving ) - { - event.preventDefault(); + if ( remoteMoving ) + { + event.preventDefault(); - calculatePos( elements.remote, x, y, windowWidth, windowHeight, remoteOffset, remoteScale, safezone ); - } + calculatePos( elements.remote, x, y, windowWidth, windowHeight, remoteOffset, remoteScale, safezone ); + } - if ( radarMoving ) - { - event.preventDefault(); + if ( radarMoving ) + { + event.preventDefault(); - calculatePos( elements.radar, x, y, windowWidth, windowHeight, radarOffset, radarScale, safezone ); - } + calculatePos( elements.radar, x, y, windowWidth, windowHeight, radarOffset, radarScale, safezone ); + } - if ( readerMoving ) - { - event.preventDefault(); + if ( readerMoving ) + { + event.preventDefault(); - calculatePos( elements.plateReader, x, y, windowWidth, windowHeight, readerOffset, readerScale, safezone ); - } + calculatePos( elements.plateReader, x, y, windowWidth, windowHeight, readerOffset, readerScale, safezone ); + } } ) $( window ).resize( function() { - windowWidth = $( this ).width(); - windowHeight = $( this ).height(); + windowWidth = $( this ).width(); + windowHeight = $( this ).height(); } ) $( document ).ready( function() { - windowWidth = $( window ).width(); - windowHeight = $( window ).height(); + windowWidth = $( window ).width(); + windowHeight = $( window ).height(); } ) elements.safezoneSlider.on( "input", function() { - let val = $( this ).val(); - safezone = parseInt( val, 10 ); + let val = $( this ).val(); + safezone = parseInt( val, 10 ); - elements.safezoneDisplay.html( val + "px" ); + elements.safezoneDisplay.html( val + "px" ); } ) function calculatePos( ele, x, y, w, h, offset, scale, safezone ) { - let eleWidth = ( ele.outerWidth() * scale ); - let eleHeight = ( ele.outerHeight() * scale ); - let eleWidthPerct = ( eleWidth / w ) * 100; - let eleHeightPerct = ( eleHeight / h ) * 100; - let eleWidthPerctHalf = eleWidthPerct / 2; - let eleHeightPerctHalf = eleHeightPerct / 2; + let eleWidth = ( ele.outerWidth() * scale ); + let eleHeight = ( ele.outerHeight() * scale ); + let eleWidthPerct = ( eleWidth / w ) * 100; + let eleHeightPerct = ( eleHeight / h ) * 100; + let eleWidthPerctHalf = eleWidthPerct / 2; + let eleHeightPerctHalf = eleHeightPerct / 2; - let maxWidth = w - eleWidth; - let maxHeight = h - eleHeight; + let maxWidth = w - eleWidth; + let maxHeight = h - eleHeight; - let left = clamp( x + offset[0], 0 + safezone, maxWidth - safezone ); - let top = clamp( y + offset[1], 0 + safezone, maxHeight - safezone ); + let left = clamp( x + offset[0], 0 + safezone, maxWidth - safezone ); + let top = clamp( y + offset[1], 0 + safezone, maxHeight - safezone ); - let leftPos = ( left / w ) * 100; - let topPos = ( top / h ) * 100; + let leftPos = ( left / w ) * 100; + let topPos = ( top / h ) * 100; - let leftLockGap = leftPos + eleWidthPerctHalf; - let topLockGap = topPos + eleHeightPerctHalf; + let leftLockGap = leftPos + eleWidthPerctHalf; + let topLockGap = topPos + eleHeightPerctHalf; - // Lock pos check - if ( leftLockGap >= 49.0 && leftLockGap <= 51.0 ) - { - leftPos = 50.0 - eleWidthPerctHalf; - } + // Lock pos check + if ( leftLockGap >= 49.0 && leftLockGap <= 51.0 ) + { + leftPos = 50.0 - eleWidthPerctHalf; + } - if ( topLockGap >= 49.0 && topLockGap <= 51.0 ) - { - topPos = 50.0 - eleHeightPerctHalf; - } + if ( topLockGap >= 49.0 && topLockGap <= 51.0 ) + { + topPos = 50.0 - eleHeightPerctHalf; + } - updatePosition( ele, leftPos, topPos ); - setUiHasBeenEdited( true ); + updatePosition( ele, leftPos, topPos ); + setUiHasBeenEdited( true ); } function updatePosition( ele, left, top ) { - ele.css( "left", left + "%" ); - ele.css( "top", top + "%" ); + ele.css( "left", left + "%" ); + ele.css( "top", top + "%" ); } function getOffset( offset, x, y ) { - return [ - offset.left - x, - offset.top - y - ] + return [ + offset.left - x, + offset.top - y + ] } function changeEleScale( ele, scaleVar, amount, display ) { - // Change the scale of the element and update it's displayer - let scale = changeScale( ele, scaleVar, amount ); - display.html( scale.toFixed( 2 ) + "x" ); + // Change the scale of the element and update it's displayer + let scale = changeScale( ele, scaleVar, amount ); + display.html( scale.toFixed( 2 ) + "x" ); - // Tell the system the UI has been edited - setUiHasBeenEdited( true ); + // Tell the system the UI has been edited + setUiHasBeenEdited( true ); - return scale; + return scale; } function changeScale( ele, current, amount ) { - let scale = clamp( current + amount, 0.25, 2.5 ); - ele.css( "transform", "scale(" + scale + ")" ); + let scale = clamp( current + amount, 0.25, 2.5 ); + ele.css( "transform", "scale(" + scale + ")" ); - return scale; + return scale; } function setScaleAndDisplay( ele, scale, display ) { - ele.css( "transform", "scale(" + scale + ")" ); - display.html( scale.toFixed( 2 ) + "x" ); + ele.css( "transform", "scale(" + scale + ")" ); + display.html( scale.toFixed( 2 ) + "x" ); } function clamp( num, min, max ) @@ -960,64 +1011,67 @@ $( "body" ).find( "button, div" ).each( function( i, obj ) { /*------------------------------------------------------------------------------------ - Close the remote when the user presses the 'Escape' key or the right mouse button + Close the remote when the user presses the 'Escape' key or the right mouse button ------------------------------------------------------------------------------------*/ function closeRemote() { - sendData( "closeRemote", null ); + sendData( "closeRemote", null ); - setEleVisible( elements.plateReaderBox, false ); - setEleVisible( elements.uiSettingsBox, false ); - setEleVisible( elements.helpWindow, false ); - loadHelp( false ); + setEleVisible( elements.plateReaderBox, false ); + setEleVisible( elements.uiSettingsBox, false ); + setEleVisible( elements.helpWindow, false ); + loadHelp( false ); - setEleVisible( elements.remote, false ); - - sendSaveData(); + setEleVisible( elements.remote, false ); + + sendSaveData(); } $( document ).keyup( function( event ) { - if ( event.keyCode == 27 ) + if ( event.keyCode == 27 ) { closeRemote(); } } ); $( document ).contextmenu( function() { - closeRemote(); + closeRemote(); } ); /*------------------------------------------------------------------------------------ - The main event listener, this is where the NUI messages sent by the LUA side arrive - at, they are then handled properly via a switch/case that runs the relevant code + The main event listener, this is where the NUI messages sent by the LUA side arrive + at, they are then handled properly via a switch/case that runs the relevant code ------------------------------------------------------------------------------------*/ window.addEventListener( "message", function( event ) { var item = event.data; - var type = event.data._type; + var type = event.data._type; switch ( type ) { - // System events + // System events case "updatePathName": resourceName = item.pathName - break; - case "loadUiSettings": - loadUiSettings( item.data ); - break; - case "displayKeyLock": - displayKeyLock( item.state ); - break; - case "displayKeybindChange": - displayKeybindState( item.state ); - return; + break; + case "loadUiSettings": + loadUiSettings( item.data, true ); + break; + case "setUiDefaults": + loadUiSettings( item.data, false ); + break; + case "displayKeyLock": + displayKeyLock( item.state ); + break; + case "displayKeybindChange": + displayKeybindState( item.state ); + return; - // Radar events + // Radar events case "openRemote": - setEleVisible( elements.remote, true ); - setUiHasBeenEdited( false ); + setEleVisible( elements.remote, true ); + setUiHasBeenEdited( false ); break; case "setRadarDisplayState": - setEleVisible( elements.radar, item.state ); + setEleVisible( elements.radar, item.state ); break; case "radarPower": radarPower( item.state ); @@ -1035,38 +1089,38 @@ window.addEventListener( "message", function( event ) { setAntennaMode( item.ant, item.mode ); break; case "antennaLock": - setAntennaLock( item.ant, item.state ); - break; - case "antennaFast": - setAntennaFastMode( item.ant, item.state ); - break; + setAntennaLock( item.ant, item.state ); + break; + case "antennaFast": + setAntennaFastMode( item.ant, item.state ); + break; case "menu": menu( item.text, item.option ); break; case "settingUpdate": settingUpdate( item.antennaData ); - break; + break; - // Plate reader events - case "setReaderDisplayState": - setEleVisible( elements.plateReader, item.state ); - break; - case "changePlate": - setPlate( item.cam, item.plate, item.index ); - break; - case "lockPlate": - setPlateLock( item.cam, item.state, item.isBolo ); - break; - - // Audio events + // Plate reader events + case "setReaderDisplayState": + setEleVisible( elements.plateReader, item.state ); + break; + case "changePlate": + setPlate( item.cam, item.plate, item.index ); + break; + case "lockPlate": + setPlateLock( item.cam, item.state, item.isBolo ); + break; + + // Audio events case "audio": playAudio( item.name, item.vol ); - break; - case "lockAudio": - playLockAudio( item.ant, item.dir, item.vol ); - break; - - // default + break; + case "lockAudio": + playLockAudio( item.ant, item.dir, item.vol ); + break; + + // default default: break; } diff --git a/sv_exports.lua b/sv_exports.lua new file mode 100644 index 0000000..3e67112 --- /dev/null +++ b/sv_exports.lua @@ -0,0 +1,50 @@ +--[[--------------------------------------------------------------------------------------- + + 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 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. + +---------------------------------------------------------------------------------------]]-- + +-- Although there is only one export at the moment, more may be added down the line. + +--[[--------------------------------------------------------------------------------------- + Locks the designated plate reader camera for the given client. + + Parameters: + clientId: + The id of the client + cam: + The camera to lock, either "front" or "rear" + beepAudio: + Play an audible beep, either true or false + boloAudio: + Play the bolo lock sound, either true or false +---------------------------------------------------------------------------------------]]-- +function TogglePlateLock( clientId, cam, beepAudio, boloAudio ) + TriggerClientEvent( "wk:togglePlateLock", clientId, cam, beepAudio, boloAudio ) +end \ No newline at end of file diff --git a/sv_saving.lua b/sv_saving.lua index f7cf773..0cb3ee1 100644 --- a/sv_saving.lua +++ b/sv_saving.lua @@ -1,9 +1,34 @@ ---[[----------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- local DATASAVE = {} DATASAVE.dir = "saves" @@ -19,6 +44,9 @@ DATASAVE.dir = "saves" -- - ip DATASAVE.idType = "license" +-- Whether or not to print messages +DATASAVE.printMessages = true + -- Saves the data for the given player into the saves folder within the resource function DATASAVE:SavePlayerData( src, data ) -- Get the player's identifier @@ -115,7 +143,9 @@ end -- Prints the given message with the resource name attached function DATASAVE:Print( msg ) - print( "^3[wk_wars2x] ^0" .. msg .. "^0" ) + if ( self.printMessages ) then + print( "^3[wk_wars2x] ^0" .. msg .. "^0" ) + end end -- Serverside event for saving a player's UI data @@ -146,5 +176,8 @@ AddEventHandler( "wk:getUiData", function() else -- 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." ) + + -- Tell the system to load the UI defaults for the client + TriggerClientEvent( "wk:setUiDefaults", source ) end end ) \ No newline at end of file diff --git a/sv_version_check.lua b/sv_version_check.lua index 399f4f0..35ddaad 100644 --- a/sv_version_check.lua +++ b/sv_version_check.lua @@ -1,9 +1,34 @@ ---[[----------------------------------------------------------------------- +--[[--------------------------------------------------------------------------------------- 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 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. + +---------------------------------------------------------------------------------------]]-- -- Branding! local label = @@ -15,6 +40,8 @@ local label = || \ \/ \/ / '__/ _` | | __| '_ \ / /\ \ | _ / \___ \ / / > < || \ /\ /| | | (_| | | |_| | | | / ____ \| | \ \ ____) | / /_ / . \ || \/ \/ |_| \__,_|_|\__|_| |_| /_/ \_\_| \_\_____/ |____/_/ \_\ + || + || Created by WolfKnight ||]] -- Returns the current version set in fxmanifest.lua