diff --git a/cl_radar.lua b/cl_radar.lua index e876b5d..99bbb73 100644 --- a/cl_radar.lua +++ b/cl_radar.lua @@ -77,6 +77,84 @@ Citizen.CreateThread( function() end end ) +--[[---------------------------------------------------------------------------------- + Plate reader variables + + NOTE - This is not a config, do not touch anything unless you know what + you are actually doing. +----------------------------------------------------------------------------------]]-- +READER = {} +READER.vars = +{ + -- Whether or not the radar's UI is visible + displayed = true, + + -- Whether or not the radar should be hidden, e.g. the display is active but the player then steps + -- out of their vehicle + hidden = false, + + cams = { + ["front"] = { + plate = nil, + index = nil + }, + + ["rear"] = { + plate = nil, + index = nil + } + } +} + +function READER:SetPlate( cam, plate ) + self.vars.cams[cam].plate = plate +end + +function READER:SetIndex( cam, index ) + self.vars.cams[cam].index = index +end + +function READER:CanPerformMainTask() + return self.vars.displayed and not self.vars.hidden +end + +function READER:GetCamFromNum( relPos ) + if ( relPos == 1 ) then + return "front" + elseif ( relPos == -1 ) then + return "rear" + end +end + +function READER:Main() + if ( PLY:VehicleStateValid() and self:CanPerformMainTask() ) then + for i = 1, -1, -2 do + local start = GetEntityCoords( PLY.veh ) + local offset = GetOffsetFromEntityInWorldCoords( PLY.veh, 0.0, ( 50.0 * i ), 0.0 ) + local veh = UTIL:GetVehicleInDirection( PLY.veh, start, offset ) + + if ( DoesEntityExist( veh ) and IsEntityAVehicle( veh ) ) then + local plate = GetVehicleNumberPlateText( veh ) + local index = GetVehicleNumberPlateTextIndex( veh ) + + local cam = self:GetCamFromNum( i ) + + self:SetPlate( cam, plate ) + self:SetIndex( cam, index ) + + SendNUIMessage( { _type = "changePlate", cam = cam, plate = plate, index = index } ) + end + end + end +end + +Citizen.CreateThread( function() + while ( true ) do + READER:Main() + + Citizen.Wait( 500 ) + end +end ) --[[---------------------------------------------------------------------------------- Radar variables @@ -273,7 +351,7 @@ function RADAR:ToggleDisplayState() self.vars.displayed = not self.vars.displayed -- Send the toggle message to the NUI side - SendNUIMessage( { _type = "toggleDisplay", state = self:GetDisplayState() } ) + SendNUIMessage( { _type = "setRadarDisplayState", state = self:GetDisplayState() } ) end -- Gets the display state @@ -1547,10 +1625,10 @@ end ) function RADAR:RunDisplayValidationCheck() if ( ( ( PLY.veh == 0 or ( PLY.veh > 0 and not PLY.vehClassValid ) ) and self:GetDisplayState() and not self:GetDisplayHidden() ) or IsPauseMenuActive() and self:GetDisplayState() ) then self:SetDisplayHidden( true ) - SendNUIMessage( { _type = "toggleDisplay", state = false } ) + SendNUIMessage( { _type = "setRadarDisplayState", state = false } ) elseif ( PLY.veh > 0 and PLY.vehClassValid and PLY.inDriverSeat and self:GetDisplayState() and self:GetDisplayHidden() ) then self:SetDisplayHidden( false ) - SendNUIMessage( { _type = "toggleDisplay", state = true } ) + SendNUIMessage( { _type = "setRadarDisplayState", state = true } ) end end diff --git a/cl_utils.lua b/cl_utils.lua index 89a3f81..dec87bf 100644 --- a/cl_utils.lua +++ b/cl_utils.lua @@ -53,7 +53,7 @@ function UTIL:Values( xs ) end function UTIL:GetVehicleInDirection( entFrom, coordFrom, coordTo ) - local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 20.0, 10, entFrom, 7 ) + local rayHandle = StartShapeTestCapsule( coordFrom.x, coordFrom.y, coordFrom.z, coordTo.x, coordTo.y, coordTo.z, 5.0, 10, entFrom, 7 ) local _, hitEntity, endCoords, surfaceNormal, vehicle = GetShapeTestResult( rayHandle ) return vehicle end diff --git a/fxmanifest.lua b/fxmanifest.lua index 0896295..826fb8b 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -19,6 +19,7 @@ files { "nui/jquery-3.4.1.min.js", "nui/radar.js", "nui/images/*", + "nui/images/plates/*", "nui/fonts/*", "nui/sounds/*" } diff --git a/nui/fonts/plate-font-hilite.ttf b/nui/fonts/plate-font-hilite.ttf new file mode 100644 index 0000000..4f25663 Binary files /dev/null and b/nui/fonts/plate-font-hilite.ttf differ diff --git a/nui/fonts/plate-font-lolite.ttf b/nui/fonts/plate-font-lolite.ttf new file mode 100644 index 0000000..a8679d1 Binary files /dev/null and b/nui/fonts/plate-font-lolite.ttf differ diff --git a/nui/fonts/plate-font-shadow.ttf b/nui/fonts/plate-font-shadow.ttf new file mode 100644 index 0000000..e5c9761 Binary files /dev/null and b/nui/fonts/plate-font-shadow.ttf differ diff --git a/nui/fonts/plate-font.ttf b/nui/fonts/plate-font.ttf new file mode 100644 index 0000000..10026aa Binary files /dev/null and b/nui/fonts/plate-font.ttf differ diff --git a/nui/images/plates/plate01.png b/nui/images/plates/0.png similarity index 100% rename from nui/images/plates/plate01.png rename to nui/images/plates/0.png diff --git a/nui/images/plates/plate02.png b/nui/images/plates/1.png similarity index 100% rename from nui/images/plates/plate02.png rename to nui/images/plates/1.png diff --git a/nui/images/plates/plate03.png b/nui/images/plates/2.png similarity index 100% rename from nui/images/plates/plate03.png rename to nui/images/plates/2.png diff --git a/nui/images/plates/plate04.png b/nui/images/plates/3.png similarity index 100% rename from nui/images/plates/plate04.png rename to nui/images/plates/3.png diff --git a/nui/images/plates/plate05.png b/nui/images/plates/4.png similarity index 100% rename from nui/images/plates/plate05.png rename to nui/images/plates/4.png diff --git a/nui/images/plates/yankton_plate.png b/nui/images/plates/5.png similarity index 100% rename from nui/images/plates/yankton_plate.png rename to nui/images/plates/5.png diff --git a/nui/images/pr_bg.png b/nui/images/pr_bg.png new file mode 100644 index 0000000..90382fa Binary files /dev/null and b/nui/images/pr_bg.png differ diff --git a/nui/images/pr_bg.psd b/nui/images/pr_bg.psd new file mode 100644 index 0000000..3a5bccc Binary files /dev/null and b/nui/images/pr_bg.psd differ diff --git a/nui/images/pr_frame.png b/nui/images/pr_frame.png new file mode 100644 index 0000000..88ad627 Binary files /dev/null and b/nui/images/pr_frame.png differ diff --git a/nui/images/pr_frame.psd b/nui/images/pr_frame.psd new file mode 100644 index 0000000..541b851 Binary files /dev/null and b/nui/images/pr_frame.psd differ diff --git a/nui/radar.css b/nui/radar.css index ae9d1fa..7954015 100644 --- a/nui/radar.css +++ b/nui/radar.css @@ -13,6 +13,26 @@ src: url( "fonts/Heebo-Regular.ttf" ); } +@font-face { + 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-face { + 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: 'Heebo', Verdana, Geneva, Tahoma, sans-serif; font-size: 13px; @@ -48,7 +68,7 @@ button:focus { outline: none; } z-index: 1; } -.frame_border { +#radarFrame .frame_border { width: 685px; height: 210px; @@ -543,25 +563,22 @@ button:focus { outline: none; } line-height: 62px; } - #rc .vol_ps_container { + #rc .plate_reader_and_help_container { width: 90%; display: grid; grid-template-columns: 1fr 1fr; justify-items: center; } - #rc .vol_ps_container .vol_and_test, - #rc .vol_ps_container .ps_blank { + #rc .plate_reader_and_help_container .plate_reader, + #rc .plate_reader_and_help_container .help { width: 80px; height: 55px; border-radius: 7px; } - #rc .vol_ps_container .hold { - border-bottom: 2px solid rgb( 0, 0, 0 ); - } - - #rc .vol_ps_container .ps_blank { - padding: 0 10px; + #rc .plate_reader_and_help_container .help { + padding: 0 10px; + font-size: 15px; } #rc .light { @@ -580,11 +597,145 @@ button:focus { outline: none; } #rc .blue { background-color: rgb( 84, 210, 255 ); - } + } + +#plateReaderFrame { + width: 500px; + height: 200px; + + position: absolute; + margin: auto; + + top: calc( 50% - ( 200px / 2 ) ); + left: calc( 50% - ( 500px / 2 ) ); + + background-image: url( "images/pr_frame.png" ); + + transition: transform 0.5s; + + /* Settings for scaling */ + transform: scale( 1.0 ); + transform-origin: 0 0; + + /* background-color: rgb(70, 70, 70); + box-shadow: inset 0px 20px 20px -15px rgba( 0, 0, 0, 0.4 ); */ +} + #plateReaderFrame .frame_border { + width: 465px; + height: 175px; + + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + + background-color: rgb( 20, 22, 18 ); + + border-radius: 5px; + + /* clip-path: polygon( 20px 2px, 665px 2px, 682px 30%, 682px 70%, 665px 208px, 20px 208px, 3px 70%, 3px 30% ); */ + } + +#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 .text { + display: block; + font-family: "Plate-Font"; + font-size: 58px; + text-align: center; + letter-spacing: -3px; + color: rgb(0, 0, 163); + 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 ); + } #uiSettingsBox { width: 250px; - height: 325px; + height: 375px; position: absolute; margin: auto; @@ -617,7 +768,7 @@ button:focus { outline: none; } } #uiSettingsBox .scaling_container { - height: 150px; + height: 225px; display: grid; grid-template-rows: 1fr 1fr; } diff --git a/nui/radar.html b/nui/radar.html index 6b05bf1..b2ece13 100644 --- a/nui/radar.html +++ b/nui/radar.html @@ -6,7 +6,6 @@ -
@@ -153,15 +152,57 @@ -
- - +
+ +
-
+
+ +
+
+ +
+
+

FRONT

+

REAR

+
+ +
+
+ + +
+ +

46EEK872

+

46EEK872

+

46EEK872

+

46EEK872

+
+
+ +
+ + +
+ +

46EEK872

+

46EEK872

+

46EEK872

+

46EEK872

+
+
+
+ +
+

LOCKED

+

LOCKED

+
+
+
@@ -190,6 +231,17 @@
+ +
+
+ +
+

Reader Scale

+

1.00x

+
+ +
+
diff --git a/nui/radar.js b/nui/radar.js index 5ea42c4..37883a5 100644 --- a/nui/radar.js +++ b/nui/radar.js @@ -47,7 +47,9 @@ const lockAudio = const elements = { radar: $( "#radarFrame" ), - remote: $( "#rc" ), + remote: $( "#rc" ), + plateReader: $( "#plateReaderFrame" ), + toggleDisplay: $( "#toggleDisplay" ), pwrBtn: $( "#pwrBtn" ), @@ -67,6 +69,24 @@ const elements = display: $( "#remoteScaleDisplay" ) }, + plateReaderScaling: { + increase: $( "#readerIncreaseScale" ), + decrease: $( "#readerDecreaseScale" ), + display: $( "#readerScaleDisplay" ) + }, + + plates: { + front: { + text: $( "#frontPlateText" ), + img: $( "#frontPlate" ) + }, + + rear: { + text: $( "#rearPlateText" ), + img: $( "#rearPlate" ) + } + }, + safezoneSlider: $( "#safezone" ), safezoneDisplay: $( "#safezoneDisplay" ), @@ -147,6 +167,7 @@ const dirs = ------------------------------------------------------------------------------------*/ elements.radar.hide(); elements.remote.hide(); +// elements.plateReader.hide(); elements.uiSettingsBox.hide(); elements.keyLock.label.hide(); @@ -172,6 +193,11 @@ function setRemoteVisible( state ) state ? elements.remote.fadeIn() : elements.remote.fadeOut(); } +function setPlateReaderVisible( state ) +{ + state ? elements.plateReader.fadeIn() : elements.plateReader.fadeOut(); +} + function setLight( ant, cat, item, state ) { let obj = elements.antennas[ant][cat][item]; @@ -221,6 +247,15 @@ function setAntennaDirs( ant, dir, fastDir ) setLight( ant, "dirs", "bwdFast", fastDir == dirs.away ); } +function setPlate( cam, plate, index ) +{ + elements.plates[cam].img.attr( "src", "images/plates/" + index + ".png" ); + + elements.plates[cam].text.find( "p" ).each( function( i, obj ) { + $( this ).html( plate ); + } ); +} + /*------------------------------------------------------------------------------------ Clearing functions @@ -427,6 +462,12 @@ function sendSaveData() scale: radarScale }, + plateReader: { + left: elements.plateReader.css( "left" ), + top: elements.plateReader.css( "top" ), + scale: readerScale + }, + safezone: safezone } @@ -436,8 +477,8 @@ function sendSaveData() function loadUiSettings( data ) { - // Iterate through "remote" and "radar" - for ( let setting of [ "remote", "radar" ] ) + // Iterate through "remote", "radar" and "plateReader" + for ( let setting of [ "remote", "radar", "plateReader" ] ) { // Iterate through the settings for ( let i of [ "left", "top" ] ) @@ -450,9 +491,10 @@ function loadUiSettings( data ) setScaleAndDisplay( elements[setting], data[setting].scale, elements[setting + "Scaling"].display ); } - // Update the remote and radar scale variables + // Update the remote, radar and reader scale variables remoteScale = data.remote.scale; radarScale = data.radar.scale; + readerScale = data.plateReader.scale; // Set the safezone and update the display elements.safezoneSlider.val( data.safezone ); @@ -465,21 +507,23 @@ function loadUiSettings( data ) ------------------------------------------------------------------------------------*/ var remoteScale = 1.0; var remoteMoving = false; -var remoteLastOffset = [ 0, 0 ]; var remoteOffset = [ 0, 0 ]; var radarScale = 1.0; var radarMoving = false; -var radarLastOffset = [ 0, 0 ]; var radarOffset = [ 0, 0 ]; +var readerScale = 1.0; +var readerMoving = false; +var readerOffset = [ 0, 0 ]; + var windowWidth = 0; var windowHeight = 0; var safezone = 0; // Close the UI settings window when the 'Close' button is pressed elements.closeUiBtn.click( function() { - setUISettingsVisible( false, true ); + setUISettingsVisible( false ); } ) // Set the remote scale buttons to change the remote's scale @@ -500,6 +544,15 @@ elements.radarScaling.decrease.click( function() { 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 ); +} ) + +elements.plateReaderScaling.decrease.click( function() { + readerScale = changeEleScale( elements.plateReader, readerScale, -0.05, elements.plateReaderScaling.display ); +} ) + // Remote mouse down and up event elements.remote.mousedown( function( event ) { remoteMoving = true; @@ -518,10 +571,20 @@ elements.radar.mousedown( function( event ) { radarOffset = getOffset( offset, event.clientX, event.clientY ); } ) +// Plate reader mouse down and up event +elements.plateReader.mousedown( function( event ) { + readerMoving = true; + + let offset = $( this ).offset(); + + readerOffset = getOffset( offset, event.clientX, event.clientY ); +} ) + $( document ).mouseup( function( event ) { // Reset the remote and radar moving variables remoteMoving = false; radarMoving = false; + readerMoving = false; } ) $( document ).mousemove( function( event ) { @@ -541,6 +604,13 @@ $( document ).mousemove( function( event ) { calculatePos( elements.radar, x, y, windowWidth, windowHeight, radarOffset, radarScale, safezone ); } + + if ( readerMoving ) + { + event.preventDefault(); + + calculatePos( elements.plateReader, x, y, windowWidth, windowHeight, readerOffset, readerScale, safezone ); + } } ) $( window ).resize( function() { @@ -582,12 +652,12 @@ function calculatePos( ele, x, y, w, h, offset, scale, safezone ) let topLockGap = topPos + eleHeightPerctHalf; // Lock pos check - if ( leftLockGap >= 48.0 && leftLockGap <= 52.0 ) + if ( leftLockGap >= 49.0 && leftLockGap <= 51.0 ) { leftPos = 50.0 - eleWidthPerctHalf; } - if ( topLockGap >= 48.0 && topLockGap <= 52.0 ) + if ( topLockGap >= 49.0 && topLockGap <= 51.0 ) { topPos = 50.0 - eleHeightPerctHalf; } @@ -610,10 +680,9 @@ function getOffset( offset, x, y ) ] } -function setUISettingsVisible( state, remote ) +function setUISettingsVisible( state ) { state ? elements.uiSettingsBox.fadeIn() : elements.uiSettingsBox.fadeOut(); - // if ( remote ) { setRemoteVisible( !state ); } } function hideUISettings() @@ -630,7 +699,6 @@ function changeEleScale( ele, scaleVar, amount, display ) display.html( scale.toFixed( 2 ) + "x" ); // Tell the system the UI has been edited - // !uiEdited ? uiEdited = true : null; setUiHasBeenEdited( true ); return scale; @@ -680,7 +748,7 @@ function closeRemote() { sendData( "closeRemote", null ); setRemoteVisible( false ); - setUISettingsVisible( false, false ); + setUISettingsVisible( false ); sendSaveData(); } @@ -714,11 +782,10 @@ window.addEventListener( "message", function( event ) { break; case "openRemote": setRemoteVisible( true ); - // uiEdited = false; setUiHasBeenEdited( false ); break; - case "toggleDisplay": - setRadarVisible( item.state ); + case "setRadarDisplayState": + setRadarVisible( item.state ); break; case "radarPower": radarPower( item.state ); @@ -756,6 +823,9 @@ window.addEventListener( "message", function( event ) { case "displayKeyLock": displayKeyLock( item.state ); break; + case "changePlate": + setPlate( item.cam, item.plate, item.index ); + break; default: break; } diff --git a/sv_saving.lua b/sv_saving.lua index e04f12b..4935d8f 100644 --- a/sv_saving.lua +++ b/sv_saving.lua @@ -51,31 +51,38 @@ function DATASAVE:GetPlayerData( src ) return data end +-- Checks that the given data is valid, helps to stop modified data from being sent through the save system function DATASAVE:CheckDataIsValid( data ) -- First we check to make sure the data being passed is actually a table if ( type( data ) ~= "table" ) then return false end - -- Then we check to make sure that the data has only 3 elements, "remote", "radar" and "safezone" + -- Then we check to make sure that the data has only 3 elements, "remote", "radar", "reader" and "safezone" local c = 0 for _ in pairs( data ) do c = c + 1 end - -- If there isn't 3 elements, then the data isn't valid - if ( c ~= 3 ) then return false end + -- If there isn't 4 elements, then the data isn't valid + if ( c ~= 4 ) then return false end return true end +-- Gets the identifier for the given player based on the identifier type specified at the top function DATASAVE:GetIdentifier( src ) + -- Get the number of identifiers the player has local max = GetNumPlayerIdentifiers( src ) + -- Iterate through the identifier numerical range for i = 0, max do + -- Get the current identifier local id = GetPlayerIdentifier( src, i ) + -- In the event the identifier is nil, report it to the server console and return nil if ( id == nil ) then self:Print( "^1It appears there was an error trying to find the specified ID (" .. self.idType .. ") for player " .. GetPlayerName( source ) ) return nil end + -- if ( string.find( id, self.idType, 1 ) ) then local split = self:SplitString( id, ":" ) return split[2]