From 390cce619581d6f49b7a31cbd5751b6159367e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20N=27gadi?= Date: Mon, 11 May 2020 04:21:10 +0200 Subject: [PATCH] single resource concept + first attempt to reorganize code --- .editorconfig | 8 +- client/bootstrap.lua | 17 + client/functions.lua | 126 +- client/main.lua | 207 ++- client/wrapper.lua | 2 +- common/functions.lua | 13 + config.lua | 21 +- fxmanifest.lua | 52 +- hud/app.css | 14 + hud/app.js | 109 ++ hud/index.html | 13 + hud/wrapper.js | 43 + locale.lua | 10 + locales/pl.lua | 175 +- locales/sc.lua | 2 +- locales/tc.lua | 2 +- modules/hud/client/events.lua | 5 + modules/hud/client/main.lua | 4 + modules/hud/client/module.lua | 5 + {html => modules/hud/data/html}/css/app.css | 4 +- .../hud/data/html}/fonts/bankgothic.ttf | Bin .../hud/data/html}/fonts/pdown.ttf | Bin .../hud/data/html}/img/accounts/bank.png | Bin .../data/html}/img/accounts/black_money.png | Bin .../hud/data/html}/img/accounts/money.png | Bin {html => modules/hud/data/html}/js/app.js | 0 .../hud/data/html}/js/mustache.min.js | 0 {html => modules/hud/data/html}/js/wrapper.js | 2 +- {html => modules/hud/data/html}/ui.html | 0 modules/hud/server/events.lua | 2 + modules/hud/server/main.lua | 3 + modules/hud/server/module.lua | 3 + modules/input/client/events.lua | 1 + modules/input/client/main.lua | 67 + modules/input/client/module.lua | 466 +++++ modules/input/server/events.lua | 1 + modules/input/server/main.lua | 1 + modules/input/server/module.lua | 2 + modules/interact/client/events.lua | 12 + modules/interact/client/main.lua | 194 +++ modules/interact/client/module.lua | 47 + modules/interact/server/events.lua | 2 + modules/interact/server/main.lua | 3 + modules/interact/server/module.lua | 3 + modules/job_police/client/events.lua | 311 ++++ modules/job_police/client/main.lua | 157 ++ modules/job_police/client/module.lua | 1517 +++++++++++++++++ modules/job_police/data/config.lua | 319 ++++ modules/job_police/data/locales/br.lua | 151 ++ modules/job_police/data/locales/cs.lua | 151 ++ modules/job_police/data/locales/de.lua | 151 ++ modules/job_police/data/locales/en.lua | 151 ++ modules/job_police/data/locales/es.lua | 151 ++ modules/job_police/data/locales/fi.lua | 151 ++ modules/job_police/data/locales/fr.lua | 151 ++ modules/job_police/data/locales/ko.lua | 151 ++ modules/job_police/data/locales/pl.lua | 151 ++ modules/job_police/data/locales/sv.lua | 151 ++ modules/job_police/server/events.lua | 515 ++++++ modules/job_police/server/main.lua | 15 + modules/job_police/server/module.lua | 31 + modules/menu_default/client/events.lua | 71 + modules/menu_default/client/main.lua | 11 + modules/menu_default/client/module.lua | 26 + modules/menu_default/data/html/css/app.css | 94 + .../data/html/fonts/bankgothic.ttf | Bin 0 -> 36272 bytes .../menu_default/data/html/fonts/pdown.ttf | Bin 0 -> 151512 bytes modules/menu_default/data/html/js/app.js | 346 ++++ .../menu_default/data/html/js/mustache.min.js | 1 + modules/menu_default/data/html/ui.html | 17 + modules/menu_default/server/events.lua | 2 + modules/menu_default/server/main.lua | 3 + modules/menu_default/server/module.lua | 3 + modules/menu_dialog/client/events.lua | 48 + modules/menu_dialog/client/main.lua | 24 + modules/menu_dialog/client/module.lua | 46 + modules/menu_dialog/data/html/css/app.css | 74 + .../data/html/fonts/bankgothic.ttf | Bin 0 -> 36272 bytes modules/menu_dialog/data/html/fonts/pdown.ttf | Bin 0 -> 151512 bytes modules/menu_dialog/data/html/js/app.js | 176 ++ .../menu_dialog/data/html/js/mustache.min.js | 1 + modules/menu_dialog/data/html/ui.html | 17 + modules/menu_dialog/server/events.lua | 2 + modules/menu_dialog/server/main.lua | 3 + modules/menu_dialog/server/module.lua | 3 + modules/menu_list/client/events.lua | 25 + modules/menu_list/client/main.lua | 6 + modules/menu_list/client/module.lua | 47 + modules/menu_list/data/html/css/app.css | 52 + .../menu_list/data/html/fonts/bankgothic.ttf | Bin 0 -> 36272 bytes modules/menu_list/data/html/fonts/pdown.ttf | Bin 0 -> 151512 bytes modules/menu_list/data/html/js/app.js | 192 +++ .../menu_list/data/html/js/mustache.min.js | 1 + modules/menu_list/data/html/ui.html | 16 + modules/menu_list/server/events.lua | 2 + modules/menu_list/server/main.lua | 3 + modules/menu_list/server/module.lua | 3 + server/common.lua | 1 + server/functions.lua | 11 +- server/main.lua | 57 +- 100 files changed, 7118 insertions(+), 282 deletions(-) create mode 100644 client/bootstrap.lua create mode 100644 hud/app.css create mode 100644 hud/app.js create mode 100644 hud/index.html create mode 100644 hud/wrapper.js create mode 100644 modules/hud/client/events.lua create mode 100644 modules/hud/client/main.lua create mode 100644 modules/hud/client/module.lua rename {html => modules/hud/data/html}/css/app.css (98%) rename {html => modules/hud/data/html}/fonts/bankgothic.ttf (100%) rename {html => modules/hud/data/html}/fonts/pdown.ttf (100%) rename {html => modules/hud/data/html}/img/accounts/bank.png (100%) rename {html => modules/hud/data/html}/img/accounts/black_money.png (100%) rename {html => modules/hud/data/html}/img/accounts/money.png (100%) rename {html => modules/hud/data/html}/js/app.js (100%) rename {html => modules/hud/data/html}/js/mustache.min.js (100%) rename {html => modules/hud/data/html}/js/wrapper.js (88%) rename {html => modules/hud/data/html}/ui.html (100%) create mode 100644 modules/hud/server/events.lua create mode 100644 modules/hud/server/main.lua create mode 100644 modules/hud/server/module.lua create mode 100644 modules/input/client/events.lua create mode 100644 modules/input/client/main.lua create mode 100644 modules/input/client/module.lua create mode 100644 modules/input/server/events.lua create mode 100644 modules/input/server/main.lua create mode 100644 modules/input/server/module.lua create mode 100644 modules/interact/client/events.lua create mode 100644 modules/interact/client/main.lua create mode 100644 modules/interact/client/module.lua create mode 100644 modules/interact/server/events.lua create mode 100644 modules/interact/server/main.lua create mode 100644 modules/interact/server/module.lua create mode 100644 modules/job_police/client/events.lua create mode 100644 modules/job_police/client/main.lua create mode 100644 modules/job_police/client/module.lua create mode 100644 modules/job_police/data/config.lua create mode 100644 modules/job_police/data/locales/br.lua create mode 100644 modules/job_police/data/locales/cs.lua create mode 100644 modules/job_police/data/locales/de.lua create mode 100644 modules/job_police/data/locales/en.lua create mode 100644 modules/job_police/data/locales/es.lua create mode 100644 modules/job_police/data/locales/fi.lua create mode 100644 modules/job_police/data/locales/fr.lua create mode 100644 modules/job_police/data/locales/ko.lua create mode 100644 modules/job_police/data/locales/pl.lua create mode 100644 modules/job_police/data/locales/sv.lua create mode 100644 modules/job_police/server/events.lua create mode 100644 modules/job_police/server/main.lua create mode 100644 modules/job_police/server/module.lua create mode 100644 modules/menu_default/client/events.lua create mode 100644 modules/menu_default/client/main.lua create mode 100644 modules/menu_default/client/module.lua create mode 100644 modules/menu_default/data/html/css/app.css create mode 100644 modules/menu_default/data/html/fonts/bankgothic.ttf create mode 100644 modules/menu_default/data/html/fonts/pdown.ttf create mode 100644 modules/menu_default/data/html/js/app.js create mode 100644 modules/menu_default/data/html/js/mustache.min.js create mode 100644 modules/menu_default/data/html/ui.html create mode 100644 modules/menu_default/server/events.lua create mode 100644 modules/menu_default/server/main.lua create mode 100644 modules/menu_default/server/module.lua create mode 100644 modules/menu_dialog/client/events.lua create mode 100644 modules/menu_dialog/client/main.lua create mode 100644 modules/menu_dialog/client/module.lua create mode 100644 modules/menu_dialog/data/html/css/app.css create mode 100644 modules/menu_dialog/data/html/fonts/bankgothic.ttf create mode 100644 modules/menu_dialog/data/html/fonts/pdown.ttf create mode 100644 modules/menu_dialog/data/html/js/app.js create mode 100644 modules/menu_dialog/data/html/js/mustache.min.js create mode 100644 modules/menu_dialog/data/html/ui.html create mode 100644 modules/menu_dialog/server/events.lua create mode 100644 modules/menu_dialog/server/main.lua create mode 100644 modules/menu_dialog/server/module.lua create mode 100644 modules/menu_list/client/events.lua create mode 100644 modules/menu_list/client/main.lua create mode 100644 modules/menu_list/client/module.lua create mode 100644 modules/menu_list/data/html/css/app.css create mode 100644 modules/menu_list/data/html/fonts/bankgothic.ttf create mode 100644 modules/menu_list/data/html/fonts/pdown.ttf create mode 100644 modules/menu_list/data/html/js/app.js create mode 100644 modules/menu_list/data/html/js/mustache.min.js create mode 100644 modules/menu_list/data/html/ui.html create mode 100644 modules/menu_list/server/events.lua create mode 100644 modules/menu_list/server/main.lua create mode 100644 modules/menu_list/server/module.lua diff --git a/.editorconfig b/.editorconfig index 9b425256..4bfca33b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,9 @@ root = true [*] -indent_size = 4 -indent_style = tab -end_of_line = crlf +indent_size = 2 +indent_style = space +end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file +insert_final_newline = true diff --git a/client/bootstrap.lua b/client/bootstrap.lua new file mode 100644 index 00000000..e658763c --- /dev/null +++ b/client/bootstrap.lua @@ -0,0 +1,17 @@ +OnESX = function(cb) + + local ESX = nil + + Citizen.CreateThread(function() + + while ESX == nil do + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + Citizen.Wait(0) + end + + cb(ESX) + + end) + +end + diff --git a/client/functions.lua b/client/functions.lua index aced3015..06db3e2d 100644 --- a/client/functions.lua +++ b/client/functions.lua @@ -1,4 +1,5 @@ ESX = {} +ESX.Modules = {} ESX.PlayerData = {} ESX.PlayerLoaded = false ESX.CurrentRequestId = 0 @@ -32,6 +33,30 @@ ESX.ClearTimeout = function(i) ESX.TimeoutCallbacks[i] = nil end +ESX.CreateFrame = function(name, url, visible) + visible = (visible == nil) and true or false + SendNUIMessage({action = 'create_frame', name = name, url = url, visible = visible}) +end + +ESX.SendFrameMessage = function(name, msg) + SendNUIMessage({target = name, data = msg}) +end + +ESX.FocusFrame = function(name, cursor) + SendNUIMessage({action = 'focus_frame', name = name}) + SetNuiFocus(true, cursor) +end + +RegisterNUICallback('nui_ready', function(data, cb) + TriggerEvent('esx:nui_ready') + cb('') +end) + +RegisterNUICallback('frame_message', function(data, cb) + TriggerEvent('esx:frame_message', data.name, data.msg, data.cb) + cb('') +end) + ESX.IsPlayerLoaded = function() return ESX.PlayerLoaded end @@ -44,41 +69,66 @@ ESX.SetPlayerData = function(key, val) ESX.PlayerData[key] = val end -ESX.ShowNotification = function(msg, flash, saveToBrief, hudColorIndex) - if saveToBrief == nil then saveToBrief = true end - AddTextEntry('esxNotification', msg) - BeginTextCommandThefeedPost('esxNotification') - if hudColorIndex then ThefeedNextPostBackgroundColor(hudColorIndex) end - EndTextCommandThefeedPostTicker(flash or false, saveToBrief) +ESX.ShowNotification = function(msg) + SetNotificationTextEntry('STRING') + AddTextComponentString(msg) + DrawNotification(0,1) end ESX.ShowAdvancedNotification = function(sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) - if saveToBrief == nil then saveToBrief = true end - AddTextEntry('esxAdvancedNotification', msg) - BeginTextCommandThefeedPost('esxAdvancedNotification') - if hudColorIndex then ThefeedNextPostBackgroundColor(hudColorIndex) end + + if saveToBrief == nil then + saveToBrief = true + end + + BeginTextCommandThefeedPost('STRING') + AddTextComponentSubstringPlayerName(msg) + + if hudColorIndex then + ThefeedNextPostBackgroundColor(hudColorIndex) + end + EndTextCommandThefeedPostMessagetext(textureDict, textureDict, false, iconType, sender, subject) - EndTextCommandThefeedPostTicker(flash or false, saveToBrief) + EndTextCommandThefeedPostTicker(flash or false, saveToBrief) + end ESX.ShowHelpNotification = function(msg, thisFrame, beep, duration) - AddTextEntry('esxHelpNotification', msg) + + BeginTextCommandDisplayHelp('STRING') + AddTextComponentSubstringPlayerName(msg) if thisFrame then - DisplayHelpTextThisFrame('esxHelpNotification', false) + DisplayHelpTextThisFrame(msg, false) else if beep == nil then beep = true end BeginTextCommandDisplayHelp('esxHelpNotification') EndTextCommandDisplayHelp(0, false, beep, duration or -1) - end + end + end -ESX.ShowFloatingHelpNotification = function(msg, coords) - AddTextEntry('esxFloatingHelpNotification', msg) - SetFloatingHelpTextWorldPosition(1, coords) - SetFloatingHelpTextStyle(1, 1, 2, -1, 3, 0) - BeginTextCommandDisplayHelp('esxFloatingHelpNotification') - EndTextCommandDisplayHelp(2, false, false, -1) +ESX.ShowFloatingHelpNotification = function(msg, coords, timeout) + + timeout = timeout or 5000 + local start = GetGameTimer() + + Citizen.CreateThread(function() + + while (GetGameTimer() - start) < timeout do + + SetFloatingHelpTextWorldPosition(1, coords.x, coords.y, coords.z) + SetFloatingHelpTextStyle(1, 1, 2, -1, 3, 0) + BeginTextCommandDisplayHelp('STRING') + AddTextComponentSubstringPlayerName(msg) + EndTextCommandDisplayHelp(2, false, true, -1) + + Citizen.Wait(0) + + end + + end) + end ESX.TriggerServerCallback = function(name, cb, ...) @@ -94,7 +144,7 @@ ESX.TriggerServerCallback = function(name, cb, ...) end ESX.UI.HUD.SetDisplay = function(opacity) - SendNUIMessage({ + ESX.SendFrameMessage('hud', { action = 'setHUDDisplay', opacity = opacity }) @@ -116,7 +166,7 @@ ESX.UI.HUD.RegisterElement = function(name, index, priority, html, data) table.insert(ESX.UI.HUD.RegisteredElements, name) - SendNUIMessage({ + ESX.SendFrameMessage('hud', { action = 'insertHUDElement', name = name, index = index, @@ -136,14 +186,14 @@ ESX.UI.HUD.RemoveElement = function(name) end end - SendNUIMessage({ + ESX.SendFrameMessage('hud', { action = 'deleteHUDElement', name = name }) end ESX.UI.HUD.UpdateElement = function(name, data) - SendNUIMessage({ + ESX.SendFrameMessage('hud', { action = 'updateHUDElement', name = name, data = data @@ -281,7 +331,7 @@ ESX.UI.Menu.IsOpen = function(type, namespace, name) end ESX.UI.ShowInventoryItemNotification = function(add, item, count) - SendNUIMessage({ + ESX.SendFrameMessage('hud', { action = 'inventoryNotification', add = add, item = item, @@ -487,7 +537,7 @@ end ESX.Game.GetClosestObject = function(coords, modelFilter) return ESX.Game.GetClosestEntity(ESX.Game.GetObjects(), false, coords, modelFilter) end ESX.Game.GetClosestPed = function(coords, modelFilter) return ESX.Game.GetClosestEntity(ESX.Game.GetPeds(true), false, coords, modelFilter) end -ESX.Game.GetClosestPlayer = function(coords) return ESX.Game.GetClosestEntity(ESX.Game.GetPlayers(true, true), true, coords, nil) end +ESX.Game.GetClosestPlayer = function(coords, modelFilter) return ESX.Game.GetClosestEntity(ESX.Game.GetPlayers(true, true), true, coords, modelFilter) end ESX.Game.GetClosestVehicle = function(coords, modelFilter) return ESX.Game.GetClosestEntity(ESX.Game.GetVehicles(), false, coords, modelFilter) end ESX.Game.GetPlayersInArea = function(coords, maxDistance) return EnumerateEntitiesWithinDistance(ESX.Game.GetPlayers(true, true), true, coords, maxDistance) end ESX.Game.GetVehiclesInArea = function(coords, maxDistance) return EnumerateEntitiesWithinDistance(ESX.Game.GetVehicles(), false, coords, maxDistance) end @@ -559,7 +609,6 @@ ESX.Game.GetVehicleProperties = function(vehicle) bodyHealth = ESX.Math.Round(GetVehicleBodyHealth(vehicle), 1), engineHealth = ESX.Math.Round(GetVehicleEngineHealth(vehicle), 1), - tankHealth = ESX.Math.Round(GetVehiclePetrolTankHealth(vehicle), 1), fuelLevel = ESX.Math.Round(GetVehicleFuelLevel(vehicle), 1), dirtLevel = ESX.Math.Round(GetVehicleDirtLevel(vehicle), 1), @@ -649,7 +698,6 @@ ESX.Game.SetVehicleProperties = function(vehicle, props) if props.plateIndex then SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex) end if props.bodyHealth then SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0) end if props.engineHealth then SetVehicleEngineHealth(vehicle, props.engineHealth + 0.0) end - if props.tankHealth then SetVehiclePetrolTankHealth(vehicle, props.tankHealth + 0.0) end if props.fuelLevel then SetVehicleFuelLevel(vehicle, props.fuelLevel + 0.0) end if props.dirtLevel then SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0) end if props.color1 then SetVehicleColours(vehicle, props.color1, colorSecondary) end @@ -932,10 +980,15 @@ ESX.ShowInventory = function() ESX.Streaming.RequestAnimDict(dict) if type == 'item_weapon' then + menu1.close() - TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false) - Citizen.Wait(1000) - TriggerServerEvent('esx:removeInventoryItem', type, item) + + Citizen.CreateThread(function() + TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false) + Citizen.Wait(1000) + TriggerServerEvent('esx:removeInventoryItem', type, item) + end) + else ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'inventory_item_count_remove', { title = _U('amount') @@ -943,11 +996,16 @@ ESX.ShowInventory = function() local quantity = tonumber(data2.value) if quantity and quantity > 0 and data.current.count >= quantity then + menu2.close() menu1.close() - TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false) - Citizen.Wait(1000) - TriggerServerEvent('esx:removeInventoryItem', type, item, quantity) + + Citizen.CreateThread(function() + TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false) + Citizen.Wait(1000) + TriggerServerEvent('esx:removeInventoryItem', type, item, quantity) + end) + else ESX.ShowNotification(_U('amount_invalid')) end diff --git a/client/main.lua b/client/main.lua index 3f1e9c30..a66d515f 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,4 +1,4 @@ -local isPaused, isDead, pickups = false, false, {} +local isLoadoutLoaded, isPaused, pickups = false, false, {} Citizen.CreateThread(function() while true do @@ -13,35 +13,17 @@ end) RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(playerData) - ESX.PlayerLoaded = true + + ESX.PlayerLoaded = true ESX.PlayerData = playerData - -- check if player is coming from loading screen - if GetEntityModel(PlayerPedId()) == GetHashKey('PLAYER_ZERO') then - local defaultModel = GetHashKey('a_m_y_stbla_02') - RequestModel(defaultModel) + local playerPed = PlayerPedId() - while not HasModelLoaded(defaultModel) do - Citizen.Wait(10) - end - - SetPlayerModel(PlayerId(), defaultModel) - SetPedDefaultComponentVariation(PlayerPedId()) - SetPedRandomComponentVariation(PlayerPedId(), true) - SetModelAsNoLongerNeeded(defaultModel) + if Config.EnablePvP then + SetCanAttackFriendly(playerPed, true, false) + NetworkSetFriendlyFireOption(true) end - -- freeze the player - FreezeEntityPosition(PlayerPedId(), true) - - -- enable PVP - SetCanAttackFriendly(PlayerPedId(), true, false) - NetworkSetFriendlyFireOption(true) - - -- disable wanted level - ClearPlayerWantedLevel(PlayerId()) - SetMaxWantedLevel(0) - if Config.EnableHud then for k,v in ipairs(playerData.accounts) do local accountTpl = '
 {{money}}
' @@ -60,42 +42,47 @@ AddEventHandler('esx:playerLoaded', function(playerData) }) end - ESX.Game.Teleport(PlayerPedId(), { - x = playerData.coords.x, - y = playerData.coords.y, - z = playerData.coords.z + 0.25, - heading = playerData.coords.heading - }, function() + -- Bringing back spawnmanager, see commit of Smallo92 at https://github.com/extendedmode/extendedmode/commit/9979c204f1237091e94fdd46580c9e7ebc79bca7 + exports.spawnmanager:spawnPlayer({ + x = playerData.coords.x, + y = playerData.coords.y, + z = playerData.coords.z, + heading = playerData.coords.heading, + model = 'mp_m_freemode_01', + skipFade = false + }, function() + TriggerServerEvent('esx:onPlayerSpawn') TriggerEvent('esx:onPlayerSpawn') - TriggerEvent('playerSpawned') -- compatibility with old scripts, will be removed soon - TriggerEvent('esx:restoreLoadout') + TriggerEvent('esx:restoreLoadout') + + StartServerSyncLoops() + + end) - Citizen.Wait(3000) - ShutdownLoadingScreen() - FreezeEntityPosition(PlayerPedId(), false) - DoScreenFadeIn(10000) - StartServerSyncLoops() - end) end) RegisterNetEvent('esx:setMaxWeight') AddEventHandler('esx:setMaxWeight', function(newMaxWeight) ESX.PlayerData.maxWeight = newMaxWeight end) -AddEventHandler('esx:onPlayerSpawn', function() isDead = false end) -AddEventHandler('esx:onPlayerDeath', function() isDead = true end) +AddEventHandler('esx:onPlayerSpawn', function() ESX.IsDead = false end) +AddEventHandler('esx:onPlayerDeath', function() ESX.IsDead = true end) +AddEventHandler('skinchanger:loadDefaultModel', function() isLoadoutLoaded = false end) AddEventHandler('skinchanger:modelLoaded', function() - while not ESX.PlayerLoaded do + + while not ESX.PlayerLoaded do Citizen.Wait(100) end - TriggerEvent('esx:restoreLoadout') + TriggerEvent('esx:restoreLoadout') + end) AddEventHandler('esx:restoreLoadout', function() local playerPed = PlayerPedId() local ammoTypes = {} + RemoveAllPedWeapons(playerPed, true) for k,v in ipairs(ESX.PlayerData.loadout) do @@ -109,6 +96,7 @@ AddEventHandler('esx:restoreLoadout', function() for k2,v2 in ipairs(v.components) do local componentHash = ESX.GetWeaponComponent(weaponName, v2).hash + GiveWeaponComponentToPed(playerPed, weaponHash, componentHash) end @@ -117,6 +105,8 @@ AddEventHandler('esx:restoreLoadout', function() ammoTypes[ammoType] = true end end + + isLoadoutLoaded = true end) RegisterNetEvent('esx:setAccountMoney') @@ -245,7 +235,7 @@ RegisterNetEvent('esx:setJob') AddEventHandler('esx:setJob', function(job) if Config.EnableHud then ESX.UI.HUD.UpdateElement('job', { - job_label = job.label, + job_label = job.label, grade_label = job.grade_label }) end @@ -268,42 +258,91 @@ AddEventHandler('esx:spawnVehicle', function(vehicleName) end) RegisterNetEvent('esx:createPickup') -AddEventHandler('esx:createPickup', function(pickupId, label, coords, type, name, components, tintIndex) - local function setObjectProperties(object) - SetEntityAsMissionEntity(object, true, false) - PlaceObjectOnGroundProperly(object) - FreezeEntityPosition(object, true) - SetEntityCollision(object, false, true) +AddEventHandler('esx:createPickup', function(pickupId, label, playerId, type, name, components, tintIndex) + + local playerPed = GetPlayerPed(GetPlayerFromServerId(playerId)) + local entityCoords, forwardVector = GetEntityCoords(playerPed), GetEntityForwardVector(playerPed) + local objectCoords = (entityCoords + forwardVector * 1.0) + + local function setupPickup(obj) + + SetEntityAsMissionEntity(obj, true, false) + PlaceObjectOnGroundProperly(obj) + FreezeEntityPosition(obj, true) + SetEntityCollision(obj, false, true) pickups[pickupId] = { - obj = object, + obj = obj, label = label, inRange = false, - coords = vector3(coords.x, coords.y, coords.z) + coords = objectCoords } + end if type == 'item_weapon' then - local weaponHash = GetHashKey(name) - ESX.Streaming.RequestWeaponAsset(weaponHash) - local pickupObject = CreateWeaponObject(weaponHash, 50, coords.x, coords.y, coords.z, true, 1.0, 0) - SetWeaponObjectTintIndex(pickupObject, tintIndex) - for k,v in ipairs(components) do - local component = ESX.GetWeaponComponent(name, v) - GiveWeaponComponentToWeaponObject(pickupObject, component.hash) - end + Citizen.CreateThread(function() + + local weaponHash = GetHashKey(name) + + ESX.Streaming.RequestWeaponAsset(weaponHash) + local pickupObject = CreateWeaponObject(weaponHash, 50, objectCoords, true, 1.0, 0) + SetWeaponObjectTintIndex(pickupObject, tintIndex) + + for k,v in ipairs(components) do + local component = ESX.GetWeaponComponent(name, v) + GiveWeaponComponentToWeaponObject(pickupObject, component.hash) + end + + setupPickup(pickupObject) + + end) - setObjectProperties(pickupObject) else - ESX.Game.SpawnLocalObject('prop_money_bag_01', coords, setObjectProperties) + + ESX.Game.SpawnLocalObject('prop_money_bag_01', objectCoords, function(obj) + setupPickup(obj) + end) end end) + RegisterNetEvent('esx:createMissingPickups') AddEventHandler('esx:createMissingPickups', function(missingPickups) for pickupId,pickup in pairs(missingPickups) do - TriggerEvent('esx:createPickup', pickupId, pickup.label, pickup.coords, pickup.type, pickup.name, pickup.components, pickup.tintIndex) + local pickupObject = nil + + if pickup.type == 'item_weapon' then + ESX.Streaming.RequestWeaponAsset(GetHashKey(pickup.name)) + pickupObject = CreateWeaponObject(GetHashKey(pickup.name), 50, pickup.coords.x, pickup.coords.y, pickup.coords.z, true, 1.0, 0) + SetWeaponObjectTintIndex(pickupObject, pickup.tintIndex) + + for k,componentName in ipairs(pickup.components) do + local component = ESX.GetWeaponComponent(pickup.name, componentName) + GiveWeaponComponentToWeaponObject(pickupObject, component.hash) + end + else + ESX.Game.SpawnLocalObject('prop_money_bag_01', pickup.coords, function(obj) + pickupObject = obj + end) + + while not pickupObject do + Citizen.Wait(10) + end + end + + SetEntityAsMissionEntity(pickupObject, true, false) + PlaceObjectOnGroundProperly(pickupObject) + FreezeEntityPosition(pickupObject, true) + SetEntityCollision(pickupObject, false, true) + + pickups[pickupId] = { + obj = pickupObject, + label = pickup.label, + inRange = false, + coords = vector3(pickup.coords.x, pickup.coords.y, pickup.coords.z) + } end end) @@ -387,7 +426,7 @@ function StartServerSyncLoops() while true do Citizen.Wait(0) - if isDead then + if ESX.IsDead then Citizen.Wait(500) else local playerPed = PlayerPedId() @@ -428,17 +467,20 @@ function StartServerSyncLoops() end) end -Citizen.CreateThread(function() - while true do - Citizen.Wait(0) +-- Disable wanted level +if Config.DisableWantedLevel then + Citizen.CreateThread(function() + while true do + Citizen.Wait(0) + local playerId = PlayerId() - if IsControlJustReleased(0, 289) then - if IsInputDisabled(0) and not isDead and not ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then - ESX.ShowInventory() + if GetPlayerWantedLevel(playerId) ~= 0 then + SetPlayerWantedLevel(playerId, 0, false) + SetPlayerWantedLevelNow(playerId, false) end end - end -end) + end) +end -- Pickups Citizen.CreateThread(function() @@ -470,14 +512,14 @@ Citizen.CreateThread(function() end end - label = ('%s~n~%s'):format(label, _U('threw_pickup_prompt')) end - ESX.Game.Utils.DrawText3D({ + ESX.ShowFloatingHelpNotification(label, { x = pickup.coords.x, y = pickup.coords.y, z = pickup.coords.z + 0.25 - }, label, 1.2, 1) + }, 100) + elseif pickup.inRange then pickup.inRange = false end @@ -488,3 +530,18 @@ Citizen.CreateThread(function() end end end) + +AddEventHandler('luaconsole:getHandlers', function(cb) + + local name = GetCurrentResourceName() + + cb(name, function(code, env) + if env ~= nil then + for k,v in pairs(env) do _ENV[k] = v end + return load(code, 'lc:' .. name, 'bt', _ENV) + else + return load(code, 'lc:' .. name, 'bt') + end + end) + +end) diff --git a/client/wrapper.lua b/client/wrapper.lua index 441312d8..382e08de 100644 --- a/client/wrapper.lua +++ b/client/wrapper.lua @@ -6,7 +6,7 @@ RegisterNUICallback('__chunk', function(data, cb) if data['end'] then local msg = json.decode(Chunks[data.id]) - TriggerEvent(GetCurrentResourceName() .. ':message:' .. data.__type, msg) + TriggerEvent(data.__namespace .. ':message:' .. data.__type, msg) Chunks[data.id] = nil end diff --git a/common/functions.lua b/common/functions.lua index e47b5b7f..ff4099eb 100644 --- a/common/functions.lua +++ b/common/functions.lua @@ -4,6 +4,19 @@ for i = 48, 57 do table.insert(Charset, string.char(i)) end for i = 65, 90 do table.insert(Charset, string.char(i)) end for i = 97, 122 do table.insert(Charset, string.char(i)) end +-- Be careful with this, use it for some config file parsing and such +ESX.EvalFile = function(resource, file, env) + + env = env or {} + env._G = env + local code = LoadResourceFile(resource, file) + + load(code, code, 't', env)() + + return env + +end + ESX.GetRandomString = function(length) math.randomseed(GetGameTimer()) diff --git a/config.lua b/config.lua index 8f6134ff..acba2923 100644 --- a/config.lua +++ b/config.lua @@ -10,21 +10,12 @@ Config.Accounts = { Config.StartingAccountMoney = {bank = 50000} Config.EnableSocietyPayouts = false -- pay from the society account that the player is employed at? Requirement: esx_society +Config.DisableWantedLevel = true Config.EnableHud = true -- enable the default hud? Display current job and accounts (black, bank & cash) +Config.EnablePvP = true -- enable pvp? Config.MaxWeight = 24 -- the max inventory weight without backpack -Config.PaycheckInterval = 7 * 60000 -- how often to recieve pay checks in milliseconds -Config.EnableDebug = false -Config.IncompatibleResourcesToStop = { - ['essentialmode'] = 'ES for short, the performance heavy RP framework no one uses - and source for the random unwanted ZAP ads you\'re seeing', - ['es_admin2'] = 'Adminstration tool for the ancient ES framework that wont work with ESX', - ['esplugin_mysql'] = 'MySQL "plugin" for the ancient ES framework that has a SQL injection vulnerability', - ['es_ui'] = 'Money HUD for ES', - ['spawnmanager'] = 'Default resource that takes care of spawning players, ESX does this already', - ['mapmanager'] = 'Default resource that was required by spawnmanager, but neither are used', - ['basic-gamemode'] = 'Resource that is solely for choosing the default game type', - ['fivem'] = 'Resource that is solely for choosing the default game type', - ['fivem-map-hipster'] = 'Default spawn locations for mapmanager', - ['fivem-map-skater'] = 'Default spawn locations for mapmanager', - ['baseevents'] = 'Default resource for handling death events, ESX does this already' -} +Config.PaycheckInterval = 7 * 60000 -- how often to recieve pay checks in milliseconds + +Config.EnableDebug = false +Config.InventoryKey = 'REPLAY_START_STOP_RECORDING_SECONDARY' -- Key F2 by default diff --git a/fxmanifest.lua b/fxmanifest.lua index 0f1c2f78..77150781 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ES Extended' -version '1.2.0' +version '2.0.0' server_scripts { '@async/async.lua', @@ -65,40 +65,54 @@ client_scripts { 'common/modules/math.lua', 'common/modules/table.lua', - 'common/functions.lua' + 'common/functions.lua', } ui_page { - 'html/ui.html' + 'hud/index.html' } files { + 'client/bootstrap.lua', 'locale.js', - 'html/ui.html', - - 'html/css/app.css', - - 'html/js/mustache.min.js', - 'html/js/wrapper.js', - 'html/js/app.js', - - 'html/fonts/pdown.ttf', - 'html/fonts/bankgothic.ttf', - - 'html/img/accounts/bank.png', - 'html/img/accounts/black_money.png', - 'html/img/accounts/money.png' + 'hud/**/*', } exports { - 'getSharedObject' + 'getSharedObject', + 'OnESX', } server_exports { - 'getSharedObject' + 'getSharedObject', + 'OnESX', } dependencies { 'mysql-async', 'async' } + +-- ESX Modules +esxmodule = function(name) + + file('modules/' .. name .. '/data/**/*') + + client_script('modules/' .. name .. '/client/module.lua') + client_script('modules/' .. name .. '/client/main.lua') + client_script('modules/' .. name .. '/client/events.lua') + + server_script('modules/' .. name .. '/server/module.lua') + server_script('modules/' .. name .. '/server/main.lua') + server_script('modules/' .. name .. '/server/events.lua') + +end + +esxmodule 'input' +esxmodule 'hud' +esxmodule 'menu_default' +esxmodule 'menu_dialog' +esxmodule 'menu_list' +esxmodule 'interact' + +esxmodule 'job_police' diff --git a/hud/app.css b/hud/app.css new file mode 100644 index 00000000..d1ab073f --- /dev/null +++ b/hud/app.css @@ -0,0 +1,14 @@ +html, body, #frames, #frames > div, #frames > div > iframe { + width : 100vw; + height : 100vh; + margin : 0; + padding : 0; + border : 0; + background-color: transparent; +} + +#frames > div, #frames > div > iframe { + position: absolute; + left: 0; + top: 0; +} diff --git a/hud/app.js b/hud/app.js new file mode 100644 index 00000000..2a821f5a --- /dev/null +++ b/hud/app.js @@ -0,0 +1,109 @@ +(() => { + + class ESX { + + constructor() { + + this.frames = {}; + this.modulePath = '../modules'; + + window.addEventListener('message', e => this.onMessage(e.data)); + + $.post('http://es_extended/nui_ready', '{}'); + + } + + createFrame(name, url, visible = true) { + + const frame = document.createElement('div'); + const iframe = document.createElement('iframe'); + + frame.appendChild(iframe); + + iframe.src = url; + this.frames[name] = {frame, iframe}; + + this.frames[name].iframe.addEventListener('message', e => this.onFrameMessage(name, e.data)); + this.frames[name].frame.style.pointerEvents = 'none'; + + document.querySelector('#frames').appendChild(frame); + + if(!visible) + this.hideFrame(name); + + return this.frames[name]; + + } + + destroyFrame(name) { + document.querySelector('#frames').removeChild(this.frames[name].frame); + this.frames[name].frame.remove(); + } + + showFrame(name) { + this.frames[name].frame.style.display = 'block'; + } + + hideFrame(name) { + this.frames[name].frame.style.display = 'none'; + } + + focusFrame(name) { + + for(let k in this.frames) { + + if(k === name) + this.frames[k].frame.style.pointerEvents = 'all'; + else + this.frames[k].frame.style.pointerEvents = 'none'; + } + + this.frames[name].iframe.contentWindow.focus(); + + } + + onMessage(msg) { + + if(msg.target) { + + if(this.frames[msg.target]) + this.frames[msg.target].iframe.contentWindow.postMessage(msg.data); + else + console.error('[esx:nui] cannot find frame : ' + msg.target); + + } else { + + switch(msg.action) { + + case 'create_frame' : { + this.createFrame(msg.name, msg.url, msg.visible); + break; + } + + case 'destroy_frame' : { + this.destroyFrame(msg.name); + break; + } + + case 'focus_frame' : { + this.focusFrame(msg.name); + break; + } + + default: break; + } + + } + + + } + + onFrameMessage(name, msg) { + $.post('http://es_extended/frame_message', JSON.stringify({name, msg})); + } + + } + + ESX = new ESX(); + +})(); diff --git a/hud/index.html b/hud/index.html new file mode 100644 index 00000000..cf60df14 --- /dev/null +++ b/hud/index.html @@ -0,0 +1,13 @@ + + + esx + + + + +
+ + + + + diff --git a/hud/wrapper.js b/hud/wrapper.js new file mode 100644 index 00000000..df9523c9 --- /dev/null +++ b/hud/wrapper.js @@ -0,0 +1,43 @@ +(() => { + + let ESXWrapper = {}; + ESXWrapper.MessageSize = 1024; + ESXWrapper.messageId = 0; + + window.SendMessage = function (namespace, type, msg) { + + ESXWrapper.messageId = (ESXWrapper.messageId < 65535) ? ESXWrapper.messageId + 1 : 0; + const str = JSON.stringify(msg); + + for (let i = 0; i < str.length; i++) { + + let count = 0; + let chunk = ''; + + while (count < ESXWrapper.MessageSize && i < str.length) { + + chunk += str[i]; + + count++; + i++; + } + + i--; + + const data = { + __namespace: namespace, + __type: type, + id: ESXWrapper.messageId, + chunk: chunk + } + + if (i == str.length - 1) + data.end = true; + + $.post('http://es_extended/__chunk', JSON.stringify(data)); + + } + + } + +})() diff --git a/locale.lua b/locale.lua index 68de6651..c092385d 100644 --- a/locale.lua +++ b/locale.lua @@ -19,3 +19,13 @@ end function _U(str, ...) -- Translate string first char uppercase return tostring(_(str, ...):gsub("^%l", string.upper)) end + +function LoadLocale(ns, lang, data) + + Locales[lang] = Locales[lang] or {} + + for k,v in pairs(data) do + Locales[lang][ns .. ':' .. k] =v + end + +end diff --git a/locales/pl.lua b/locales/pl.lua index 35012487..2a04b378 100644 --- a/locales/pl.lua +++ b/locales/pl.lua @@ -10,9 +10,9 @@ Locales['pl'] = { ['giveammo'] = 'daj amunicje', ['amountammo'] = 'ilość amunicji', ['noammo'] = 'nie posiadasz wystarczającej ilości amunicji!', - ['gave_item'] = 'dałeś/aś ~y~%sx~s~ ~b~%s~s~ dla ~y~%s~s~', - ['received_item'] = 'otrzymałeś/aś ~y~%sx~s~ ~b~%s~s~ od ~b~%s~s~', - ['gave_weapon'] = 'dałeś/aś ~b~%s~s~ dla ~y~%s~s~', + ['gave_item'] = 'dajesz ~y~%sx~s~ ~b~%s~s~ dla ~y~%s~s~', + ['received_item'] = 'otrzymujesz ~y~%sx~s~ ~b~%s~s~ od ~b~%s~s~', + ['gave_weapon'] = 'dajesz ~b~%s~s~ dla ~y~%s~s~', ['gave_weapon_ammo'] = 'dałeś/aś ~o~%sx %s~s~ do ~b~%s~s~ dla ~y~%s~s~', ['gave_weapon_withammo'] = 'dałeś/aś ~b~%s~s~ z ~o~%sx %s~s~ dla ~y~%s~s~', ['gave_weapon_hasalready'] = '~y~%s~s~ już posiada ~y~%s~s~', @@ -22,8 +22,8 @@ Locales['pl'] = { ['received_weapon_withammo'] = 'otrzymałeś/aś ~b~%s~s~ z ~o~%sx %s~s~ od ~b~%s~s~', ['received_weapon_hasalready'] = '~b~%s~s~ próbował/a przekazać ci ~y~%s~s~, lecz już posiadasz jedno', ['received_weapon_noweapon'] = '~b~%s~s~ próbował/a przekazać ci amunicje do ~y~%s~s~, lecz nie posiadasz tej broni', - ['gave_account_money'] = 'dałeś/aś ~g~%s$~s~ (%s) dla ~y~%s~s~', - ['received_account_money'] = 'otrzymałeś/aś ~g~%s$~s~ (%s) od ~b~%s~s~', + ['gave_account_money'] = 'dajesz ~g~%s$~s~ (%s) dla ~y~%s~s~', + ['received_account_money'] = 'otrzymujesz ~g~%s$~s~ (%s) od ~b~%s~s~', ['amount_invalid'] = 'nieprawidłowa ilość', ['players_nearby'] = 'brak graczy w pobliżu', ['ex_inv_lim'] = 'akcja nie jest możliwa, nie możesz mieć więcej ~y~%s~s~', @@ -33,75 +33,76 @@ Locales['pl'] = { ['threw_account'] = 'wyrzuciłeś/aś ~g~$%s~s~ ~b~%s~s~', ['threw_weapon'] = 'wyrzuciłeś/aś ~b~%s~s~', ['threw_weapon_ammo'] = 'wyrzuciłeś/aś ~b~%s~s~ z ~o~%sx %s~s~', - ['threw_weapon_already'] = 'już posiadasz taką samą broń', - ['threw_cannot_pickup'] = 'nie możesz tego podnieść, gdyż masz pełny ekwipunek!', - ['threw_pickup_prompt'] = 'naciśnij ~y~E~s~ aby podnieść', + ['threw_weapon_already'] = 'you already carry the same weapon', + ['threw_cannot_pickup'] = 'you cannot pickup that because your inventory is full!', + ['threw_pickup_prompt'] = 'press ~y~E~s~ to pickup', -- Key mapping - ['keymap_showinventory'] = 'pokaż ekwipunek', + ['keymap_showinventory'] = 'show Inventory', -- Salary related - ['received_salary'] = 'otrzymałeś/aś wynagrodzenie: ~g~%s$~s~', - ['received_help'] = 'otrzymałeś/aś zapomogę: ~g~$%s~s~', + ['received_salary'] = 'otrzymałeś wynagrodzenie: ~g~%s$~s~', + ['received_help'] = 'otrzymałem zapomogę: ~g~$%s~s~', ['company_nomoney'] = 'firma, w której pracujesz, jest zbyt biedna, by wypłacić twoją pensję', - ['received_paycheck'] = 'otrzymano wypłate', + ['received_paycheck'] = 'otrzymana wypłata', ['bank'] = 'bank', ['account_bank'] = 'bank', - ['account_black_money'] = 'brudne pieniądze', - ['account_money'] = 'pieniądze', + ['account_black_money'] = 'dirty Money', + ['account_money'] = 'cash', + ['act_imp'] = 'działanie niemożliwe', ['in_vehicle'] = 'nie możesz przekazywać przedmiotów w pojeździe', -- Commands - ['command_car'] = 'przywołaj pojazd', - ['command_car_car'] = 'nazwa lub hash przywołanego pojazdu', - ['command_cardel'] = 'usuń pojazd w pobliżu', - ['command_cardel_radius'] = 'opcjonalnie usuń każdy pojazd w obszarze', - ['command_clear'] = 'wyczyść czat', - ['command_clearall'] = 'wyczyść czat dla wszystkich graczy', - ['command_clearinventory'] = 'wyczyść ekwipunek gracza', - ['command_clearloadout'] = 'wyczyść wyposarzenie gracza', - ['command_giveaccountmoney'] = 'daj pieniądze na podany typ konta', - ['command_giveaccountmoney_account'] = 'prawidłowy typ konta', - ['command_giveaccountmoney_amount'] = 'ilość do dodania', - ['command_giveaccountmoney_invalid'] = 'nieprawidłowy typ konta', - ['command_giveitem'] = 'daj przedmiot graczowi', - ['command_giveitem_item'] = 'nazwa przedmiotu', - ['command_giveitem_count'] = 'ilość przedimotu', - ['command_giveweapon'] = 'daj broń graczowi', - ['command_giveweapon_weapon'] = 'nazwa broni', - ['command_giveweapon_ammo'] = 'ilość amunicji', - ['command_giveweapon_hasalready'] = 'gracz już posiada tą broń', - ['command_giveweaponcomponent'] = 'daj komponent do broni graczowi', - ['command_giveweaponcomponent_component'] = 'nazwa komponentu', - ['command_giveweaponcomponent_invalid'] = 'nieprawidłowy komponent do broni', - ['command_giveweaponcomponent_hasalready'] = 'gracz już posiada ten komponent do tej broni', - ['command_giveweaponcomponent_missingweapon'] = 'gracz nie posiada tej broni', - ['command_save'] = 'zapisz gracza w bazie danych', - ['command_saveall'] = 'zapisz wszystkich graczy w bazie danych', - ['command_setaccountmoney'] = 'ustaw ilość pieniędzy danego konta dla gracza', - ['command_setaccountmoney_amount'] = 'ilość pieniędzy do ustawienia', - ['command_setcoords'] = 'teleportuj na koordynaty', + ['command_car'] = 'spawn an vehicle', + ['command_car_car'] = 'vehicle spawn name or hash', + ['command_cardel'] = 'delete vehicle in proximity', + ['command_cardel_radius'] = 'optional, delete every vehicle within the specified radius', + ['command_clear'] = 'clear chat', + ['command_clearall'] = 'clear chat for all players', + ['command_clearinventory'] = 'clear player inventory', + ['command_clearloadout'] = 'clear a player loadout', + ['command_giveaccountmoney'] = 'give account money', + ['command_giveaccountmoney_account'] = 'valid account name', + ['command_giveaccountmoney_amount'] = 'amount to add', + ['command_giveaccountmoney_invalid'] = 'invalid account name', + ['command_giveitem'] = 'give an item to a player', + ['command_giveitem_item'] = 'item name', + ['command_giveitem_count'] = 'item count', + ['command_giveweapon'] = 'give a weapon to a player', + ['command_giveweapon_weapon'] = 'weapon name', + ['command_giveweapon_ammo'] = 'ammo count', + ['command_giveweapon_hasalready'] = 'player already has that weapon', + ['command_giveweaponcomponent'] = 'give weapon component', + ['command_giveweaponcomponent_component'] = 'component name', + ['command_giveweaponcomponent_invalid'] = 'invalid weapon component', + ['command_giveweaponcomponent_hasalready'] = 'player already has that weapon component', + ['command_giveweaponcomponent_missingweapon'] = 'player does not have that weapon', + ['command_save'] = 'save a player to database', + ['command_saveall'] = 'save all players to database', + ['command_setaccountmoney'] = 'set account money for a player', + ['command_setaccountmoney_amount'] = 'amount of money to set', + ['command_setcoords'] = 'teleport to coordinates', ['command_setcoords_x'] = 'x axis', ['command_setcoords_y'] = 'y axis', ['command_setcoords_z'] = 'z axis', - ['command_setjob'] = 'ustaw prace dla gracza', - ['command_setjob_job'] = 'nazwa pracy', - ['command_setjob_grade'] = 'stanowisko w pracy', - ['command_setjob_invalid'] = 'praca, stanowisko lub obydwa są nieprawidłowe', - ['command_setgroup'] = 'ustaw grupe gracza', - ['command_setgroup_group'] = 'nazwa grupy', - ['commanderror_argumentmismatch'] = 'nieprawiłowa ilość argumentów (przeszło %s, wymagane %s)', - ['commanderror_argumentmismatch_number'] = 'nieprawidłowy typ argumentu #%s (przeszedł tekst, wymagany numer)', - ['commanderror_invaliditem'] = 'nieprawidłowa nazwa przedmiotu', - ['commanderror_invalidweapon'] = 'nieprawidłowa broń', - ['commanderror_console'] = 'podana komenda nie może zostać uruchomiona przez konsole', - ['commanderror_invalidcommand'] = '^3%s^0 nie jest poprawną komendą!', - ['commanderror_invalidplayerid'] = 'brak dostepnego gracza pasującego do podanego id serwerowego', - ['commandgeneric_playerid'] = 'id gracza', + ['command_setjob'] = 'set job for a player', + ['command_setjob_job'] = 'job name', + ['command_setjob_grade'] = 'job grade', + ['command_setjob_invalid'] = 'the job, grade or both are invalid', + ['command_setgroup'] = 'set player group', + ['command_setgroup_group'] = 'group name', + ['commanderror_argumentmismatch'] = 'argument count mismatch (passed %s, wanted %s)', + ['commanderror_argumentmismatch_number'] = 'argument #%s type mismatch (passed string, wanted number)', + ['commanderror_invaliditem'] = 'invalid item name', + ['commanderror_invalidweapon'] = 'invalid weapon', + ['commanderror_console'] = 'that command can not be run from console', + ['commanderror_invalidcommand'] = '^3%s^0 is not an valid command!', + ['commanderror_invalidplayerid'] = 'there is no player online matching that server id', + ['commandgeneric_playerid'] = 'player id', -- Locale settings - ['locale_digit_grouping_symbol'] = ',', + ['locale_digit_grouping_symbol'] = ' ', ['locale_currency'] = '$%s', -- Weapons @@ -183,42 +184,42 @@ Locales['pl'] = { -- Weapon Components ['component_clip_default'] = 'domyślny tłumik', ['component_clip_extended'] = 'rozszerzony tłumik', - ['component_clip_drum'] = 'magazynek bębnowy', - ['component_clip_box'] = 'magazynek', + ['component_clip_drum'] = 'drum Magazine', + ['component_clip_box'] = 'box Magazine', ['component_flashlight'] = 'latarka', ['component_scope'] = 'luneta', ['component_scope_advanced'] = 'zaawansowana luneta', ['component_suppressor'] = 'tłumik', ['component_grip'] = 'uchwyt', - ['component_luxary_finish'] = 'luksusowe wykończenie broni', + ['component_luxary_finish'] = 'luxary Weapon Finish', -- Weapon Ammo - ['ammo_rounds'] = 'nabój/oi', - ['ammo_shells'] = 'pocisk(ów)', - ['ammo_charge'] = 'naładowania', - ['ammo_petrol'] = 'galon(y) paliwa', - ['ammo_firework'] = 'fajerwerka/i', - ['ammo_rockets'] = 'rakieta/y', - ['ammo_grenadelauncher'] = 'granat(y)', - ['ammo_grenade'] = 'granat(y)', - ['ammo_stickybomb'] = 'bomba/y', - ['ammo_pipebomb'] = 'bomba/y', - ['ammo_smokebomb'] = 'bomba/y', - ['ammo_molotov'] = 'kontail(e)', - ['ammo_proxmine'] = 'mina/y', - ['ammo_bzgas'] = 'puszka/ek', - ['ammo_ball'] = 'kula/e', - ['ammo_snowball'] = 'snieżka/i', - ['ammo_flare'] = 'flara/y', - ['ammo_flaregun'] = 'flara/y', + ['ammo_rounds'] = 'round(s)', + ['ammo_shells'] = 'shell(s)', + ['ammo_charge'] = 'charge', + ['ammo_petrol'] = 'gallons of fuel', + ['ammo_firework'] = 'firework(s)', + ['ammo_rockets'] = 'rocket(s)', + ['ammo_grenadelauncher'] = 'grenade(s)', + ['ammo_grenade'] = 'grenade(s)', + ['ammo_stickybomb'] = 'bomb(s)', + ['ammo_pipebomb'] = 'bomb(s)', + ['ammo_smokebomb'] = 'bomb(s)', + ['ammo_molotov'] = 'cocktail(s)', + ['ammo_proxmine'] = 'mine(s)', + ['ammo_bzgas'] = 'can(s)', + ['ammo_ball'] = 'ball(s)', + ['ammo_snowball'] = 'snowball(s)', + ['ammo_flare'] = 'flare(s)', + ['ammo_flaregun'] = 'flare(s)', -- Weapon Tints - ['tint_default'] = 'domyślny skin', - ['tint_green'] = 'zielony skin', - ['tint_gold'] = 'złoty skin', - ['tint_pink'] = 'różowy skin', - ['tint_army'] = 'wojskowy skin', - ['tint_lspd'] = 'niebieski skin', - ['tint_orange'] = 'pomarańczowy skin', - ['tint_platinum'] = 'platynowy skin', + ['tint_default'] = 'default skin', + ['tint_green'] = 'green skin', + ['tint_gold'] = 'gold skin', + ['tint_pink'] = 'pink skin', + ['tint_army'] = 'army skin', + ['tint_lspd'] = 'blue skin', + ['tint_orange'] = 'orange skin', + ['tint_platinum'] = 'platinum skin', } diff --git a/locales/sc.lua b/locales/sc.lua index 229403de..cfe39ae2 100644 --- a/locales/sc.lua +++ b/locales/sc.lua @@ -42,7 +42,7 @@ Locales['sc'] = { -- Salary related ['received_salary'] = '你收到了你的工资: ~g~$%s~s~', - ['received_help'] = '你领取到了你的失业救济金: ~g~$%s~s~', + ['received_help'] = '鉴于你良好的表现,系统赠送给你一些奖励: ~g~$%s~s~', ['company_nomoney'] = '你受雇的公司太穷了,无法支付你的工资。', ['received_paycheck'] = '收到转账', ['bank'] = '花园银行', diff --git a/locales/tc.lua b/locales/tc.lua index 663259fb..9e31c8db 100644 --- a/locales/tc.lua +++ b/locales/tc.lua @@ -42,7 +42,7 @@ Locales['tc'] = { -- Salary related ['received_salary'] = '您收到您的薪水: ~g~$%s~s~', - ['received_help'] = '你領取到了你的失業救濟金: ~g~$%s~s~', + ['received_help'] = '由於您表現良好,系統給予您一些獎勵: ~g~$%s~s~', ['company_nomoney'] = '您的公司太窮了,無法給予您薪水。', ['received_paycheck'] = '收到轉帳', ['bank'] = '花園銀行', diff --git a/modules/hud/client/events.lua b/modules/hud/client/events.lua new file mode 100644 index 00000000..9c491962 --- /dev/null +++ b/modules/hud/client/events.lua @@ -0,0 +1,5 @@ +local self = ESX.Modules['hud'] + +AddEventHandler('esx:nui_ready', function() + ESX.CreateFrame('hud', 'nui://' .. GetCurrentResourceName() .. '/modules/hud/data/html/ui.html') +end) diff --git a/modules/hud/client/main.lua b/modules/hud/client/main.lua new file mode 100644 index 00000000..3f66e079 --- /dev/null +++ b/modules/hud/client/main.lua @@ -0,0 +1,4 @@ + +local self = ESX.Modules['hud'] + + diff --git a/modules/hud/client/module.lua b/modules/hud/client/module.lua new file mode 100644 index 00000000..8c81ec03 --- /dev/null +++ b/modules/hud/client/module.lua @@ -0,0 +1,5 @@ +ESX.Modules['hud'] = {}; +local self = ESX.Modules['hud'] + + + diff --git a/html/css/app.css b/modules/hud/data/html/css/app.css similarity index 98% rename from html/css/app.css rename to modules/hud/data/html/css/app.css index b487523f..b6f1147c 100644 --- a/html/css/app.css +++ b/modules/hud/data/html/css/app.css @@ -20,8 +20,8 @@ html { padding: 4px; text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; text-align: right; - top: 80; - right: 40; + top: 20; + right: 20; } #inventory_notifications { diff --git a/html/fonts/bankgothic.ttf b/modules/hud/data/html/fonts/bankgothic.ttf similarity index 100% rename from html/fonts/bankgothic.ttf rename to modules/hud/data/html/fonts/bankgothic.ttf diff --git a/html/fonts/pdown.ttf b/modules/hud/data/html/fonts/pdown.ttf similarity index 100% rename from html/fonts/pdown.ttf rename to modules/hud/data/html/fonts/pdown.ttf diff --git a/html/img/accounts/bank.png b/modules/hud/data/html/img/accounts/bank.png similarity index 100% rename from html/img/accounts/bank.png rename to modules/hud/data/html/img/accounts/bank.png diff --git a/html/img/accounts/black_money.png b/modules/hud/data/html/img/accounts/black_money.png similarity index 100% rename from html/img/accounts/black_money.png rename to modules/hud/data/html/img/accounts/black_money.png diff --git a/html/img/accounts/money.png b/modules/hud/data/html/img/accounts/money.png similarity index 100% rename from html/img/accounts/money.png rename to modules/hud/data/html/img/accounts/money.png diff --git a/html/js/app.js b/modules/hud/data/html/js/app.js similarity index 100% rename from html/js/app.js rename to modules/hud/data/html/js/app.js diff --git a/html/js/mustache.min.js b/modules/hud/data/html/js/mustache.min.js similarity index 100% rename from html/js/mustache.min.js rename to modules/hud/data/html/js/mustache.min.js diff --git a/html/js/wrapper.js b/modules/hud/data/html/js/wrapper.js similarity index 88% rename from html/js/wrapper.js rename to modules/hud/data/html/js/wrapper.js index 0d208709..d85201b1 100644 --- a/html/js/wrapper.js +++ b/modules/hud/data/html/js/wrapper.js @@ -33,7 +33,7 @@ if (i == str.length - 1) data.end = true; - $.post('http://' + namespace + '/__chunk', JSON.stringify(data)); + $.post('http://' + GetCurrentResourceName() + '/__chunk', JSON.stringify(data)); } diff --git a/html/ui.html b/modules/hud/data/html/ui.html similarity index 100% rename from html/ui.html rename to modules/hud/data/html/ui.html diff --git a/modules/hud/server/events.lua b/modules/hud/server/events.lua new file mode 100644 index 00000000..d0124661 --- /dev/null +++ b/modules/hud/server/events.lua @@ -0,0 +1,2 @@ +local self = ESX.Modules['hud'] + diff --git a/modules/hud/server/main.lua b/modules/hud/server/main.lua new file mode 100644 index 00000000..52b7e9d2 --- /dev/null +++ b/modules/hud/server/main.lua @@ -0,0 +1,3 @@ + +local self = ESX.Modules['hud'] + diff --git a/modules/hud/server/module.lua b/modules/hud/server/module.lua new file mode 100644 index 00000000..e1db6d5c --- /dev/null +++ b/modules/hud/server/module.lua @@ -0,0 +1,3 @@ +ESX.Modules['hud'] = {}; +local self = ESX.Modules['hud'] + diff --git a/modules/input/client/events.lua b/modules/input/client/events.lua new file mode 100644 index 00000000..6a248bdc --- /dev/null +++ b/modules/input/client/events.lua @@ -0,0 +1 @@ +local self = ESX.Modules['input'] diff --git a/modules/input/client/main.lua b/modules/input/client/main.lua new file mode 100644 index 00000000..12f29bb1 --- /dev/null +++ b/modules/input/client/main.lua @@ -0,0 +1,67 @@ +local self = ESX.Modules['input'] + +Citizen.CreateThread(function() + while true do + + local events = { + pressed = {}, + released = {}, + dpressed = {}, + dreleased = {}, + } + + for group, ids in pairs(self.RegisteredControls) do + + for i=1, #ids, 1 do + + local id = ids[i] + + if self.IsControlEnabled(group, id) then + + if IsControlJustPressed(group, id) then + events.pressed[#events.pressed + 1] = {group, id, self.LastPressed[group][id]} + end + + if IsControlJustReleased(group, id) then + events.released[#events.released + 1] = {group, id, self.LastReleased[group][id]} + end + + else + + DisableControlAction(group, id, true); + + if IsDisabledControlJustPressed(group, id) then + events.dpressed[#events.dpressed + 1] = {group, id, self.LastDisabledPressed[group][id]} + self.LastDisabledPressed[group][id] = GetGameTimer() + end + + if IsDisabledControlJustReleased(group, id) then + events.dreleased[#events.dreleased + 1] = {group, id, self.LastDisabledReleased[group][id]} + self.LastDisabledReleased[group][id] = GetGameTimer() + end + + end + + end + end + + for i=1, #events.pressed, 1 do + TriggerEvent('esx:input:pressed:' .. events.pressed[i][1] .. ':' .. events.pressed[i][2], events.pressed[i][3]) + end + + for i=1, #events.released, 1 do + TriggerEvent('esx:input:released:' .. events.released[i][1] .. ':' .. events.released[i][2], events.released[i][3]) + end + + for i=1, #events.dpressed, 1 do + TriggerEvent('esx:input:disabled:pressed:' .. events.dpressed[i][1] .. ':' .. events.dpressed[i][2], events.dpressed[i][3]) + end + + for i=1, #events.dreleased, 1 do + TriggerEvent('esx:input:disabled:released:' .. events.dreleased[i][1] .. ':' .. events.dreleased[i][2], events.dreleased[i][3]) + end + + Citizen.Wait(0) + + end +end) diff --git a/modules/input/client/module.lua b/modules/input/client/module.lua new file mode 100644 index 00000000..7d8c5ea1 --- /dev/null +++ b/modules/input/client/module.lua @@ -0,0 +1,466 @@ +ESX.Modules['input'] = {} +local self = ESX.Modules['input'] +self.RegisteredControls = {} +self.EnabledControls = {} +self.LastPressed = {} +self.LastDisabledPressed = {} +self.LastReleased = {} +self.LastDisabledReleased = {} + +self.Groups = { + MOVE = 0, + LOOK = 1, + WHEEL = 2, + CELLPHONE_NAVIGATE = 3, + CELLPHONE_NAVIGATE_UD = 4, + CELLPHONE_NAVIGATE_LR = 5, + FRONTEND_DPAD_ALL = 6, + FRONTEND_DPAD_UD = 7, + FRONTEND_DPAD_LR = 8, + FRONTEND_LSTICK_ALL = 9, + FRONTEND_RSTICK_ALL = 10, + FRONTEND_GENERIC_UD = 11, + FRONTEND_GENERIC_LR = 12, + FRONTEND_GENERIC_ALL = 13, + FRONTEND_BUMPERS = 14, + FRONTEND_TRIGGERS = 15, + FRONTEND_STICKS = 16, + SCRIPT_DPAD_ALL = 17, + SCRIPT_DPAD_UD = 18, + SCRIPT_DPAD_LR = 19, + SCRIPT_LSTICK_ALL = 20, + SCRIPT_RSTICK_ALL = 21, + SCRIPT_BUMPERS = 22, + SCRIPT_TRIGGERS = 23, + WEAPON_WHEEL_CYCLE = 24, + FLY = 25, + SUB = 26, + VEH_MOVE_ALL = 27, + CURSOR = 28, + CURSOR_SCROLL = 29, + SNIPER_ZOOM_SECONDARY = 30, + VEH_HYDRAULICS_CONTROL = 31, +} + +self.Controls = { + NEXT_CAMERA = 0, + LOOK_LR = 1, + LOOK_UD = 2, + LOOK_UP_ONLY = 3, + LOOK_DOWN_ONLY = 4, + LOOK_LEFT_ONLY = 5, + LOOK_RIGHT_ONLY = 6, + CINEMATIC_SLOWMO = 7, + SCRIPTED_FLY_UD = 8, + SCRIPTED_FLY_LR = 9, + SCRIPTED_FLY_ZUP = 10, + SCRIPTED_FLY_ZDOWN = 11, + WEAPON_WHEEL_UD = 12, + WEAPON_WHEEL_LR = 13, + WEAPON_WHEEL_NEXT = 14, + WEAPON_WHEEL_PREV = 15, + SELECT_NEXT_WEAPON = 16, + SELECT_PREV_WEAPON = 17, + SKIP_CUTSCENE = 18, + CHARACTER_WHEEL = 19, + MULTIPLAYER_INFO = 20, + SPRINT = 21, + JUMP = 22, + ENTER = 23, + ATTACK = 24, + AIM = 25, + LOOK_BEHIND = 26, + PHONE = 27, + SPECIAL_ABILITY = 28, + SPECIAL_ABILITY_SECONDARY = 29, + MOVE_LR = 30, + MOVE_UD = 31, + MOVE_UP_ONLY = 32, + MOVE_DOWN_ONLY = 33, + MOVE_LEFT_ONLY = 34, + MOVE_RIGHT_ONLY = 35, + DUCK = 36, + SELECT_WEAPON = 37, + PICKUP = 38, + SNIPER_ZOOM = 39, + SNIPER_ZOOM_IN_ONLY = 40, + SNIPER_ZOOM_OUT_ONLY = 41, + SNIPER_ZOOM_IN_SECONDARY = 42, + SNIPER_ZOOM_OUT_SECONDARY = 43, + COVER = 44, + RELOAD = 45, + TALK = 46, + DETONATE = 47, + HUD_SPECIAL = 48, + ARREST = 49, + ACCURATE_AIM = 50, + CONTEXT = 51, + CONTEXT_SECONDARY = 52, + WEAPON_SPECIAL = 53, + WEAPON_SPECIAL_TWO = 54, + DIVE = 55, + DROP_WEAPON = 56, + DROP_AMMO = 57, + THROW_GRENADE = 58, + VEH_MOVE_LR = 59, + VEH_MOVE_UD = 60, + VEH_MOVE_UP_ONLY = 61, + VEH_MOVE_DOWN_ONLY = 62, + VEH_MOVE_LEFT_ONLY = 63, + VEH_MOVE_RIGHT_ONLY = 64, + VEH_SPECIAL = 65, + VEH_GUN_LR = 66, + VEH_GUN_UD = 67, + VEH_AIM = 68, + VEH_ATTACK = 69, + VEH_ATTACK2 = 70, + VEH_ACCELERATE = 71, + VEH_BRAKE = 72, + VEH_DUCK = 73, + VEH_HEADLIGHT = 74, + VEH_EXIT = 75, + VEH_HANDBRAKE = 76, + VEH_HOTWIRE_LEFT = 77, + VEH_HOTWIRE_RIGHT = 78, + VEH_LOOK_BEHIND = 79, + VEH_CIN_CAM = 80, + VEH_NEXT_RADIO = 81, + VEH_PREV_RADIO = 82, + VEH_NEXT_RADIO_TRACK = 83, + VEH_PREV_RADIO_TRACK = 84, + VEH_RADIO_WHEEL = 85, + VEH_HORN = 86, + VEH_FLY_THROTTLE_UP = 87, + VEH_FLY_THROTTLE_DOWN = 88, + VEH_FLY_YAW_LEFT = 89, + VEH_FLY_YAW_RIGHT = 90, + VEH_PASSENGER_AIM = 91, + VEH_PASSENGER_ATTACK = 92, + VEH_SPECIAL_ABILITY_FRANKLIN = 93, + VEH_STUNT_UD = 94, + VEH_CINEMATIC_UD = 95, + VEH_CINEMATIC_UP_ONLY = 96, + VEH_CINEMATIC_DOWN_ONLY = 97, + VEH_CINEMATIC_LR = 98, + VEH_SELECT_NEXT_WEAPON = 99, + VEH_SELECT_PREV_WEAPON = 100, + VEH_ROOF = 101, + VEH_JUMP = 102, + VEH_GRAPPLING_HOOK = 103, + VEH_SHUFFLE = 104, + VEH_DROP_PROJECTILE = 105, + VEH_MOUSE_CONTROL_OVERRIDE = 106, + VEH_FLY_ROLL_LR = 107, + VEH_FLY_ROLL_LEFT_ONLY = 108, + VEH_FLY_ROLL_RIGHT_ONLY = 109, + VEH_FLY_PITCH_UD = 110, + VEH_FLY_PITCH_UP_ONLY = 111, + VEH_FLY_PITCH_DOWN_ONLY = 112, + VEH_FLY_UNDERCARRIAGE = 113, + VEH_FLY_ATTACK = 114, + VEH_FLY_SELECT_NEXT_WEAPON = 115, + VEH_FLY_SELECT_PREV_WEAPON = 116, + VEH_FLY_SELECT_TARGET_LEFT = 117, + VEH_FLY_SELECT_TARGET_RIGHT = 118, + VEH_FLY_VERTICAL_FLIGHT_MODE = 119, + VEH_FLY_DUCK = 120, + VEH_FLY_ATTACK_CAMERA = 121, + VEH_FLY_MOUSE_CONTROL_OVERRIDE = 122, + VEH_SUB_TURN_LR = 123, + VEH_SUB_TURN_LEFT_ONLY = 124, + VEH_SUB_TURN_RIGHT_ONLY = 125, + VEH_SUB_PITCH_UD = 126, + VEH_SUB_PITCH_UP_ONLY = 127, + VEH_SUB_PITCH_DOWN_ONLY = 128, + VEH_SUB_THROTTLE_UP = 129, + VEH_SUB_THROTTLE_DOWN = 130, + VEH_SUB_ASCEND = 131, + VEH_SUB_DESCEND = 132, + VEH_SUB_TURN_HARD_LEFT = 133, + VEH_SUB_TURN_HARD_RIGHT = 134, + VEH_SUB_MOUSE_CONTROL_OVERRIDE = 135, + VEH_PUSHBIKE_PEDAL = 136, + VEH_PUSHBIKE_SPRINT = 137, + VEH_PUSHBIKE_FRONT_BRAKE = 138, + VEH_PUSHBIKE_REAR_BRAKE = 139, + MELEE_ATTACK_LIGHT = 140, + MELEE_ATTACK_HEAVY = 141, + MELEE_ATTACK_ALTERNATE = 142, + MELEE_BLOCK = 143, + PARACHUTE_DEPLOY = 144, + PARACHUTE_DETACH = 145, + PARACHUTE_TURN_LR = 146, + PARACHUTE_TURN_LEFT_ONLY = 147, + PARACHUTE_TURN_RIGHT_ONLY = 148, + PARACHUTE_PITCH_UD = 149, + PARACHUTE_PITCH_UP_ONLY = 150, + PARACHUTE_PITCH_DOWN_ONLY = 151, + PARACHUTE_BRAKE_LEFT = 152, + PARACHUTE_BRAKE_RIGHT = 153, + PARACHUTE_SMOKE = 154, + PARACHUTE_PRECISION_LANDING = 155, + MAP = 156, + SELECT_WEAPON_UNARMED = 157, + SELECT_WEAPON_MELEE = 158, + SELECT_WEAPON_HANDGUN = 159, + SELECT_WEAPON_SHOTGUN = 160, + SELECT_WEAPON_SMG = 161, + SELECT_WEAPON_AUTO_RIFLE = 162, + SELECT_WEAPON_SNIPER = 163, + SELECT_WEAPON_HEAVY = 164, + SELECT_WEAPON_SPECIAL = 165, + SELECT_CHARACTER_MICHAEL = 166, + SELECT_CHARACTER_FRANKLIN = 167, + SELECT_CHARACTER_TREVOR = 168, + SELECT_CHARACTER_MULTIPLAYER = 169, + SAVE_REPLAY_CLIP = 170, + SPECIAL_ABILITY_PC = 171, + CELLPHONE_UP = 172, + CELLPHONE_DOWN = 173, + CELLPHONE_LEFT = 174, + CELLPHONE_RIGHT = 175, + CELLPHONE_SELECT = 176, + CELLPHONE_CANCEL = 177, + CELLPHONE_OPTION = 178, + CELLPHONE_EXTRA_OPTION = 179, + CELLPHONE_SCROLL_FORWARD = 180, + CELLPHONE_SCROLL_BACKWARD = 181, + CELLPHONE_CAMERA_FOCUS_LOCK = 182, + CELLPHONE_CAMERA_GRID = 183, + CELLPHONE_CAMERA_SELFIE = 184, + CELLPHONE_CAMERA_DOF = 185, + CELLPHONE_CAMERA_EXPRESSION = 186, + FRONTEND_DOWN = 187, + FRONTEND_UP = 188, + FRONTEND_LEFT = 189, + FRONTEND_RIGHT = 190, + FRONTEND_RDOWN = 191, + FRONTEND_RUP = 192, + FRONTEND_RLEFT = 193, + FRONTEND_RRIGHT = 194, + FRONTEND_AXIS_X = 195, + FRONTEND_AXIS_Y = 196, + FRONTEND_RIGHT_AXIS_X = 197, + FRONTEND_RIGHT_AXIS_Y = 198, + FRONTEND_PAUSE = 199, + FRONTEND_PAUSE_ALTERNATE = 200, + FRONTEND_ACCEPT = 201, + FRONTEND_CANCEL = 202, + FRONTEND_X = 203, + FRONTEND_Y = 204, + FRONTEND_LB = 205, + FRONTEND_RB = 206, + FRONTEND_LT = 207, + FRONTEND_RT = 208, + FRONTEND_LS = 209, + FRONTEND_RS = 210, + FRONTEND_LEADERBOARD = 211, + FRONTEND_SOCIAL_CLUB = 212, + FRONTEND_SOCIAL_CLUB_SECONDARY = 213, + FRONTEND_DELETE = 214, + FRONTEND_ENDSCREEN_ACCEPT = 215, + FRONTEND_ENDSCREEN_EXPAND = 216, + FRONTEND_SELECT = 217, + SCRIPT_LEFT_AXIS_X = 218, + SCRIPT_LEFT_AXIS_Y = 219, + SCRIPT_RIGHT_AXIS_X = 220, + SCRIPT_RIGHT_AXIS_Y = 221, + SCRIPT_RUP = 222, + SCRIPT_RDOWN = 223, + SCRIPT_RLEFT = 224, + SCRIPT_RRIGHT = 225, + SCRIPT_LB = 226, + SCRIPT_RB = 227, + SCRIPT_LT = 228, + SCRIPT_RT = 229, + SCRIPT_LS = 230, + SCRIPT_RS = 231, + SCRIPT_PAD_UP = 232, + SCRIPT_PAD_DOWN = 233, + SCRIPT_PAD_LEFT = 234, + SCRIPT_PAD_RIGHT = 235, + SCRIPT_SELECT = 236, + CURSOR_ACCEPT = 237, + CURSOR_CANCEL = 238, + CURSOR_X = 239, + CURSOR_Y = 240, + CURSOR_SCROLL_UP = 241, + CURSOR_SCROLL_DOWN = 242, + ENTER_CHEAT_CODE = 243, + INTERACTION_MENU = 244, + MP_TEXT_CHAT_ALL = 245, + MP_TEXT_CHAT_TEAM = 246, + MP_TEXT_CHAT_FRIENDS = 247, + MP_TEXT_CHAT_CREW = 248, + PUSH_TO_TALK = 249, + CREATOR_LS = 250, + CREATOR_RS = 251, + CREATOR_LT = 252, + CREATOR_RT = 253, + CREATOR_MENU_TOGGLE = 254, + CREATOR_ACCEPT = 255, + CREATOR_DELETE = 256, + ATTACK2 = 257, + RAPPEL_JUMP = 258, + RAPPEL_LONG_JUMP = 259, + RAPPEL_SMASH_WINDOW = 260, + PREV_WEAPON = 261, + NEXT_WEAPON = 262, + MELEE_ATTACK1 = 263, + MELEE_ATTACK2 = 264, + WHISTLE = 265, + MOVE_LEFT = 266, + MOVE_RIGHT = 267, + MOVE_UP = 268, + MOVE_DOWN = 269, + LOOK_LEFT = 270, + LOOK_RIGHT = 271, + LOOK_UP = 272, + LOOK_DOWN = 273, + SNIPER_ZOOM_IN = 274, + SNIPER_ZOOM_OUT = 275, + SNIPER_ZOOM_IN_ALTERNATE = 276, + SNIPER_ZOOM_OUT_ALTERNATE = 277, + VEH_MOVE_LEFT = 278, + VEH_MOVE_RIGHT = 279, + VEH_MOVE_UP = 280, + VEH_MOVE_DOWN = 281, + VEH_GUN_LEFT = 282, + VEH_GUN_RIGHT = 283, + VEH_GUN_UP = 284, + VEH_GUN_DOWN = 285, + VEH_LOOK_LEFT = 286, + VEH_LOOK_RIGHT = 287, + REPLAY_START_STOP_RECORDING = 288, + REPLAY_START_STOP_RECORDING_SECONDARY = 289, + SCALED_LOOK_LR = 290, + SCALED_LOOK_UD = 291, + SCALED_LOOK_UP_ONLY = 292, + SCALED_LOOK_DOWN_ONLY = 293, + SCALED_LOOK_LEFT_ONLY = 294, + SCALED_LOOK_RIGHT_ONLY = 295, + REPLAY_MARKER_DELETE = 296, + REPLAY_CLIP_DELETE = 297, + REPLAY_PAUSE = 298, + REPLAY_REWIND = 299, + REPLAY_FFWD = 300, + REPLAY_NEWMARKER = 301, + REPLAY_RECORD = 302, + REPLAY_SCREENSHOT = 303, + REPLAY_HIDEHUD = 304, + REPLAY_STARTPOINT = 305, + REPLAY_ENDPOINT = 306, + REPLAY_ADVANCE = 307, + REPLAY_BACK = 308, + REPLAY_TOOLS = 309, + REPLAY_RESTART = 310, + REPLAY_SHOWHOTKEY = 311, + REPLAY_CYCLEMARKERLEFT = 312, + REPLAY_CYCLEMARKERRIGHT = 313, + REPLAY_FOVINCREASE = 314, + REPLAY_FOVDECREASE = 315, + REPLAY_CAMERAUP = 316, + REPLAY_CAMERADOWN = 317, + REPLAY_SAVE = 318, + REPLAY_TOGGLETIME = 319, + REPLAY_TOGGLETIPS = 320, + REPLAY_PREVIEW = 321, + REPLAY_TOGGLE_TIMELINE = 322, + REPLAY_TIMELINE_PICKUP_CLIP = 323, + REPLAY_TIMELINE_DUPLICATE_CLIP = 324, + REPLAY_TIMELINE_PLACE_CLIP = 325, + REPLAY_CTRL = 326, + REPLAY_TIMELINE_SAVE = 327, + REPLAY_PREVIEW_AUDIO = 328, + VEH_DRIVE_LOOK = 329, + VEH_DRIVE_LOOK2 = 330, + VEH_FLY_ATTACK2 = 331, + RADIO_WHEEL_UD = 332, + RADIO_WHEEL_LR = 333, + VEH_SLOWMO_UD = 334, + VEH_SLOWMO_UP_ONLY = 335, + VEH_SLOWMO_DOWN_ONLY = 336, + VEH_HYDRAULICS_CONTROL_TOGGLE = 337, + VEH_HYDRAULICS_CONTROL_LEFT = 338, + VEH_HYDRAULICS_CONTROL_RIGHT = 339, + VEH_HYDRAULICS_CONTROL_UP = 340, + VEH_HYDRAULICS_CONTROL_DOWN = 341, + VEH_HYDRAULICS_CONTROL_UD = 342, + VEH_HYDRAULICS_CONTROL_LR = 343, + MAP_POI = 344, + INPUT_REPLAY_SNAPMATIC_PHOTO = 345, +} + +self.RegisterControl = function(group, id) + if ESX.Table.IndexOf(self.RegisteredControls[group], id) == -1 then + self.RegisteredControls[group][#self.RegisteredControls[group] + 1] = id + end +end + +self.UnregisterControl = function(group, id) + if ESX.Table.IndexOf(self.RegisteredControls[group], id) ~= -1 then + table.remove(self.RegisteredControls[group], ESX.Table.IndexOf(self.RegisteredControls[group], id)) + end +end + +self.EnableControl = function(group, id) + self.EnabledControls[group][id] = self.EnabledControls[group][id] + 1 +end + +self.DisableControl = function(group, id) + self.EnabledControls[group][id] = self.EnabledControls[group][id] - 1 +end + +self.IsControlRegistered = function(group, id) + return ESX.Table.IndexOf(self.RegisteredControls[group], id) ~= -1 +end + +self.IsControlPressed = function(group, id) + return self.IsControlEnabled(group, id) and (IsControlPressed(group, id)) +end + +self.IsDisabledControlPressed = function(group, id) + return (not self.IsControlEnabled(group, id)) and (IsDisabledControlPressed(group, id)) +end + +self.IsControlEnabled = function(group, id) + return self.EnabledControls[group][id] >= 0 +end + +for k1, group in pairs(self.Groups) do + + self.RegisteredControls[group] = {} + self.EnabledControls[group] = {} + self.LastPressed[group] = {} + self.LastDisabledPressed[group] = {} + self.LastReleased[group] = {} + self.LastDisabledReleased[group] = {} + + for k2, id in pairs(self.Controls) do + self.EnabledControls[group][id] = 0 + self.LastPressed[group][id] = -1 + self.LastDisabledPressed[group][id] = -1 + self.LastReleased[group][id] = -1 + self.LastDisabledReleased[group][id] = -1 + end + +end + +self.On = function(event, group, id, cb) + + return AddEventHandler('esx:input:' .. event .. ':' .. group .. ':' .. id, cb) + +end + +self.InitESX = function() + + self.RegisterControl(Input.Groups.MOVE, Input.Controls[Config.InventoryKey]) + self.On('released', Input.Groups.MOVE, Input.Controls[Config.InventoryKey], function(lastPressed) + + if (not ESX.IsDead) and (not ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory')) then + ESX.ShowInventory() + end + + end) + +end diff --git a/modules/input/server/events.lua b/modules/input/server/events.lua new file mode 100644 index 00000000..6a248bdc --- /dev/null +++ b/modules/input/server/events.lua @@ -0,0 +1 @@ +local self = ESX.Modules['input'] diff --git a/modules/input/server/main.lua b/modules/input/server/main.lua new file mode 100644 index 00000000..6a248bdc --- /dev/null +++ b/modules/input/server/main.lua @@ -0,0 +1 @@ +local self = ESX.Modules['input'] diff --git a/modules/input/server/module.lua b/modules/input/server/module.lua new file mode 100644 index 00000000..1d041737 --- /dev/null +++ b/modules/input/server/module.lua @@ -0,0 +1,2 @@ +ESX.Modules['input'] = {} +local self = ESX.Modules['input'] diff --git a/modules/interact/client/events.lua b/modules/interact/client/events.lua new file mode 100644 index 00000000..caf76c7a --- /dev/null +++ b/modules/interact/client/events.lua @@ -0,0 +1,12 @@ +local self = ESX.Modules['interact'] + +AddEventHandler('esx:interact:register', self.Register) + +-- Do not use this in prod ! internal event only +AddEventHandler('esx:interact:enter', function(name, data) + TriggerEvent('esx:interact:enter:' .. name, data) +end) + +AddEventHandler('esx:interact:exit', function(name, data) + TriggerEvent('esx:interact:exit:' .. name, data) +end) diff --git a/modules/interact/client/main.lua b/modules/interact/client/main.lua new file mode 100644 index 00000000..78a956a9 --- /dev/null +++ b/modules/interact/client/main.lua @@ -0,0 +1,194 @@ +local self = ESX.Modules['interact'] + +self.LOVE_PLAYER_GROUP = AddRelationshipGroup('LOVE_PLAYER') + +SetRelationshipBetweenGroups(0, self.LOVE_PLAYER_GROUP, 'PLAYER') + +Citizen.CreateThread(function() + + while true do + + Citizen.Wait(100) + + local ped = PlayerPedId() + local coords = GetOffsetFromEntityInWorldCoords(ped, 0.0, 0.0, -1.0) + + self.Cache.player.ped = ped + self.Cache.player.coords = vector3(table.unpack(coords)) + + local toRemove = {} + + for i=1, #self.Data, 1 do + + local data = self.Data[i] + + if data.pos == nil then + + print('[esx_interact] data.pos is nil => ' .. json.encode(data)) + + else + + local distance = #(data.pos - self.Cache.player.coords); + if + (distance <= data.distance) and + (ESX.Table.FindIndex(self.Cache.current, function(e) return e.__id == data.__id end) == -1) + then + + if (data.check == nil) or data.check(self.Cache.player.ped, self.Cache.player.coords) then + data.playing = false + self.Cache.current[#self.Cache.current + 1] = data + end + + elseif (distance > data.distance) then + + local idx = ESX.Table.FindIndex(self.Cache.current, function(e) return e.__id == data.__id end) + + if idx ~= -1 then + toRemove[#toRemove + 1] = idx + end + + end + + end + + end + + if #toRemove > 0 then + self.Cache.current = ESX.Table.Filter(self.Cache.current, function(e) return ESX.Table.IndexOf(toRemove, e.__id) ~= -1 end) + end + + end + +end) + +-- Markers +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + for i=1, #self.Cache.current, 1 do + + local curr = self.Cache.current[i] + + if curr.type == 'marker' then + + DrawMarker( + curr.mtype, + curr.pos.x + 0.0, curr.pos.y + 0.0, curr.pos.z + 0.0, + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + curr.size.x + 0.0, curr.size.y + 0.0, curr.size.z + 0.0, + curr.color.r, curr.color.g, curr.color.b, curr.color.a, + curr.bobUpAndDown, curr.faceCamera, 2, curr.rotate, nil, nil, false + ) + + end + + end + + end +end) + +-- NPCs +Citizen.CreateThread(function() + while true do + + Citizen.Wait(1000) + + for i=1, #self.Cache.current, 1 do + + local curr = self.Cache.current[i] + + if curr.type == 'npc' then + + if IsModelValid(curr.model) and IsModelInCdimage(curr.model) then + + local found = false + + local closestPed, closestDistance = ESX.Game.GetClosestPed({ + x = curr.pos.x + 0.0, + y = curr.pos.y + 0.0, + z = curr.pos.z + 0.0 + }, {Cache.player.ped}) + + if closestPed ~= -1 then + + local model = GetEntityModel(closestPed) + + if (model == curr.model) and (closestDistance <= 10.0) then + + found = true + + if (curr.lib ~= nil) and (curr.anim ~= nil) then + + if not HasAnimDictLoaded(curr.lib) then + RequestAnimDict(curr.lib) + end + + if HasAnimDictLoaded(curr.lib) and (not curr.playing) then + curr.playing = true + TaskPlayAnim(closestPed, curr.lib, curr.anim, 8.0, -8.0, -1, 1, 1.0, false, false, false) + end + + end + + end + + end + + if not found then + + print('Create ped : ' .. curr.model .. ' @ ' .. curr.pos.x .. ' ' .. curr.pos.y .. ' ' .. curr.pos.z) + + RequestModel(curr.model) + + while not HasModelLoaded(curr.model) do + Citizen.Wait(0) + end + + curr.__ped = CreatePed(26, curr.model, curr.pos.x + 0.0, curr.pos.y + 0.0, curr.pos.z + 0.0, curr.heading + 0.0, true, false) + + SetModelAsNoLongerNeeded(curr.model) + + SetPedRelationshipGroupHash(curr.__ped, self.LOVE_PLAYER_GROUP) + SetBlockingOfNonTemporaryEvents(curr.__ped, true) + TaskStandStill(curr.__ped, -1) + SetEntityInvincible(curr.__ped, true) + FreezeEntityPosition(curr.__ped, true) + + end + + else + print('Invalid/inexistent model => ' .. curr.model) + end + + end + + end + + end +end) + +Citizen.CreateThread(function() + while true do + + Citizen.Wait(100) + + for i=1, #self.Cache.current, 1 do + + local data = self.Cache.current[i] + local distance = #(data.pos - self.Cache.player.coords); + + if (distance <= data.radius) and (not self.Cache.using[data.__id]) then + self.Cache.using[data.__id] = true + TriggerEvent('esx:interact:enter', data.name, data) + elseif (distance > data.radius) and self.Cache.using[data.__id] then + self.Cache.using[data.__id] = nil + TriggerEvent('esx:interact:exit', data.name, data) + end + + end + + end +end) diff --git a/modules/interact/client/module.lua b/modules/interact/client/module.lua new file mode 100644 index 00000000..7fab0039 --- /dev/null +++ b/modules/interact/client/module.lua @@ -0,0 +1,47 @@ +ESX.Modules['interact'] = {}; +local self = ESX.Modules['interact'] + +self.Id = 0 +self.Data = {} + +self.Cache = { + player = { + ped = 0, + coords = vector3(0.0, 0.0, 0.0) + }, + current = {}, + using = {}, +} + +self.Register = function(data) + + local idx = -1 + + for i=1, #self.Data, 1 do + if self.Data[i].name == data.name then + idx = i + break + end + end + + if self.Id >= 65535 then + data.__id = 1 + else + data.__id = self.Id + 1 + end + + data.size = (type(data.size) == 'number') and {x = data.size, y = data.size, z = data.size} or data.size + + if data.faceCamera == nil then data.faceCamera = false end + if data.bobUpAndDown == nil then data.bobUpAndDown = false end + if data.rotate == nil then data.rotate = false end + + self.Id = data.__id + + if idx == -1 then + self.Data[#self.Data + 1] = data + else + self.Data[idx] = data + end + +end diff --git a/modules/interact/server/events.lua b/modules/interact/server/events.lua new file mode 100644 index 00000000..841e735c --- /dev/null +++ b/modules/interact/server/events.lua @@ -0,0 +1,2 @@ +local self = ESX.Modules['interact'] + diff --git a/modules/interact/server/main.lua b/modules/interact/server/main.lua new file mode 100644 index 00000000..d1ba7452 --- /dev/null +++ b/modules/interact/server/main.lua @@ -0,0 +1,3 @@ + +local self = ESX.Modules['interact'] + diff --git a/modules/interact/server/module.lua b/modules/interact/server/module.lua new file mode 100644 index 00000000..fdccf53a --- /dev/null +++ b/modules/interact/server/module.lua @@ -0,0 +1,3 @@ +ESX.Modules['interact'] = {}; +local self = ESX.Modules['interact'] + diff --git a/modules/job_police/client/events.lua b/modules/job_police/client/events.lua new file mode 100644 index 00000000..961c7597 --- /dev/null +++ b/modules/job_police/client/events.lua @@ -0,0 +1,311 @@ +local self = ESX.Modules['job_police'] + +-- Locals +local Input = ESX.Modules['input'] + +RegisterNetEvent('esx:setJob') +AddEventHandler('esx:setJob', function(job) + Citizen.Wait(5000) + TriggerServerEvent('esx_policejob:forceBlip') +end) + +RegisterNetEvent('esx_phone:loaded') +AddEventHandler('esx_phone:loaded', function(phoneNumber, contacts) + + local specialContact = { + name = _U('job_police:phone_police'), + number = 'police', + base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDFGQTJDRkI0QUJCMTFFN0JBNkQ5OENBMUI4QUEzM0YiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDFGQTJDRkM0QUJCMTFFN0JBNkQ5OENBMUI4QUEzM0YiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MUZBMkNGOTRBQkIxMUU3QkE2RDk4Q0ExQjhBQTMzRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MUZBMkNGQTRBQkIxMUU3QkE2RDk4Q0ExQjhBQTMzRiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoW66EYAAAjGSURBVHjapJcLcFTV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' + } + + TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon) + +end) + +-- don't show dispatches if the player isn't in service +AddEventHandler('esx_phone:cancelMessage', function(dispatchNumber) + + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'police' and ESX.PlayerData.job.name == dispatchNumber then + -- if esx_service is enabled + if self.Config.EnableESXService and not playerInService then + CancelEvent() + end + end + +end) + +AddEventHandler('esx_policejob:hasEnteredMarker', function(station, part, partNum) + if part == 'Cloakroom' then + self.CurrentAction = 'menu_cloakroom' + self.CurrentActionMsg = _U('job_police:open_cloackroom') + self.CurrentActionData = {} + elseif part == 'Armory' then + self.CurrentAction = 'menu_armory' + self.CurrentActionMsg = _U('job_police:open_armory') + self.CurrentActionData = {station = station} + elseif part == 'Vehicles' then + self.CurrentAction = 'menu_vehicle_spawner' + self.CurrentActionMsg = _U('job_police:garage_prompt') + self.CurrentActionData = {station = station, part = part, partNum = partNum} + elseif part == 'Helicopters' then + self.CurrentAction = 'Helicopters' + self.CurrentActionMsg = _U('job_police:helicopter_prompt') + self.CurrentActionData = {station = station, part = part, partNum = partNum} + elseif part == 'BossActions' then + self.CurrentAction = 'menu_boss_actions' + self.CurrentActionMsg = _U('job_police:open_bossmenu') + self.CurrentActionData = {} + end +end) + +AddEventHandler('esx_policejob:hasExitedMarker', function(station, part, partNum) + if not isInShopMenu then + ESX.UI.Menu.CloseAll() + end + + self.CurrentAction = nil +end) + +AddEventHandler('esx_policejob:hasEnteredEntityZone', function(entity) + local playerPed = PlayerPedId() + + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'police' and IsPedOnFoot(playerPed) then + self.CurrentAction = 'remove_entity' + self.CurrentActionMsg = _U('job_police:remove_prop') + self.CurrentActionData = {entity = entity} + end + + if GetEntityModel(entity) == GetHashKey('p_ld_stinger_s') then + local playerPed = PlayerPedId() + local coords = GetEntityCoords(playerPed) + + if IsPedInAnyVehicle(playerPed, false) then + local vehicle = GetVehiclePedIsIn(playerPed) + + for i=0, 7, 1 do + SetVehicleTyreBurst(vehicle, i, true, 1000) + end + end + end +end) + +AddEventHandler('esx_policejob:hasExitedEntityZone', function(entity) + if self.CurrentAction == 'remove_entity' then + self.CurrentAction = nil + end +end) + +RegisterNetEvent('esx_policejob:handcuff') +AddEventHandler('esx_policejob:handcuff', function() + self.IsHandcuffed = not self.IsHandcuffed + local playerPed = PlayerPedId() + + if self.IsHandcuffed then + RequestAnimDict('mp_arresting') + while not HasAnimDictLoaded('mp_arresting') do + Citizen.Wait(100) + end + + TaskPlayAnim(playerPed, 'mp_arresting', 'idle', 8.0, -8, -1, 49, 0, 0, 0, 0) + + SetEnableHandcuffs(playerPed, true) + DisablePlayerFiring(playerPed, true) + SetCurrentPedWeapon(playerPed, GetHashKey('WEAPON_UNARMED'), true) -- unarm player + SetPedCanPlayGestureAnims(playerPed, false) + FreezeEntityPosition(playerPed, true) + DisplayRadar(false) + + if self.Config.EnableHandcuffTimer then + if handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + + StartHandcuffTimer() + end + else + if self.Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + + ClearPedSecondaryTask(playerPed) + SetEnableHandcuffs(playerPed, false) + DisablePlayerFiring(playerPed, false) + SetPedCanPlayGestureAnims(playerPed, true) + FreezeEntityPosition(playerPed, false) + DisplayRadar(true) + end +end) + +RegisterNetEvent('esx_policejob:unrestrain') +AddEventHandler('esx_policejob:unrestrain', function() + + if self.IsHandcuffed then + + local playerPed = PlayerPedId() + + self.IsHandcuffed = false + + ClearPedSecondaryTask(playerPed) + SetEnableHandcuffs(playerPed, false) + DisablePlayerFiring(playerPed, false) + SetPedCanPlayGestureAnims(playerPed, true) + FreezeEntityPosition(playerPed, false) + DisplayRadar(true) + + -- end timer + if self.Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + end +end) + +RegisterNetEvent('esx_policejob:drag') +AddEventHandler('esx_policejob:drag', function(copId) + if self.IsHandcuffed then + dragStatus.isDragged = not dragStatus.isDragged + dragStatus.CopId = copId + end +end) + +RegisterNetEvent('esx_policejob:putInVehicle') +AddEventHandler('esx_policejob:putInVehicle', function() + if self.IsHandcuffed then + local playerPed = PlayerPedId() + local coords = GetEntityCoords(playerPed) + + if IsAnyVehicleNearPoint(coords, 5.0) then + local vehicle = GetClosestVehicle(coords, 5.0, 0, 71) + + if DoesEntityExist(vehicle) then + local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(vehicle) + + for i=maxSeats - 1, 0, -1 do + if IsVehicleSeatFree(vehicle, i) then + freeSeat = i + break + end + end + + if freeSeat then + TaskWarpPedIntoVehicle(playerPed, vehicle, freeSeat) + dragStatus.isDragged = false + end + end + end + end +end) + +RegisterNetEvent('esx_policejob:OutVehicle') +AddEventHandler('esx_policejob:OutVehicle', function() + local playerPed = PlayerPedId() + + if IsPedSittingInAnyVehicle(playerPed) then + local vehicle = GetVehiclePedIsIn(playerPed, false) + TaskLeaveVehicle(playerPed, vehicle, 16) + end +end) + +RegisterNetEvent('esx_policejob:updateBlip') +AddEventHandler('esx_policejob:updateBlip', function() + + -- Refresh all blips + for k, existingBlip in pairs(self.BlipsCops) do + RemoveBlip(existingBlip) + end + + -- Clean the blip table + self.BlipsCops = {} + + -- Enable blip? + if self.Config.EnableESXService and not playerInService then + return + end + + if not self.Config.EnableJobBlip then + return + end + + -- Is the player a cop? In that case show all the blips for other cops + if ESX.PlayerData.job and ESX.PlayerData.job.name == 'police' then + ESX.TriggerServerCallback('esx_society:getOnlinePlayers', function(players) + for i=1, #players, 1 do + if players[i].job.name == 'police' then + local id = GetPlayerFromServerId(players[i].source) + if NetworkIsPlayerActive(id) and GetPlayerPed(id) ~= PlayerPedId() then + CreateBlip(id) + end + end + end + end) + end + +end) + +AddEventHandler('playerSpawned', function(spawn) + isDead = false + TriggerEvent('esx_policejob:unrestrain') + + if not hasAlreadyJoined then + TriggerServerEvent('esx_policejob:spawned') + end + hasAlreadyJoined = true +end) + +AddEventHandler('esx:onPlayerDeath', function(data) + isDead = true +end) + +AddEventHandler('onResourceStop', function(resource) + if resource == GetCurrentResourceName() then + TriggerEvent('esx_policejob:unrestrain') + TriggerEvent('esx_phone:removeSpecialContact', 'police') + + if self.Config.EnableESXService then + TriggerServerEvent('esx_service:disableService', 'police') + end + + if self.Config.EnableHandcuffTimer and self.HandcuffTimer.active then + ESX.ClearTimeout(self.HandcuffTimer.task) + end + end +end) + +-- Key Controls +Input.On('released', Input.Groups.MOVE, Input.Controls.PICKUP, function(lastPressed) + + if self.CurrentAction and self.IsPolice() then + self.CurrentAction() + self.CurrentAction = nil + end + +end) + +Input.On('released', Input.Groups.MOVE, Input.Controls.SELECT_CHARACTER_FRANKLIN, function(lastPressed) + + if (not self.IsDead) and self.IsPolice() and (not ESX.UI.Menu.IsOpen('default', GetCurrentResourceName(), 'police_actions')) then + + if not self.Config.EnableESXService then + OpenPoliceActionsMenu() + elseif playerInService then + OpenPoliceActionsMenu() + else + ESX.ShowNotification(_U('job_police:service_not')) + end + + end + +end) + +Input.On('released', Input.Groups.MOVE, Input.Controls.PICKUP, function(lastPressed) + + if self.CurrentAction and self.IsPolice() and self.CurrentTask.busy then + + ESX.ShowNotification(_U('job_police:impound_canceled')) + ESX.ClearTimeout(self.CurrentTask.task) + ClearPedTasks(PlayerPedId()) + + self.CurrentTask.busy = false + + end + +end) diff --git a/modules/job_police/client/main.lua b/modules/job_police/client/main.lua new file mode 100644 index 00000000..b5a21e69 --- /dev/null +++ b/modules/job_police/client/main.lua @@ -0,0 +1,157 @@ +local self = ESX.Modules['job_police'] + +-- Init +self.Init() + +-- Drag +Citizen.CreateThread(function() + + local wasDragged = false + + while true do + Citizen.Wait(0) + local playerPed = PlayerPedId() + + if self.IsHandcuffed and self.DragStatus.isDragged then + + local targetPed = GetPlayerPed(GetPlayerFromServerId(self.DragStatus.CopId)) + + if DoesEntityExist(targetPed) and IsPedOnFoot(targetPed) and not IsPedDeadOrDying(targetPed, true) then + + if not wasDragged then + AttachEntityToEntity(playerPed, targetPed, 11816, 0.54, 0.54, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) + wasDragged = true + else + Citizen.Wait(1000) + end + + else + + wasDragged = false + self.DragStatus.isDragged = false + DetachEntity(playerPed, true, false) + + end + + elseif wasDragged then + + wasDragged = false + DetachEntity(playerPed, true, false) + + else + + Citizen.Wait(500) + + end + + end +end) + +-- Handcuff +Citizen.CreateThread(function() + while true do + Citizen.Wait(0) + local playerPed = PlayerPedId() + + if self.IsHandcuffed then + DisableControlAction(0, 1, true) -- Disable pan + DisableControlAction(0, 2, true) -- Disable tilt + DisableControlAction(0, 24, true) -- Attack + DisableControlAction(0, 257, true) -- Attack 2 + DisableControlAction(0, 25, true) -- Aim + DisableControlAction(0, 263, true) -- Melee Attack 1 + DisableControlAction(0, 32, true) -- W + DisableControlAction(0, 34, true) -- A + DisableControlAction(0, 31, true) -- S + DisableControlAction(0, 30, true) -- D + + DisableControlAction(0, 45, true) -- Reload + DisableControlAction(0, 22, true) -- Jump + DisableControlAction(0, 44, true) -- Cover + DisableControlAction(0, 37, true) -- Select Weapon + DisableControlAction(0, 23, true) -- Also 'enter'? + + DisableControlAction(0, 288, true) -- Disable phone + DisableControlAction(0, 289, true) -- Inventory + DisableControlAction(0, 170, true) -- Animations + DisableControlAction(0, 167, true) -- Job + + DisableControlAction(0, 0, true) -- Disable changing view + DisableControlAction(0, 26, true) -- Disable looking behind + DisableControlAction(0, 73, true) -- Disable clearing animation + DisableControlAction(2, 199, true) -- Disable pause screen + + DisableControlAction(0, 59, true) -- Disable steering in vehicle + DisableControlAction(0, 71, true) -- Disable driving forward in vehicle + DisableControlAction(0, 72, true) -- Disable reversing in vehicle + + DisableControlAction(2, 36, true) -- Disable going stealth + + DisableControlAction(0, 47, true) -- Disable weapon + DisableControlAction(0, 264, true) -- Disable melee + DisableControlAction(0, 257, true) -- Disable melee + DisableControlAction(0, 140, true) -- Disable melee + DisableControlAction(0, 141, true) -- Disable melee + DisableControlAction(0, 142, true) -- Disable melee + DisableControlAction(0, 143, true) -- Disable melee + DisableControlAction(0, 75, true) -- Disable exit vehicle + DisableControlAction(27, 75, true) -- Disable exit vehicle + + if IsEntityPlayingAnim(playerPed, 'mp_arresting', 'idle', 3) ~= 1 then + ESX.Streaming.RequestAnimDict('mp_arresting', function() + TaskPlayAnim(playerPed, 'mp_arresting', 'idle', 8.0, -8, -1, 49, 0.0, false, false, false) + end) + end + else + Citizen.Wait(500) + end + end +end) + +-- Enter / Exit entity zone events +Citizen.CreateThread(function() + local trackedEntities = { + 'prop_roadcone02a', + 'prop_barrier_work05', + 'p_ld_stinger_s', + 'prop_boxpile_07d', + 'hei_prop_cash_crate_half_full' + } + + while true do + Citizen.Wait(500) + + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + + local closestDistance = -1 + local closestEntity = nil + + for i=1, #trackedEntities, 1 do + local object = GetClosestObjectOfType(playerCoords, 3.0, GetHashKey(trackedEntities[i]), false, false, false) + + if DoesEntityExist(object) then + local objCoords = GetEntityCoords(object) + local distance = #(playerCoords - objCoords) + + if closestDistance == -1 or closestDistance > distance then + closestDistance = distance + closestEntity = object + end + end + end + + if closestDistance ~= -1 and closestDistance <= 3.0 then + if LastEntity ~= closestEntity then + TriggerEvent('esx_policejob:hasEnteredEntityZone', closestEntity) + LastEntity = closestEntity + end + else + if LastEntity then + TriggerEvent('esx_policejob:hasExitedEntityZone', LastEntity) + LastEntity = nil + end + end + end +end) + diff --git a/modules/job_police/client/module.lua b/modules/job_police/client/module.lua new file mode 100644 index 00000000..ed9d78dd --- /dev/null +++ b/modules/job_police/client/module.lua @@ -0,0 +1,1517 @@ +ESX.Modules['job_police'] = {} +local self = ESX.Modules['job_police'] + +-- Properties +self.Config = ESX.EvalFile(GetCurrentResourceName(), 'modules/job_police/data/config.lua', { + vector3 = vector3 +})['Config'] + +self.CurrentActionData = {} +self.HandcuffTimer = {} +self.DragStatus = {isDragged = false} +self.BlipsCops = {} +self.CurrentTask = {} +self.HasAlreadyEnteredMarker = false +self.IsDead = false +self.IsHandcuffed = false +self.HasAlreadyJoined = false +self.PlayerInService = false +self.LastStation = nil +self.LastPart = nil +self.LastPartNum = nil +self.LastEntity = nil +self.CurrentAction = nil +self.CurrentActionMsg = nil +self.IsInShopMenu = false +self.SpawnedVehicles = {} + +-- Locals +local Interact = ESX.Modules['interact'] +local Input = ESX.Modules['input'] + +-- Methods +self.Init = function() + + self.RegisterControls() + + local translations = ESX.EvalFile(GetCurrentResourceName(), 'modules/job_police/data/locales/' .. Config.Locale .. '.lua')['Translations'] + LoadLocale('job_police', Config.Locale, translations) + + for stationName, station in pairs(self.Config.PoliceStations) do + + -- Blip + local blip = AddBlipForCoord(station.Blip.Coords) + + SetBlipSprite (blip, station.Blip.Sprite) + SetBlipDisplay(blip, station.Blip.Display) + SetBlipScale (blip, station.Blip.Scale) + SetBlipColour (blip, station.Blip.Colour) + SetBlipAsShortRange(blip, true) + + BeginTextCommandSetBlipName('STRING') + AddTextComponentSubstringPlayerName(_U('job_police:map_blip')) + EndTextCommandSetBlipName(blip) + + -- Cloakrooms + for i=1, #station.Cloakrooms, 1 do + + local cloakroom = station.Cloakrooms[i] + local key = 'job_police:' .. stationName .. 'cloakroom:' .. tostring(i) + + Interact.Register({ + name = key, + type = 'marker', + distance = self.Config.DrawDistance, + radius = 2.0, + pos = cloakroom, + size = 1.0, + mtype = 20, + color = self.Config.MarkerColor, + rotate = true, + check = self.IsPolice, + }) + + AddEventHandler('esx:interact:enter:' .. key, function(data) + + ESX.ShowHelpNotification(_U('job_police:open_cloackroom')) + + self.CurrentAction = function() + self.OpenCloakroomMenu(station) + end + + end) + + AddEventHandler('esx:interact:exit:' .. key, function(data) + self.CurrentAction = nil + end) + + end + + -- Armories + for i=1, #station.Armories, 1 do + + local armory = station.Armories[i] + local key = 'job_police:' .. stationName .. ':armory:' .. tostring(i) + + Interact.Register({ + name = key, + type = 'marker', + distance = self.Config.DrawDistance, + radius = 1.0, + pos = armory, + size = 0.5, + mtype = 21, + color = self.Config.MarkerColor, + rotate = true, + check = self.IsPolice, + }) + + AddEventHandler('esx:interact:enter:' .. key, function(data) + + ESX.ShowHelpNotification(_U('job_police:open_armory')) + + self.CurrentAction = function() + self.OpenArmoryMenu(station) + end + + end) + + AddEventHandler('esx:interact:exit:' .. key, function(data) + self.CurrentAction = nil + end) + + end + + -- Vehicles + for i=1, #station.Vehicles, 1 do + + local vehicle = station.Vehicles[i] + local key = 'job_police:' .. stationName .. ':garage:' .. tostring(i) + + Interact.Register({ + name = key, + type = 'marker', + distance = self.Config.DrawDistance, + radius = 2.0, + pos = vehicle.Spawner, + size = 1.0, + mtype = 36, + color = self.Config.MarkerColor, + rotate = true, + check = self.IsPolice, + config = vehicle + }) + + AddEventHandler('esx:interact:enter:' .. key, function(data) + + ESX.ShowHelpNotification(_U('job_police:garage_prompt')) + + self.CurrentAction = function() + self.OpenVehicleSpawnerMenu('car', data.config) + end + + end) + + AddEventHandler('esx:interact:exit:' .. key, function(data) + self.CurrentAction = nil + end) + + end + + -- Helicopters + for i=1, #station.Helicopters, 1 do + + local heli = station.Helicopters[i] + local key = 'job_police:' .. stationName .. ':garage_heli:' .. tostring(i) + + Interact.Register({ + name = key, + type = 'marker', + distance = self.Config.DrawDistance, + radius = 2.0, + pos = heli.Spawner, + size = 1.0, + mtype = 36, + color = self.Config.MarkerColor, + rotate = true, + check = self.IsPolice, + config = heli + }) + + AddEventHandler('esx:interact:enter:' .. key, function(data) + + ESX.ShowHelpNotification(_U('job_police:helicopter_prompt')) + + self.CurrentAction = function() + self.OpenVehicleSpawnerMenu('helicopter', data.config) + end + + end) + + AddEventHandler('esx:interact:exit:' .. key, function(data) + self.CurrentAction = nil + end) + + end + + end + +end + +self.RegisterControls = function() + + Input.RegisterControl(Input.Groups.MOVE, Input.Controls.PICKUP) + Input.RegisterControl(Input.Groups.MOVE, Input.Controls.SELECT_CHARACTER_FRANKLIN) + Input.RegisterControl(Input.Groups.MOVE, Input.Controls.PICKUP) + +end + +self.IsPolice = function(playerPed, coords) + return ESX.PlayerData.job and ESX.PlayerData.job.name == 'police' +end + +self.CleanPlayer = function(playerPed) + SetPedArmour(playerPed, 0) + ClearPedBloodDamage(playerPed) + ResetPedVisibleDamage(playerPed) + ClearPedLastWeaponDamage(playerPed) + ResetPedMovementClipset(playerPed, 0) +end + +self.SetUniform = function(uniform, playerPed) + + TriggerEvent('skinchanger:getSkin', function(skin) + + local uniformObject + + if skin.sex == 0 then + uniformObject = self.Config.Uniforms[uniform].male + else + uniformObject = self.Config.Uniforms[uniform].female + end + + if uniformObject then + TriggerEvent('skinchanger:loadClothes', skin, uniformObject) + + if uniform == 'bullet_wear' then + SetPedArmour(playerPed, 100) + end + else + ESX.ShowNotification(_U('job_police:no_outfit')) + end + end) + +end + +self.OpenCloakroomMenu = function() + + local playerPed = PlayerPedId() + local grade = ESX.PlayerData.job.grade_name + + local elements = { + {label = _U('job_police:citizen_wear'), value = 'citizen_wear'}, + {label = _U('job_police:bullet_wear'), uniform = 'bullet_wear'}, + {label = _U('job_police:gilet_wear'), uniform = 'gilet_wear'}, + {label = _U('job_police:police_wear'), uniform = grade} + } + + if self.Config.EnableCustomPeds then + for k,v in ipairs(Config.CustomPeds.shared) do + table.insert(elements, {label = v.label, value = 'freemode_ped', maleModel = v.maleModel, femaleModel = v.femaleModel}) + end + + for k,v in ipairs(Config.CustomPeds[grade]) do + table.insert(elements, {label = v.label, value = 'freemode_ped', maleModel = v.maleModel, femaleModel = v.femaleModel}) + end + end + + ESX.UI.Menu.CloseAll() + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'cloakroom', { + title = _U('job_police:cloakroom'), + align = 'top-left', + elements = elements + }, function(data, menu) + + menu.close() + + self.CleanPlayer(playerPed) + + if data.current.value == 'citizen_wear' then + if self.Config.EnableNonFreemodePeds then + ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin) + local isMale = skin.sex == 0 + + TriggerEvent('skinchanger:loadDefaultModel', isMale, function() + ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin) + TriggerEvent('skinchanger:loadSkin', skin) + TriggerEvent('esx:restoreLoadout') + end) + end) + + end) + else + ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin) + TriggerEvent('skinchanger:loadSkin', skin) + end) + end + + if self.Config.EnableESXService then + ESX.TriggerServerCallback('esx_service:isInService', function(isInService) + if isInService then + PlayerInService = false + + local notification = { + title = _U('job_police:service_anonunce'), + subject = '', + msg = _U('job_police:service_out_announce', GetPlayerName(PlayerId())), + iconType = 1 + } + + TriggerServerEvent('esx_service:notifyAllInService', notification, 'police') + + TriggerServerEvent('esx_service:disableService', 'police') + TriggerEvent('esx_policejob:updateBlip') + ESX.ShowNotification(_U('job_police:service_out')) + end + end, 'police') + end + end + + if self.Config.EnableESXService and data.current.value ~= 'citizen_wear' then + local awaitService + + ESX.TriggerServerCallback('esx_service:isInService', function(isInService) + if not isInService then + + ESX.TriggerServerCallback('esx_service:enableService', function(canTakeService, maxInService, inServiceCount) + if not canTakeService then + ESX.ShowNotification(_U('job_police:service_max', inServiceCount, maxInService)) + else + awaitService = true + PlayerInService = true + + local notification = { + title = _U('job_police:service_anonunce'), + subject = '', + msg = _U('job_police:service_in_announce', GetPlayerName(PlayerId())), + iconType = 1 + } + + TriggerServerEvent('esx_service:notifyAllInService', notification, 'police') + TriggerEvent('esx_policejob:updateBlip') + ESX.ShowNotification(_U('job_police:service_in')) + end + end, 'police') + + else + awaitService = true + end + end, 'police') + + while awaitService == nil do + Citizen.Wait(5) + end + + -- if we couldn't enter service don't let the player get changed + if not awaitService then + return + end + end + + if data.current.uniform then + self.SetUniform(data.current.uniform, playerPed) + elseif data.current.value == 'freemode_ped' then + local modelHash + + ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin) + if skin.sex == 0 then + modelHash = GetHashKey(data.current.maleModel) + else + modelHash = GetHashKey(data.current.femaleModel) + end + + ESX.Streaming.RequestModel(modelHash, function() + SetPlayerModel(PlayerId(), modelHash) + SetModelAsNoLongerNeeded(modelHash) + SetPedDefaultComponentVariation(PlayerPedId()) + + TriggerEvent('esx:restoreLoadout') + end) + end) + end + end, function(data, menu) + + menu.close() + + end, nil, function() + + ESX.ShowHelpNotification(_U('job_police:open_cloackroom')) + + self.CurrentAction = function() + self.OpenCloakroomMenu(station) + end + + end) + +end + +self.OpenArmoryMenu = function(station) + local elements = { + {label = _U('job_police:buy_weapons'), value = 'buy_weapons'} + } + + if self.Config.EnableArmoryManagement then + table.insert(elements, {label = _U('job_police:get_weapon'), value = 'get_weapon'}) + table.insert(elements, {label = _U('job_police:put_weapon'), value = 'put_weapon'}) + table.insert(elements, {label = _U('job_police:remove_object'), value = 'get_stock'}) + table.insert(elements, {label = _U('job_police:deposit_object'), value = 'put_stock'}) + end + + ESX.UI.Menu.CloseAll() + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory', { + title = _U('job_police:armory'), + align = 'top-left', + elements = elements + }, function(data, menu) + + if data.current.value == 'get_weapon' then + self.OpenGetWeaponMenu() + elseif data.current.value == 'put_weapon' then + self.OpenPutWeaponMenu() + elseif data.current.value == 'buy_weapons' then + self.OpenBuyWeaponsMenu() + elseif data.current.value == 'put_stock' then + self.OpenPutStocksMenu() + elseif data.current.value == 'get_stock' then + self.OpenGetStocksMenu() + end + + end, function(data, menu) + menu.close() + end, nil, function() + + + ESX.ShowHelpNotification(_U('job_police:open_armory')) + + self.CurrentAction = function() + self.OpenArmoryMenu(station) + end + + return true + + end) + +end + +self.OpenPoliceActionsMenu = function() + ESX.UI.Menu.CloseAll() + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'police_actions', { + title = 'Police', + align = 'top-left', + elements = { + {label = _U('job_police:citizen_interaction'), value = 'citizen_interaction'}, + {label = _U('job_police:vehicle_interaction'), value = 'vehicle_interaction'}, + {label = _U('job_police:object_spawner'), value = 'object_spawner'} + }}, function(data, menu) + if data.current.value == 'citizen_interaction' then + local elements = { + {label = _U('job_police:id_card'), value = 'identity_card'}, + {label = _U('job_police:search'), value = 'search'}, + {label = _U('job_police:handcuff'), value = 'handcuff'}, + {label = _U('job_police:drag'), value = 'drag'}, + {label = _U('job_police:put_in_vehicle'), value = 'put_in_vehicle'}, + {label = _U('job_police:out_the_vehicle'), value = 'out_the_vehicle'}, + {label = _U('job_police:fine'), value = 'fine'}, + {label = _U('job_police:unpaid_bills'), value = 'unpaid_bills'} + } + + if self.Config.EnableLicenses then + table.insert(elements, {label = _U('job_police:license_check'), value = 'license'}) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', { + title = _U('job_police:citizen_interaction'), + align = 'top-left', + elements = elements + }, function(data2, menu2) + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + if closestPlayer ~= -1 and closestDistance <= 3.0 then + local action = data2.current.value + + if action == 'identity_card' then + OpenIdentityCardMenu(closestPlayer) + elseif action == 'search' then + OpenBodySearchMenu(closestPlayer) + elseif action == 'handcuff' then + TriggerServerEvent('esx_policejob:handcuff', GetPlayerServerId(closestPlayer)) + elseif action == 'drag' then + TriggerServerEvent('esx_policejob:drag', GetPlayerServerId(closestPlayer)) + elseif action == 'put_in_vehicle' then + TriggerServerEvent('esx_policejob:putInVehicle', GetPlayerServerId(closestPlayer)) + elseif action == 'out_the_vehicle' then + TriggerServerEvent('esx_policejob:OutVehicle', GetPlayerServerId(closestPlayer)) + elseif action == 'fine' then + OpenFineMenu(closestPlayer) + elseif action == 'license' then + ShowPlayerLicense(closestPlayer) + elseif action == 'unpaid_bills' then + OpenUnpaidBillsMenu(closestPlayer) + end + else + ESX.ShowNotification(_U('job_police:no_players_nearby')) + end + end, function(data2, menu2) + menu2.close() + end) + elseif data.current.value == 'vehicle_interaction' then + local elements = {} + local playerPed = PlayerPedId() + local vehicle = ESX.Game.GetVehicleInDirection() + + if DoesEntityExist(vehicle) then + table.insert(elements, {label = _U('job_police:vehicle_info'), value = 'vehicle_infos'}) + table.insert(elements, {label = _U('job_police:pick_lock'), value = 'hijack_vehicle'}) + table.insert(elements, {label = _U('job_police:impound'), value = 'impound'}) + end + + table.insert(elements, {label = _U('job_police:search_database'), value = 'search_database'}) + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_interaction', { + title = _U('job_police:vehicle_interaction'), + align = 'top-left', + elements = elements + }, function(data2, menu2) + local coords = GetEntityCoords(playerPed) + vehicle = ESX.Game.GetVehicleInDirection() + action = data2.current.value + + if action == 'search_database' then + LookupVehicle() + elseif DoesEntityExist(vehicle) then + if action == 'vehicle_infos' then + local vehicleData = ESX.Game.GetVehicleProperties(vehicle) + OpenVehicleInfosMenu(vehicleData) + elseif action == 'hijack_vehicle' then + if IsAnyVehicleNearPoint(coords.x, coords.y, coords.z, 3.0) then + TaskStartScenarioInPlace(playerPed, 'WORLD_HUMAN_WELDING', 0, true) + Citizen.Wait(20000) + ClearPedTasksImmediately(playerPed) + + SetVehicleDoorsLocked(vehicle, 1) + SetVehicleDoorsLockedForAllPlayers(vehicle, false) + ESX.ShowNotification(_U('job_police:vehicle_unlocked')) + end + elseif action == 'impound' then + -- is the script busy? + if CurrentTask.busy then + return + end + + ESX.ShowHelpNotification(_U('job_police:impound_prompt')) + TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true) + + CurrentTask.busy = true + CurrentTask.task = ESX.SetTimeout(10000, function() + ClearPedTasks(playerPed) + ImpoundVehicle(vehicle) + Citizen.Wait(100) -- sleep the entire script to let stuff sink back to reality + end) + + -- keep track of that vehicle! + Citizen.CreateThread(function() + while CurrentTask.busy do + Citizen.Wait(1000) + + vehicle = GetClosestVehicle(coords.x, coords.y, coords.z, 3.0, 0, 71) + if not DoesEntityExist(vehicle) and CurrentTask.busy then + ESX.ShowNotification(_U('job_police:impound_canceled_moved')) + ESX.ClearTimeout(CurrentTask.task) + ClearPedTasks(playerPed) + CurrentTask.busy = false + break + end + end + end) + end + else + ESX.ShowNotification(_U('job_police:no_vehicles_nearby')) + end + + end) + + elseif data.current.value == 'object_spawner' then + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', { + title = _U('job_police:traffic_interaction'), + align = 'top-left', + elements = { + {label = _U('job_police:cone'), model = 'prop_roadcone02a'}, + {label = _U('job_police:barrier'), model = 'prop_barrier_work05'}, + {label = _U('job_police:spikestrips'), model = 'p_ld_stinger_s'}, + {label = _U('job_police:box'), model = 'prop_boxpile_07d'}, + {label = _U('job_police:cash'), model = 'hei_prop_cash_crate_half_full'} + }}, function(data2, menu2) + local playerPed = PlayerPedId() + local coords, forward = GetEntityCoords(playerPed), GetEntityForwardVector(playerPed) + local objectCoords = (coords + forward * 1.0) + + ESX.Game.SpawnObject(data2.current.model, objectCoords, function(obj) + SetEntityHeading(obj, GetEntityHeading(playerPed)) + PlaceObjectOnGroundProperly(obj) + end) + end, function(data2, menu2) + menu2.close() + end) + end + end) + +end + +self.OpenIdentityCardMenu = function(player) + ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(data) + local elements = { + {label = _U('job_police:name', data.name)}, + {label = _U('job_police:job', ('%s - %s'):format(data.job, data.grade))} + } + + if self.Config.EnableESXIdentity then + table.insert(elements, {label = _U('job_police:sex', _U(data.sex))}) + table.insert(elements, {label = _U('job_police:dob', data.dob)}) + table.insert(elements, {label = _U('job_police:height', data.height)}) + end + + if data.drunk then + table.insert(elements, {label = _U('job_police:bac', data.drunk)}) + end + + if data.licenses then + table.insert(elements, {label = _U('job_police:license_label')}) + + for i=1, #data.licenses, 1 do + table.insert(elements, {label = data.licenses[i].label}) + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction', { + title = _U('job_police:citizen_interaction'), + align = 'top-left', + elements = elements + }, nil, function(data, menu) + menu.close() + end) + end, GetPlayerServerId(player)) +end + +self.OpenBodySearchMenu = function(player) + ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(data) + local elements = {} + + for i=1, #data.accounts, 1 do + if data.accounts[i].name == 'black_money' and data.accounts[i].money > 0 then + table.insert(elements, { + label = _U('job_police:confiscate_dirty', ESX.Math.Round(data.accounts[i].money)), + value = 'black_money', + itemType = 'item_account', + amount = data.accounts[i].money + }) + + break + end + end + + table.insert(elements, {label = _U('job_police:guns_label')}) + + for i=1, #data.weapons, 1 do + table.insert(elements, { + label = _U('job_police:confiscate_weapon', ESX.GetWeaponLabel(data.weapons[i].name), data.weapons[i].ammo), + value = data.weapons[i].name, + itemType = 'item_weapon', + amount = data.weapons[i].ammo + }) + end + + table.insert(elements, {label = _U('job_police:inventory_label')}) + + for i=1, #data.inventory, 1 do + if data.inventory[i].count > 0 then + table.insert(elements, { + label = _U('job_police:confiscate_inv', data.inventory[i].count, data.inventory[i].label), + value = data.inventory[i].name, + itemType = 'item_standard', + amount = data.inventory[i].count + }) + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'body_search', { + title = _U('job_police:search'), + align = 'top-left', + elements = elements + }, function(data, menu) + if data.current.value then + TriggerServerEvent('esx_policejob:confiscatePlayerItem', GetPlayerServerId(player), data.current.itemType, data.current.value, data.current.amount) + OpenBodySearchMenu(player) + end + end, function(data, menu) + menu.close() + end) + end, GetPlayerServerId(player)) +end + +self.OpenFineMenu = function(player) + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'fine', { + title = _U('job_police:fine'), + align = 'top-left', + elements = { + {label = _U('job_police:traffic_offense'), value = 0}, + {label = _U('job_police:minor_offense'), value = 1}, + {label = _U('job_police:average_offense'), value = 2}, + {label = _U('job_police:major_offense'), value = 3} + }}, function(data, menu) + OpenFineCategoryMenu(player, data.current.value) + end, function(data, menu) + menu.close() + end) +end + +self.OpenFineCategoryMenu = function(player, category) + ESX.TriggerServerCallback('esx_policejob:getFineList', function(fines) + local elements = {} + + for k,fine in ipairs(fines) do + table.insert(elements, { + label = ('%s %s'):format(fine.label, _U('job_police:armory_item', ESX.Math.GroupDigits(fine.amount))), + value = fine.id, + amount = fine.amount, + fineLabel = fine.label + }) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'fine_category', { + title = _U('job_police:fine'), + align = 'top-left', + elements = elements + }, function(data, menu) + menu.close() + + if self.Config.EnablePlayerManagement then + TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(player), 'society_police', _U('job_police:fine_total', data.current.fineLabel), data.current.amount) + else + TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(player), '', _U('job_police:fine_total', data.current.fineLabel), data.current.amount) + end + + ESX.SetTimeout(300, function() + OpenFineCategoryMenu(player, category) + end) + end, function(data, menu) + menu.close() + end) + end, category) +end + +self.LookupVehicle = function() + ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'lookup_vehicle', { + title = _U('job_police:search_database_title'), + }, function(data, menu) + local length = string.len(data.value) + if not data.value or length < 2 or length > 8 then + ESX.ShowNotification(_U('job_police:search_database_error_invalid')) + else + ESX.TriggerServerCallback('esx_policejob:getVehicleInfos', function(retrivedInfo) + local elements = {{label = _U('job_police:plate', retrivedInfo.plate)}} + menu.close() + + if not retrivedInfo.owner then + table.insert(elements, {label = _U('job_police:owner_unknown')}) + else + table.insert(elements, {label = _U('job_police:owner', retrivedInfo.owner)}) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_infos', { + title = _U('job_police:vehicle_info'), + align = 'top-left', + elements = elements + }, nil, function(data2, menu2) + menu2.close() + end) + end, data.value) + + end + end, function(data, menu) + menu.close() + end) +end + +self.ShowPlayerLicense = function(player) + local elements = {} + + ESX.TriggerServerCallback('esx_policejob:getOtherPlayerData', function(playerData) + if playerData.licenses then + for i=1, #playerData.licenses, 1 do + if playerData.licenses[i].label and playerData.licenses[i].type then + table.insert(elements, { + label = playerData.licenses[i].label, + type = playerData.licenses[i].type + }) + end + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'manage_license', { + title = _U('job_police:license_revoke'), + align = 'top-left', + elements = elements, + }, function(data, menu) + ESX.ShowNotification(_U('job_police:licence_you_revoked', data.current.label, playerData.name)) + TriggerServerEvent('esx_policejob:message', GetPlayerServerId(player), _U('job_police:license_revoked', data.current.label)) + + TriggerServerEvent('esx_license:removeLicense', GetPlayerServerId(player), data.current.type) + + ESX.SetTimeout(300, function() + ShowPlayerLicense(player) + end) + end, function(data, menu) + menu.close() + end) + + end, GetPlayerServerId(player)) +end + +self.OpenUnpaidBillsMenu = function(player) + local elements = {} + + ESX.TriggerServerCallback('esx_billing:getTargetBills', function(bills) + for k,bill in ipairs(bills) do + table.insert(elements, { + label = ('%s - %s'):format(bill.label, _U('job_police:armory_item', ESX.Math.GroupDigits(bill.amount))), + billId = bill.id + }) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'billing', { + title = _U('job_police:unpaid_bills'), + align = 'top-left', + elements = elements + }, nil, function(data, menu) + menu.close() + end) + end, GetPlayerServerId(player)) +end + +self.OpenVehicleInfosMenu = function(vehicleData) + ESX.TriggerServerCallback('esx_policejob:getVehicleInfos', function(retrivedInfo) + local elements = {{label = _U('job_police:plate', retrivedInfo.plate)}} + + if not retrivedInfo.owner then + table.insert(elements, {label = _U('job_police:owner_unknown')}) + else + table.insert(elements, {label = _U('job_police:owner', retrivedInfo.owner)}) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_infos', { + title = _U('job_police:vehicle_info'), + align = 'top-left', + elements = elements + }, nil, function(data, menu) + menu.close() + end) + end, vehicleData.plate) +end + +self.OpenGetWeaponMenu = function() + ESX.TriggerServerCallback('esx_policejob:getArmoryWeapons', function(weapons) + local elements = {} + + for i=1, #weapons, 1 do + if weapons[i].count > 0 then + table.insert(elements, { + label = 'x' .. weapons[i].count .. ' ' .. ESX.GetWeaponLabel(weapons[i].name), + value = weapons[i].name + }) + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_get_weapon', { + title = _U('job_police:get_weapon_menu'), + align = 'top-left', + elements = elements + }, function(data, menu) + menu.close() + + ESX.TriggerServerCallback('esx_policejob:removeArmoryWeapon', function() + OpenGetWeaponMenu() + end, data.current.value) + end, function(data, menu) + menu.close() + end) + end) +end + +self.OpenPutWeaponMenu = function() + local elements = {} + local playerPed = PlayerPedId() + local weaponList = ESX.GetWeaponList() + + for i=1, #weaponList, 1 do + local weaponHash = GetHashKey(weaponList[i].name) + + if HasPedGotWeapon(playerPed, weaponHash, false) and weaponList[i].name ~= 'WEAPON_UNARMED' then + table.insert(elements, { + label = weaponList[i].label, + value = weaponList[i].name + }) + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_put_weapon', { + title = _U('job_police:put_weapon_menu'), + align = 'top-left', + elements = elements + }, function(data, menu) + menu.close() + + ESX.TriggerServerCallback('esx_policejob:addArmoryWeapon', function() + OpenPutWeaponMenu() + end, data.current.value, true) + end, function(data, menu) + menu.close() + end) +end + +self.OpenBuyWeaponsMenu = function() + local elements = {} + local playerPed = PlayerPedId() + + local authorizedWeapons = {} + + for i=1, ESX.PlayerData.job.grade, 1 do + + local weapons = self.Config.AuthorizedWeapons[i] + + for j=1, #weapons, 1 do + authorizedWeapons[#authorizedWeapons + 1] = weapons[j] + end + + end + + for k,v in ipairs(authorizedWeapons) do + local weaponNum, weapon = ESX.GetWeapon(v.weapon) + local components, label = {} + local hasWeapon = HasPedGotWeapon(playerPed, GetHashKey(v.weapon), false) + + if v.components then + for i=1, #v.components do + if v.components[i] then + local component = weapon.components[i] + local hasComponent = HasPedGotWeaponComponent(playerPed, GetHashKey(v.weapon), component.hash) + + if hasComponent then + label = ('%s: %s'):format(component.label, _U('job_police:armory_owned')) + else + if v.components[i] > 0 then + label = ('%s: %s'):format(component.label, _U('job_police:armory_item', ESX.Math.GroupDigits(v.components[i]))) + else + label = ('%s: %s'):format(component.label, _U('job_police:armory_free')) + end + end + + table.insert(components, { + label = label, + componentLabel = component.label, + hash = component.hash, + name = component.name, + price = v.components[i], + hasComponent = hasComponent, + componentNum = i + }) + end + end + end + + if hasWeapon and v.components then + label = ('%s: >'):format(weapon.label) + elseif hasWeapon and not v.components then + label = ('%s: %s'):format(weapon.label, _U('job_police:armory_owned')) + else + if v.price > 0 then + label = ('%s: %s'):format(weapon.label, _U('job_police:armory_item', ESX.Math.GroupDigits(v.price))) + else + label = ('%s: %s'):format(weapon.label, _U('job_police:armory_free')) + end + end + + table.insert(elements, { + label = label, + weaponLabel = weapon.label, + name = weapon.name, + components = components, + price = v.price, + hasWeapon = hasWeapon + }) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_buy_weapons', { + title = _U('job_police:armory_weapontitle'), + align = 'top-left', + elements = elements + }, function(data, menu) + if data.current.hasWeapon then + if #data.current.components > 0 then + OpenWeaponComponentShop(data.current.components, data.current.name, menu) + end + else + ESX.TriggerServerCallback('esx_policejob:buyWeapon', function(bought) + if bought then + if data.current.price > 0 then + ESX.ShowNotification(_U('job_police:armory_bought', data.current.weaponLabel, ESX.Math.GroupDigits(data.current.price))) + end + + menu.close() + OpenBuyWeaponsMenu() + else + ESX.ShowNotification(_U('job_police:armory_money')) + end + end, data.current.name, 1) + end + end, function(data, menu) + menu.close() + end) +end + +self.OpenWeaponComponentShop = function(components, weaponName, parentShop) + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'armory_buy_weapons_components', { + title = _U('job_police:armory_componenttitle'), + align = 'top-left', + elements = components + }, function(data, menu) + if data.current.hasComponent then + ESX.ShowNotification(_U('job_police:armory_hascomponent')) + else + ESX.TriggerServerCallback('esx_policejob:buyWeapon', function(bought) + if bought then + if data.current.price > 0 then + ESX.ShowNotification(_U('job_police:armory_bought', data.current.componentLabel, ESX.Math.GroupDigits(data.current.price))) + end + + menu.close() + parentShop.close() + OpenBuyWeaponsMenu() + else + ESX.ShowNotification(_U('job_police:armory_money')) + end + end, weaponName, 2, data.current.componentNum) + end + end, function(data, menu) + menu.close() + end) +end + +self.OpenGetStocksMenu = function() + ESX.TriggerServerCallback('esx_policejob:getStockItems', function(items) + local elements = {} + + for i=1, #items, 1 do + table.insert(elements, { + label = 'x' .. items[i].count .. ' ' .. items[i].label, + value = items[i].name + }) + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'stocks_menu', { + title = _U('job_police:police_stock'), + align = 'top-left', + elements = elements + }, function(data, menu) + local itemName = data.current.value + + ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'stocks_menu_get_item_count', { + title = _U('job_police:quantity') + }, function(data2, menu2) + local count = tonumber(data2.value) + + if not count then + ESX.ShowNotification(_U('job_police:quantity_invalid')) + else + menu2.close() + menu.close() + TriggerServerEvent('esx_policejob:getStockItem', itemName, count) + + Citizen.Wait(300) + OpenGetStocksMenu() + end + end, function(data2, menu2) + menu2.close() + end) + end, function(data, menu) + menu.close() + end) + end) +end + +self.OpenPutStocksMenu = function() + ESX.TriggerServerCallback('esx_policejob:getPlayerInventory', function(inventory) + local elements = {} + + for i=1, #inventory.items, 1 do + local item = inventory.items[i] + + if item.count > 0 then + table.insert(elements, { + label = item.label .. ' x' .. item.count, + type = 'item_standard', + value = item.name + }) + end + end + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'stocks_menu', { + title = _U('job_police:inventory'), + align = 'top-left', + elements = elements + }, function(data, menu) + local itemName = data.current.value + + ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'stocks_menu_put_item_count', { + title = _U('job_police:quantity') + }, function(data2, menu2) + local count = tonumber(data2.value) + + if not count then + ESX.ShowNotification(_U('job_police:quantity_invalid')) + else + menu2.close() + menu.close() + TriggerServerEvent('esx_policejob:putStockItems', itemName, count) + + Citizen.Wait(300) + OpenPutStocksMenu() + end + end, function(data2, menu2) + menu2.close() + end) + end, function(data, menu) + menu.close() + end) + end) +end + +-- Create blip for colleagues +self.CreateBlip = function(id) + local ped = GetPlayerPed(id) + local blip = GetBlipFromEntity(ped) + + if not DoesBlipExist(blip) then -- Add blip and create head display on player + blip = AddBlipForEntity(ped) + SetBlipSprite(blip, 1) + ShowHeadingIndicatorOnBlip(blip, true) -- Player Blip indicator + SetBlipRotation(blip, math.ceil(GetEntityHeading(ped))) -- update rotation + SetBlipNameToPlayerName(blip, id) -- update blip name + SetBlipScale(blip, 0.85) -- set scale + SetBlipAsShortRange(blip, true) + + table.insert(blipsCops, blip) -- add blip to array so we can remove it later + end +end + +-- handcuff timer, unrestrain the player after an certain amount of time +self.StartHandcuffTimer = function() + if self.Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + + handcuffTimer.active = true + + handcuffTimer.task = ESX.SetTimeout(Config.HandcuffTimer, function() + ESX.ShowNotification(_U('job_police:unrestrained_timer')) + TriggerEvent('esx_policejob:unrestrain') + handcuffTimer.active = false + end) + +end + +-- TODO +-- - return to garage if owned +-- - message owner that his vehicle has been impounded +self.ImpoundVehicle = function(vehicle) + --local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))) + ESX.Game.DeleteVehicle(vehicle) + ESX.ShowNotification(_U('job_police:impound_successful')) + currentTask.busy = false +end + +self.OpenVehicleSpawnerMenu = function(type, config) + + local playerCoords = GetEntityCoords(PlayerPedId()) + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle', { + title = _U('job_police:garage_title'), + align = 'top-left', + elements = { + {label = _U('job_police:garage_storeditem'), action = 'garage'}, + {label = _U('job_police:garage_storeitem'), action = 'store_garage'}, + {label = _U('job_police:garage_buyitem'), action = 'buy_vehicle'} + }}, function(data, menu) + + if data.current.action == 'buy_vehicle' then + + local shopElements = {} + local authorizedVehicles = {} + + for i=1, ESX.PlayerData.job.grade, 1 do + + local vehicles = self.Config.AuthorizedVehicles[type][i] + + for j=1, #vehicles, 1 do + authorizedVehicles[#authorizedVehicles + 1] = vehicles[j] + end + + end + + if authorizedVehicles then + if #authorizedVehicles > 0 then + for k,vehicle in ipairs(authorizedVehicles) do + if IsModelInCdimage(vehicle.model) then + local vehicleLabel = GetLabelText(GetDisplayNameFromVehicleModel(vehicle.model)) + + table.insert(shopElements, { + label = ('%s - %s'):format(vehicleLabel, _U('job_police:shop_item', ESX.Math.GroupDigits(vehicle.price))), + name = vehicleLabel, + model = vehicle.model, + price = vehicle.price, + props = vehicle.props, + type = type + }) + end + end + + if #shopElements > 0 then + self.OpenShopMenu(shopElements, config) + else + ESX.ShowNotification(_U('job_police:garage_notauthorized')) + end + else + ESX.ShowNotification(_U('job_police:garage_notauthorized')) + end + else + ESX.ShowNotification(_U('job_police:garage_notauthorized')) + end + elseif data.current.action == 'garage' then + local garage = {} + + ESX.TriggerServerCallback('esx_vehicleshop:retrieveJobVehicles', function(jobVehicles) + if #jobVehicles > 0 then + local allVehicleProps = {} + + for k,v in ipairs(jobVehicles) do + local props = json.decode(v.vehicle) + + if IsModelInCdimage(props.model) then + local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(props.model)) + local label = ('%s - %s: '):format(vehicleName, props.plate) + + if v.stored then + label = label .. ('%s'):format(_U('job_police:garage_stored')) + else + label = label .. ('%s'):format(_U('job_police:garage_notstored')) + end + + table.insert(garage, { + label = label, + stored = v.stored, + model = props.model, + plate = props.plate + }) + + allVehicleProps[props.plate] = props + end + end + + if #garage > 0 then + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_garage', { + title = _U('job_police:garage_title'), + align = 'top-left', + elements = garage + }, function(data2, menu2) + if data2.current.stored then + + + local foundSpawn, spawnPoint = self.GetAvailableVehicleSpawnPoint(config.SpawnPoints) + + if foundSpawn then + menu2.close() + + ESX.Game.SpawnVehicle(data2.current.model, spawnPoint.coords, spawnPoint.heading, function(vehicle) + local vehicleProps = allVehicleProps[data2.current.plate] + ESX.Game.SetVehicleProperties(vehicle, vehicleProps) + + TriggerServerEvent('esx_vehicleshop:setJobVehicleState', data2.current.plate, false) + ESX.ShowNotification(_U('job_police:garage_released')) + end) + end + + else + ESX.ShowNotification(_U('job_police:garage_notavailable')) + end + end, function(data2, menu2) + menu2.close() + end) + else + ESX.ShowNotification(_U('job_police:garage_empty')) + end + else + ESX.ShowNotification(_U('job_police:garage_empty')) + end + end, type) + + elseif data.current.action == 'store_garage' then + StoreNearbyVehicle(playerCoords) + end + end, function(data, menu) + menu.close() + end, nil, function() + + if type == 'car' then + + ESX.ShowHelpNotification(_U('job_police:garage_prompt')) + + self.CurrentAction = function() + self.OpenVehicleSpawnerMenu('car', data.config) + end + + elseif type == 'helicopter' then + + ESX.ShowHelpNotification(_U('job_police:helicopter_prompt')) + + self.CurrentAction = function() + self.OpenVehicleSpawnerMenu('helicopter', data.config) + end + + end + + end) + +end + +self.StoreNearbyVehicle = function(playerCoords) + local vehicles, vehiclePlates = ESX.Game.GetVehiclesInArea(playerCoords, 30.0), {} + + if #vehicles > 0 then + for k,v in ipairs(vehicles) do + + -- Make sure the vehicle we're saving is empty, or else it wont be deleted + if GetVehicleNumberOfPassengers(v) == 0 and IsVehicleSeatFree(v, -1) then + table.insert(vehiclePlates, { + vehicle = v, + plate = ESX.Math.Trim(GetVehicleNumberPlateText(v)) + }) + end + end + else + ESX.ShowNotification(_U('job_police:garage_store_nearby')) + return + end + + ESX.TriggerServerCallback('esx_policejob:storeNearbyVehicle', function(storeSuccess, foundNum) + if storeSuccess then + local vehicleId = vehiclePlates[foundNum] + local attempts = 0 + ESX.Game.DeleteVehicle(vehicleId.vehicle) + IsBusy = true + + Citizen.CreateThread(function() + BeginTextCommandBusyspinnerOn('STRING') + AddTextComponentSubstringPlayerName(_U('job_police:garage_storing')) + EndTextCommandBusyspinnerOn(4) + + while IsBusy do + Citizen.Wait(100) + end + + BusyspinnerOff() + end) + + -- Workaround for vehicle not deleting when other players are near it. + while DoesEntityExist(vehicleId.vehicle) do + Citizen.Wait(500) + attempts = attempts + 1 + + -- Give up + if attempts > 30 then + break + end + + vehicles = ESX.Game.GetVehiclesInArea(playerCoords, 30.0) + if #vehicles > 0 then + for k,v in ipairs(vehicles) do + if ESX.Math.Trim(GetVehicleNumberPlateText(v)) == vehicleId.plate then + ESX.Game.DeleteVehicle(v) + break + end + end + end + end + + IsBusy = false + ESX.ShowNotification(_U('job_police:garage_has_stored')) + else + ESX.ShowNotification(_U('job_police:garage_has_notstored')) + end + end, vehiclePlates) +end + +self.GetAvailableVehicleSpawnPoint = function(spawnPoints) + + local found, foundSpawnPoint = false, nil + + for i=1, #spawnPoints, 1 do + if ESX.Game.IsSpawnPointClear(spawnPoints[i].coords, spawnPoints[i].radius) then + found, foundSpawnPoint = true, spawnPoints[i] + break + end + end + + if found then + return true, foundSpawnPoint + else + ESX.ShowNotification(_U('job_police:vehicle_blocked')) + return false + end +end + +self.OpenShopMenu = function(elements, config) + + local playerPed = PlayerPedId() + isInShopMenu = true + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop', { + title = _U('job_police:vehicleshop_title'), + align = 'top-left', + elements = elements + }, function(data, menu) + + menu.close() + + ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop_confirm', { + title = _U('job_police:vehicleshop_confirm', data.current.name, data.current.price), + align = 'top-left', + elements = { + {label = _U('job_police:confirm_no'), value = 'no'}, + {label = _U('job_police:confirm_yes'), value = 'yes'} + }}, function(data2, menu2) + + menu2.close() + + if data2.current.value == 'yes' then + + ESX.TriggerServerCallback('esx_policejob:canBuyVehicle', function (success) + + if success then + + local foundSpawn, spawnPoint = self.GetAvailableVehicleSpawnPoint(config.SpawnPoints) + + if foundSpawn then + + ESX.Game.SpawnVehicle(data.current.model, spawnPoint.coords, spawnPoint.heading, function(vehicle) + + local props = ESX.Game.GetVehicleProperties(vehicle) + props.plate = exports['esx_vehicleshop']:GeneratePlate() -- TODO Should be in core + + SetVehicleNumberPlateText(vehicle, props.plate) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + + TriggerServerEvent('esx_policejob:buyJobVehicle', props, data.current.type) + + ESX.ShowNotification(_U('job_police:vehicleshop_bought', data.current.name, ESX.Math.GroupDigits(data.current.price))) + + end) + + end + + else + ESX.ShowNotification(_U('job_police:vehicleshop_money')) + menu2.close() + end + + end, data.current.model, data.current.type) + + end + + end, function(data2, menu2) + menu2.close() + end) + + end) + +end + +self.DeleteSpawnedVehicles = function() + + for i=1, #self.SpawnedVehicles, 1 do + ESX.Game.DeleteVehicle(self.SpawnedVehicles[i]) + end + + self.SpawnedVehicles = {} + +end + +self.WaitForVehicleToLoad = function(modelHash) + + modelHash = (type(modelHash) == 'number' and modelHash or GetHashKey(modelHash)) + + if not HasModelLoaded(modelHash) then + RequestModel(modelHash) + + BeginTextCommandBusyspinnerOn('STRING') + AddTextComponentSubstringPlayerName(_U('vehicleshop_awaiting_model')) + EndTextCommandBusyspinnerOn(4) + + while not HasModelLoaded(modelHash) do + Citizen.Wait(0) + DisableAllControlActions(0) + end + + BusyspinnerOff() + end +end diff --git a/modules/job_police/data/config.lua b/modules/job_police/data/config.lua new file mode 100644 index 00000000..b039d9b1 --- /dev/null +++ b/modules/job_police/data/config.lua @@ -0,0 +1,319 @@ +Config = {} + +Config.DrawDistance = 100.0 +Config.MarkerType = 1 +Config.MarkerSize = {x = 1.5, y = 1.5, z = 0.5} +Config.MarkerColor = {r = 50, g = 50, b = 204, a = 100} + +Config.EnablePlayerManagement = false +Config.EnableArmoryManagement = false +Config.EnableESXIdentity = false -- enable if you're using esx_identity +Config.EnableLicenses = false -- enable if you're using esx_license + +Config.EnableHandcuffTimer = true -- enable handcuff timer? will unrestrain player after the time ends +Config.HandcuffTimer = 10 * 60000 -- 10 mins + +Config.EnableJobBlip = false -- enable blips for cops on duty, requires esx_society +Config.EnableCustomPeds = false -- enable custom peds in cloak room? See Config.CustomPeds below to customize peds + +Config.EnableESXService = false -- enable esx service? +Config.MaxInService = 5 + +Config.Locale = 'fr' + +Config.PoliceStations = { + + LSPD = { + + Blip = { + Coords = vector3(425.1, -979.5, 30.7), + Sprite = 60, + Display = 4, + Scale = 1.2, + Colour = 29 + }, + + Cloakrooms = { + vector3(452.6, -992.8, 30.6) + }, + + Armories = { + vector3(451.7, -980.1, 30.6) + }, + + Vehicles = { + { + Spawner = vector3(454.6, -1017.4, 28.4), + InsideShop = vector3(228.5, -993.5, -99.5), + SpawnPoints = { + {coords = vector3(438.4, -1018.3, 27.7), heading = 90.0, radius = 6.0}, + {coords = vector3(441.0, -1024.2, 28.3), heading = 90.0, radius = 6.0}, + {coords = vector3(453.5, -1022.2, 28.0), heading = 90.0, radius = 6.0}, + {coords = vector3(450.9, -1016.5, 28.1), heading = 90.0, radius = 6.0} + } + }, + + { + Spawner = vector3(473.3, -1018.8, 28.0), + InsideShop = vector3(228.5, -993.5, -99.0), + SpawnPoints = { + {coords = vector3(475.9, -1021.6, 28.0), heading = 276.1, radius = 6.0}, + {coords = vector3(484.1, -1023.1, 27.5), heading = 302.5, radius = 6.0} + } + } + }, + + Helicopters = { + { + Spawner = vector3(461.1, -981.5, 43.6), + InsideShop = vector3(477.0, -1106.4, 43.0), + SpawnPoints = { + {coords = vector3(449.5, -981.2, 43.6), heading = 92.6, radius = 10.0} + } + } + }, + + BossActions = { + vector3(448.4, -973.2, 30.6) + } + + } + +} + +Config.AuthorizedWeapons = { + { -- recruit + {weapon = 'WEAPON_APPISTOL', components = {0, 0, 1000, 4000, nil}, price = 10000}, + {weapon = 'WEAPON_NIGHTSTICK', price = 0}, + {weapon = 'WEAPON_STUNGUN', price = 1500}, + {weapon = 'WEAPON_FLASHLIGHT', price = 80} + }, + + { -- officer + {weapon = 'WEAPON_ADVANCEDRIFLE', components = {0, 6000, 1000, 4000, 8000, nil}, price = 50000}, + }, + + { -- sergeant + {weapon = 'WEAPON_PUMPSHOTGUN', components = {2000, 6000, nil}, price = 70000}, + }, + + { -- lieutenant + }, + + { -- boss + } +} + +Config.AuthorizedVehicles = { + car = { + { -- recruit + + }, + + { -- officer + {model = 'police3', price = 20000} + }, + + { -- sergeant + {model = 'policet', price = 18500}, + {model = 'policeb', price = 30500} + }, + + { -- lieutenant + {model = 'riot', price = 70000}, + {model = 'fbi2', price = 60000} + }, + + { -- boss + + } + }, + + helicopter = { + + { -- recruit + + }, + + { -- officer + + }, + + {-- sergeant + + }, + + { -- lieutenant + {model = 'polmav', props = {modLivery = 0}, price = 200000} + }, + + { -- boss + {model = 'polmav', props = {modLivery = 0}, price = 100000} + } + } +} + +Config.CustomPeds = { + shared = { + {label = 'Sheriff Ped', maleModel = 's_m_y_sheriff_01', femaleModel = 's_f_y_sheriff_01'}, + {label = 'Police Ped', maleModel = 's_m_y_cop_01', femaleModel = 's_f_y_cop_01'} + }, + + recruit = {}, + + officer = {}, + + sergeant = {}, + + lieutenant = {}, + + boss = { + {label = 'SWAT Ped', maleModel = 's_m_y_swat_01', femaleModel = 's_m_y_swat_01'} + } +} + +-- CHECK SKINCHANGER CLIENT MAIN.LUA for matching elements +Config.Uniforms = { + recruit = { + male = { + tshirt_1 = 59, tshirt_2 = 1, + torso_1 = 55, torso_2 = 0, + decals_1 = 0, decals_2 = 0, + arms = 41, + pants_1 = 25, pants_2 = 0, + shoes_1 = 25, shoes_2 = 0, + helmet_1 = 46, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + }, + female = { + tshirt_1 = 36, tshirt_2 = 1, + torso_1 = 48, torso_2 = 0, + decals_1 = 0, decals_2 = 0, + arms = 44, + pants_1 = 34, pants_2 = 0, + shoes_1 = 27, shoes_2 = 0, + helmet_1 = 45, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + } + }, + + officer = { + male = { + tshirt_1 = 58, tshirt_2 = 0, + torso_1 = 55, torso_2 = 0, + decals_1 = 0, decals_2 = 0, + arms = 41, + pants_1 = 25, pants_2 = 0, + shoes_1 = 25, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + }, + female = { + tshirt_1 = 35, tshirt_2 = 0, + torso_1 = 48, torso_2 = 0, + decals_1 = 0, decals_2 = 0, + arms = 44, + pants_1 = 34, pants_2 = 0, + shoes_1 = 27, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + } + }, + + sergeant = { + male = { + tshirt_1 = 58, tshirt_2 = 0, + torso_1 = 55, torso_2 = 0, + decals_1 = 8, decals_2 = 1, + arms = 41, + pants_1 = 25, pants_2 = 0, + shoes_1 = 25, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + }, + female = { + tshirt_1 = 35, tshirt_2 = 0, + torso_1 = 48, torso_2 = 0, + decals_1 = 7, decals_2 = 1, + arms = 44, + pants_1 = 34, pants_2 = 0, + shoes_1 = 27, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + } + }, + + lieutenant = { + male = { + tshirt_1 = 58, tshirt_2 = 0, + torso_1 = 55, torso_2 = 0, + decals_1 = 8, decals_2 = 2, + arms = 41, + pants_1 = 25, pants_2 = 0, + shoes_1 = 25, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + }, + female = { + tshirt_1 = 35, tshirt_2 = 0, + torso_1 = 48, torso_2 = 0, + decals_1 = 7, decals_2 = 2, + arms = 44, + pants_1 = 34, pants_2 = 0, + shoes_1 = 27, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + } + }, + + boss = { + male = { + tshirt_1 = 58, tshirt_2 = 0, + torso_1 = 55, torso_2 = 0, + decals_1 = 8, decals_2 = 3, + arms = 41, + pants_1 = 25, pants_2 = 0, + shoes_1 = 25, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + }, + female = { + tshirt_1 = 35, tshirt_2 = 0, + torso_1 = 48, torso_2 = 0, + decals_1 = 7, decals_2 = 3, + arms = 44, + pants_1 = 34, pants_2 = 0, + shoes_1 = 27, shoes_2 = 0, + helmet_1 = -1, helmet_2 = 0, + chain_1 = 0, chain_2 = 0, + ears_1 = 2, ears_2 = 0 + } + }, + + bullet_wear = { + male = { + bproof_1 = 11, bproof_2 = 1 + }, + female = { + bproof_1 = 13, bproof_2 = 1 + } + }, + + gilet_wear = { + male = { + tshirt_1 = 59, tshirt_2 = 1 + }, + female = { + tshirt_1 = 36, tshirt_2 = 1 + } + } +} diff --git a/modules/job_police/data/locales/br.lua b/modules/job_police/data/locales/br.lua new file mode 100644 index 00000000..9423af49 --- /dev/null +++ b/modules/job_police/data/locales/br.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloackroom + ['cloakroom'] = 'Vestiário', + ['citizen_wear'] = 'Roupa casual', + ['police_wear'] = 'Uniforme da Polícia', + ['gilet_wear'] = 'orange reflective jacket', + ['bullet_wear'] = 'bulletproof vest', + ['no_outfit'] = 'there\'s no uniform that fits you!', + ['open_cloackroom'] = 'Pressione ~INPUT_CONTEXT~ para se trocar', + -- Armory + ['remove_object'] = 'take object', + ['deposit_object'] = 'deposit object', + ['get_weapon'] = 'Pegar arma', + ['put_weapon'] = 'Entregar arma', + ['buy_weapons'] = 'Comprar armas', + ['armory'] = 'Arsenal', + ['open_armory'] = 'Pressione ~INPUT_CONTEXT~ para acessar o arsenal', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~g~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'you cannot enter service, max officers in service: %s/%s', + ['service_not'] = 'you have not entered service! You\'ll have to get changed first.', + ['service_anonunce'] = 'service information', + ['service_in'] = 'you\'ve entered service, welcome!', + ['service_in_announce'] = 'operator ~y~%s~s~ has entered service!', + ['service_out'] = 'you have left service.', + ['service_out_announce'] = 'operator ~y~%s~s~ has left their service.', + -- Action Menu + ['citizen_interaction'] = 'Interagir com o cidadão', + ['vehicle_interaction'] = 'Interagir com o veículo', + ['object_spawner'] = 'Interagir com as rodovias', + + ['id_card'] = 'Carteira de identidade', + ['search'] = 'Procurar', + ['handcuff'] = 'Algemar / Soltar', + ['drag'] = 'drag', + ['put_in_vehicle'] = 'Colocar no veículo', + ['out_the_vehicle'] = 'take out of vehicle', + ['fine'] = 'Multa', + ['unpaid_bills'] = 'manage unpaid bills', + ['license_check'] = 'manage license', + ['license_revoke'] = 'revoke license', + ['license_revoked'] = 'your ~b~%s~s~ has been ~y~revoked~s~!', + ['licence_you_revoked'] = 'you revoked a ~b~%s~s~ which belonged to ~y~%s~s~', + ['no_players_nearby'] = 'nenhum jogador nas proximidades', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'Informações', + ['pick_lock'] = 'Trancar veículo', + ['vehicle_unlocked'] = 'Veículo ~g~destravado~s~', + ['no_vehicles_nearby'] = 'Nenhum veículo nas proximidades', + ['impound'] = 'apreender carro', + ['impound_prompt'] = 'Pressione ~INPUT_CONTEXT~ para cancelar a ~y~apreender~s~', + ['impound_canceled'] = 'you canceled the impound', + ['impound_canceled_moved'] = 'o apreender foi cancelado porque o veículo mudou', + ['impound_successful'] = 'você apreendeu o veículo', + ['search_database'] = 'informação do veículo', + ['search_database_title'] = 'informações do veículo - pesquisa com número de registro', + ['search_database_error_invalid'] = 'que ~r~não~s~ é um número de registro ~y~válido~s~', + -- Traffic interaction + ['traffic_interaction'] = 'Interagir com as rodovias', + ['cone'] = 'Cones', + ['barrier'] = 'Barreira', + ['spikestrips'] = 'Fita de pregos', + ['box'] = 'Caixa', + ['cash'] = 'Caixa de dinheiro', + -- ID Card Menu + ['name'] = 'name: %s', + ['job'] = 'job: %s', + ['sex'] = 'sex: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'height: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'unknown', + ['male'] = 'male', + ['female'] = 'female', + -- Body Search Menu + ['guns_label'] = '--- Armas ---', + ['inventory_label'] = '--- Inventário ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'confiscar %s', + ['confiscate_weapon'] = 'confiscate %s with %s bullets', + ['confiscate_inv'] = 'Confiscar %sx %s', + ['confiscate_dirty'] = 'Confiscar dinheiro sujo: $%s', + ['you_confiscated'] = 'you confiscated ~y~%sx~s~ ~b~%s~s~ from ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ were confiscated by ~y~%s~s~', + ['you_confiscated_account'] = 'you confiscated ~g~$%s~s~ (%s) from ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) was confiscated by ~y~%s~s~', + ['you_confiscated_weapon'] = 'you confiscated ~b~%s~s~ from ~b~%s~s~ with ~o~%s~s~ bullets', + ['got_confiscated_weapon'] = 'your ~b~%s~s~ with ~o~%s~s~ bullets was confiscated by ~y~%s~s~', + ['traffic_offense'] = 'Infrações de transito', + ['minor_offense'] = 'Infração leve', + ['average_offense'] = 'Infração média', + ['major_offense'] = 'Infração grave', + ['fine_total'] = 'multa: %s', + -- Vehicle Info Menu + ['plate'] = 'placa: %s', + ['owner_unknown'] = 'proprietário: Desconhecido', + ['owner'] = 'proprietário: %s', + -- Boss Menu + ['open_bossmenu'] = 'Pressione ~INPUT_CONTEXT~ para abrir o menu', + ['quantity_invalid'] = 'invalid quantity', + ['have_withdrawn'] = 'you have withdrawn ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'you have deposited ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'quantity', + ['inventory'] = 'inventory', + ['police_stock'] = 'police Stock', + -- Misc + ['remove_prop'] = 'Pressione ~INPUT_CONTEXT~ para remover o objeto', + ['map_blip'] = 'Departamento de Polícia', + ['unrestrained_timer'] = 'you feel your handcuffs slowly losing grip and fading away.', + -- Notifications + ['alert_police'] = 'Alerta da Polícia', + ['phone_police'] = 'police', +} diff --git a/modules/job_police/data/locales/cs.lua b/modules/job_police/data/locales/cs.lua new file mode 100644 index 00000000..aad0524c --- /dev/null +++ b/modules/job_police/data/locales/cs.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'satna', + ['citizen_wear'] = 'civilní oblek', + ['police_wear'] = 'policejní oblek', + ['gilet_wear'] = 'oranžová reflexní vesta', + ['bullet_wear'] = 'neprůstřelná vesta', + ['no_outfit'] = 'není zde žádná uniforma, která by ti sedla!', + ['open_cloackroom'] = 'stiskni ~INPUT_CONTEXT~ pro změnu ~y~oblečení~s~.', + -- Armory + ['remove_object'] = 'vzít objekt', + ['deposit_object'] = 'odevzdat objekt', + ['get_weapon'] = 'vzít zbraň ze zbrojnice', + ['put_weapon'] = 'uchovat zbraň ve zbrojnici', + ['buy_weapons'] = 'koupit zbraně', + ['armory'] = 'zbrojnice', + ['open_armory'] = 'stiskni ~INPUT_CONTEXT~ pro přístup do ~y~zbrojnice~s~.', + ['armory_owned'] = 'vlastněno', + ['armory_free'] = 'zdarma', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'zbrojnice', + ['armory_componenttitle'] = 'zbrojnice - Příslušenství ke zbraním', + ['armory_bought'] = 'zakoupil jsi ~y~%s~s~ za ~g~$%s~s~', + ['armory_money'] = 'nemáš dostatek peněz na tuto zbraň', + ['armory_hascomponent'] = 'toto příslušenství máš již nainstalováno!', + ['get_weapon_menu'] = 'zbrojnice - Vzít zbraň', + ['put_weapon_menu'] = 'zbrojnice - Uchovat zbraň', + -- Vehicles + ['vehicle_menu'] = 'vozidlo', + ['vehicle_blocked'] = 'vsechny dostupne spawn pointy jsou blokovany!', + ['garage_prompt'] = 'stiskni ~INPUT_CONTEXT~ pro otevreni ~y~akce vozidel~s~.', + ['garage_title'] = 'akce vozidel', + ['garage_stored'] = 'uloženo', + ['garage_notstored'] = 'není v garáži', + ['garage_storing'] = 'pokousime se o odstraneni vozidla, ujisti se, ze kolem nej nejsou hraci.', + ['garage_has_stored'] = 'vozidlo bylo ulozeno do garaze', + ['garage_has_notstored'] = 'zadne nejblizsi vlastnene vozidlo nenalezeno', + ['garage_notavailable'] = 'tvoje vozidlo neni ulozeno v garazi.', + ['garage_blocked'] = 'nejsou zde zadne spawn pointy!', + ['garage_empty'] = 'zadne vozidlo nemas v garazi.', + ['garage_released'] = 'tvoje vozidlo bylo vyjmuto z garaze.', + ['garage_store_nearby'] = 'nejsou poblíž zádná vozidla.', + ['garage_storeditem'] = 'otevřít garáž', + ['garage_storeitem'] = 'uchovat vozidlo v garáži', + ['garage_buyitem'] = 'prodej vozidel', + ['garage_notauthorized'] = 'nemas opravneni ke koupi tohoto vozidla.', + ['helicopter_prompt'] = 'stiskni ~INPUT_CONTEXT~ pro pristup k ~y~akcim Helikopter~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'prodejce vozidel', + ['vehicleshop_confirm'] = 'opravdu chces koupit toto vozidlo?', + ['vehicleshop_bought'] = 'koupil jsi ~y~%s~s~ za ~r~$%s~s~', + ['vehicleshop_money'] = 'toto vozidlo si nemuzete dovolit', + ['vehicleshop_awaiting_model'] = 'vozidlo se prave ~g~stahuje a nacita~s~ prosim pockej', + ['confirm_no'] = 'ne', + ['confirm_yes'] = 'ano', + -- Service + ['service_max'] = 'nemuzete vstoupit do sluzby, max dustojníci v provozu: %s/%s', + ['service_not'] = 'nezadali jste sluzbu! Nejprve se musíte zmenit.', + ['service_anonunce'] = 'informace o sluzbe', + ['service_in'] = 'vstoupil jsi do sluzby, vitej!', + ['service_in_announce'] = 'operator ~y~%s~s~ se pripojil do sluzby!', + ['service_out'] = 'opustil jsi sluzbu.', + ['service_out_announce'] = 'operator ~y~%s~s~ opustil jejich sluzbu.', + -- Action Menu + ['citizen_interaction'] = 'Interakce s občanem', + ['vehicle_interaction'] = 'Interakce vozidla', + ['object_spawner'] = 'Objekty', + + ['id_card'] = 'Občanský průkaz', + ['search'] = 'prohledat', + ['handcuff'] = 'poutat / odpoutat', + ['drag'] = 'prenést', + ['put_in_vehicle'] = 'vlozit do vozidla', + ['out_the_vehicle'] = 'vytahnout z vozidla', + ['fine'] = 'pokuta', + ['unpaid_bills'] = 'spravovat nezaplacené pokuty', + ['license_check'] = 'spravovat průkazy', + ['license_revoke'] = 'zneplatnit průkaz', + ['license_revoked'] = 'vase ~b~%s~s~ bylo ~y~zruseno~s~!', + ['licence_you_revoked'] = 'zrusil jsi ~b~%s~s~ ktery patril ~y~%s~s~', + ['no_players_nearby'] = 'zadny hrac pobliz!', + ['being_searched'] = 'prave jsi ~y~prohledavan~s~ ~b~policii~s~', + -- Vehicle interaction + ['vehicle_info'] = 'informace o vozidle', + ['pick_lock'] = 'vypáčit vozidlo', + ['vehicle_unlocked'] = 'vozidlo je ~g~Odemčeno~s~', + ['no_vehicles_nearby'] = 'there is no vehicles nearby', + ['impound'] = 'odtahnout vozidlo', + ['impound_prompt'] = 'zmackni ~INPUT_CONTEXT~ pro zruseni ~y~odtahnuti~s~', + ['impound_canceled'] = 'zrusil jsi odtah', + ['impound_canceled_moved'] = 'odtah byl zrusen,protoze se vozidlo pohlo!', + ['impound_successful'] = 'uspesne jsi odtahl vozidlo', + ['search_database'] = 'informace o vozidle', + ['search_database_title'] = 'informace o vozidle - pomocí registracnich cisel', + ['search_database_error_invalid'] = 'tohle ~r~neni~s~ ~y~spravne~s~ registracni cislo', + -- Traffic interaction + ['traffic_interaction'] = 'interakce provozu', + ['cone'] = 'kuzel', + ['barrier'] = 'bariera', + ['spikestrips'] = 'ostnaty pas', + ['box'] = 'box', + ['cash'] = 'box penez', + -- ID Card Menu + ['name'] = 'jméno: %s', + ['job'] = 'práce: %s', + ['sex'] = 'pohlaví: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'výška: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'neznámé', + ['male'] = 'muž', + ['female'] = 'žena', + -- Body Search Menu + ['guns_label'] = '--- Zbraně ---', + ['inventory_label'] = '--- Inventář ---', + ['license_label'] = ' --- Průkazy ---', + ['confiscate'] = 'zabavit %s', + ['confiscate_weapon'] = 'zabavit %s s %s naboji', + ['confiscate_inv'] = 'zabavit %sx %s', + ['confiscate_dirty'] = 'zabavit spinave penize: $%s', + ['you_confiscated'] = 'zabavil jsi ~y~%sx~s~ ~b~%s~s~ od ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ byly zabaveny od ~y~%s~s~', + ['you_confiscated_account'] = 'zabavil jsi ~g~$%s~s~ (%s) od ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) byly zabaveny ~y~%s~s~', + ['you_confiscated_weapon'] = 'zabavil jsi ~b~%s~s~ od ~b~%s~s~ s ~o~%s~s~ naboji ', + ['got_confiscated_weapon'] = 'tvoje ~b~%s~s~ s ~o~%s~s~ bylo zabaveno od ~y~%s~s~', + ['traffic_offense'] = 'dopravní přestupek', + ['minor_offense'] = 'malý přestupek', + ['average_offense'] = 'přestupek', + ['major_offense'] = 'trestný čin', + ['fine_total'] = 'pokuta: %s', + -- Vehicle Info Menu + ['plate'] = 'SPZ: %s', + ['owner_unknown'] = 'vlastník: Neznámý', + ['owner'] = 'vlastník: %s', + -- Boss Menu + ['open_bossmenu'] = 'stiskni ~INPUT_CONTEXT~ pro otevření menu', + ['quantity_invalid'] = 'neplatné množství', + ['have_withdrawn'] = 'vybral jsi ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'vložil jsi ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'množství', + ['inventory'] = 'inventář', + ['police_stock'] = 'policejní sklad', + -- Misc + ['remove_prop'] = 'stiskni ~INPUT_CONTEXT~ pro odstranění předmětu', + ['map_blip'] = 'policejní stanice', + ['unrestrained_timer'] = 'cítíš, že tvé pouta pomalu ztrácejí přilnavost a padají.', + -- Notifications + ['alert_police'] = 'policejní poplach', + ['phone_police'] = 'policie', +} diff --git a/modules/job_police/data/locales/de.lua b/modules/job_police/data/locales/de.lua new file mode 100644 index 00000000..639fb1d7 --- /dev/null +++ b/modules/job_police/data/locales/de.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloackroom + ['cloakroom'] = 'Garderobe', + ['citizen_wear'] = 'Zivilkleidung', + ['police_wear'] = 'Arbeitskleidung', + ['gilet_wear'] = 'orange reflective jacket', + ['bullet_wear'] = 'bulletproof vest', + ['no_outfit'] = 'there\'s no uniform that fits you!', + ['open_cloackroom'] = 'Drücke ~INPUT_CONTEXT~ um dich umzuziehen', + -- Armory + ['remove_object'] = 'take object', + ['deposit_object'] = 'deposit object', + ['get_weapon'] = 'Waffen holen', + ['put_weapon'] = 'Waffen bringen', + ['buy_weapons'] = 'Waffen kaufen', + ['armory'] = 'Waffenkammer', + ['open_armory'] = 'Drücke ~INPUT_CONTEXT~ um die Waffenkammer zu öffnen', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~r~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'you cannot enter service, max officers in service: %s/%s', + ['service_not'] = 'you have not entered service! You\'ll have to get changed first.', + ['service_anonunce'] = 'service information', + ['service_in'] = 'you\'ve entered service, welcome!', + ['service_in_announce'] = 'operator ~y~%s~s~ has entered service!', + ['service_out'] = 'you have left service.', + ['service_out_announce'] = 'operator ~y~%s~s~ has left their service.', + -- Action Menu + ['citizen_interaction'] = 'Zivilistenaktionen', + ['vehicle_interaction'] = 'Fahrzeuginteraktionen', + ['object_spawner'] = 'Objekt Spawner', + + ['id_card'] = 'ID Karte', + ['search'] = 'Suche', + ['handcuff'] = 'Festnehmen / Freilassen', + ['drag'] = 'drag', + ['put_in_vehicle'] = 'In Fahrzeug setzen', + ['out_the_vehicle'] = 'take out of vehicle', + ['fine'] = 'Strafe', + ['unpaid_bills'] = 'manage unpaid bills', + ['license_check'] = 'manage license', + ['license_revoke'] = 'revoke license', + ['license_revoked'] = 'your ~b~%s~s~ has been ~y~revoked~s~!', + ['licence_you_revoked'] = 'you revoked a ~b~%s~s~ which belonged to ~y~%s~s~', + ['no_players_nearby'] = 'keine Spieler in der Nähe', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'Fahrzeug Info', + ['pick_lock'] = 'Fahrzeug öffnen', + ['vehicle_unlocked'] = 'Fahrzeug ~g~offen~s~', + ['no_vehicles_nearby'] = 'Keine Fahrzeuge in der Nähe', + ['impound'] = 'impound vehicle', + ['impound_prompt'] = 'press ~INPUT_CONTEXT~ to cancel the ~y~impound~s~', + ['impound_canceled'] = 'you canceled the impound', + ['impound_canceled_moved'] = 'the impound has been canceled because the vehicle moved', + ['impound_successful'] = 'you have impounded the vehicle', + ['search_database'] = 'vehicle information', + ['search_database_title'] = 'vehicle information - search with registration number', + ['search_database_error_invalid'] = 'that is ~r~not~s~ a ~y~valid~s~ registration number', + -- Traffic interaction + ['traffic_interaction'] = 'Straßeninteraktionen', + ['cone'] = 'Hütchen', + ['barrier'] = 'Barriere', + ['spikestrips'] = 'Nagelband', + ['box'] = 'Box', + ['cash'] = 'Box mit Geld', + -- ID Card Menu + ['name'] = 'name: %s', + ['job'] = 'job: %s', + ['sex'] = 'sex: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'height: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'unknown', + ['male'] = 'male', + ['female'] = 'female', + -- Body Search Menu + ['guns_label'] = '--- Waffen ---', + ['inventory_label'] = '--- Inventar ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'konfeszieren %s', + ['confiscate_weapon'] = 'confiscate %s with %s bullets', + ['confiscate_inv'] = 'konfeziere %sx %s', + ['confiscate_dirty'] = 'schwarzgeld konfesziert: $%s', + ['you_confiscated'] = 'you confiscated ~y~%sx~s~ ~b~%s~s~ from ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ were confiscated by ~y~%s~s~', + ['you_confiscated_account'] = 'you confiscated ~g~$%s~s~ (%s) from ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) was confiscated by ~y~%s~s~', + ['you_confiscated_weapon'] = 'you confiscated ~b~%s~s~ from ~b~%s~s~ with ~o~%s~s~ bullets', + ['got_confiscated_weapon'] = 'your ~b~%s~s~ with ~o~%s~s~ bullets was confiscated by ~y~%s~s~', + ['traffic_offense'] = 'Verkehrs vergehen', + ['minor_offense'] = 'Geringes vergehen', + ['average_offense'] = 'Normales vergehen', + ['major_offense'] = 'Hohes vergehen', + ['fine_total'] = 'strafe: %s', + -- Vehicle Info Menu + ['plate'] = 'plate: %s', + ['owner_unknown'] = 'besitzer: Unbekannt', + ['owner'] = 'besitzer: %s', + -- Boss Menu + ['open_bossmenu'] = 'Drücke ~INPUT_CONTEXT~ um das Menü zu öffnen', + ['quantity_invalid'] = 'invalid quantity', + ['have_withdrawn'] = 'you have withdrawn ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'you have deposited ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'quantity', + ['inventory'] = 'inventory', + ['police_stock'] = 'police Stock', + -- Misc + ['remove_prop'] = 'Drücke ~INPUT_CONTEXT~ um das Objekt zu entfernen', + ['map_blip'] = 'Polizeistation', + ['unrestrained_timer'] = 'you feel your handcuffs slowly losing grip and fading away.', + -- Notifications + ['alert_police'] = 'Polizei alamieren', + ['phone_police'] = 'police', +} diff --git a/modules/job_police/data/locales/en.lua b/modules/job_police/data/locales/en.lua new file mode 100644 index 00000000..c230c8bc --- /dev/null +++ b/modules/job_police/data/locales/en.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'locker room', + ['citizen_wear'] = 'civilian Outfit', + ['police_wear'] = 'police Outfit', + ['gilet_wear'] = 'orange reflective jacket', + ['bullet_wear'] = 'bulletproof vest', + ['no_outfit'] = 'there\'s no uniform that fits you!', + ['open_cloackroom'] = 'press ~INPUT_CONTEXT~ to change ~y~clothes~s~.', + -- Armory + ['remove_object'] = 'withdraw object', + ['deposit_object'] = 'deposit object', + ['get_weapon'] = 'withdraw weapon from armory', + ['put_weapon'] = 'store weapon in armory', + ['buy_weapons'] = 'buy weapons', + ['armory'] = 'armory', + ['open_armory'] = 'press ~INPUT_CONTEXT~ to access the ~y~Armory~s~.', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~r~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'you cannot enter service, max officers in service: %s/%s', + ['service_not'] = 'you have not entered service! You\'ll have to get changed first.', + ['service_anonunce'] = 'service information', + ['service_in'] = 'you\'ve entered service, welcome!', + ['service_in_announce'] = 'operator ~y~%s~s~ has entered service!', + ['service_out'] = 'you have left service.', + ['service_out_announce'] = 'operator ~y~%s~s~ has left their service.', + -- Action Menu + ['citizen_interaction'] = 'citizen Interaction', + ['vehicle_interaction'] = 'vehicle Interaction', + ['object_spawner'] = 'object Spawner', + + ['id_card'] = 'ID Card', + ['search'] = 'search', + ['handcuff'] = 'cuff / Uncuff', + ['drag'] = 'escort', + ['put_in_vehicle'] = 'put in Vehicle', + ['out_the_vehicle'] = 'drag out from vehicle', + ['fine'] = 'fine', + ['unpaid_bills'] = 'manage unpaid bills', + ['license_check'] = 'manage license', + ['license_revoke'] = 'revoke license', + ['license_revoked'] = 'your ~b~%s~s~ has been ~y~revoked~s~!', + ['licence_you_revoked'] = 'you revoked a ~b~%s~s~ which belonged to ~y~%s~s~', + ['no_players_nearby'] = 'there is no player(s) nearby!', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'vehicle Info', + ['pick_lock'] = 'lockpick Vehicle', + ['vehicle_unlocked'] = 'vehicle ~g~Unlocked~s~', + ['no_vehicles_nearby'] = 'there is no vehicles nearby', + ['impound'] = 'impound vehicle', + ['impound_prompt'] = 'press ~INPUT_CONTEXT~ to cancel the ~y~impound~s~', + ['impound_canceled'] = 'you canceled the impound', + ['impound_canceled_moved'] = 'the impound has been canceled because the vehicle moved', + ['impound_successful'] = 'you have impounded the vehicle', + ['search_database'] = 'vehicle information', + ['search_database_title'] = 'vehicle information - search with registration number', + ['search_database_error_invalid'] = 'that is ~r~not~s~ a ~y~valid~s~ registration number', + -- Traffic interaction + ['traffic_interaction'] = 'interaction Traffic', + ['cone'] = 'cone', + ['barrier'] = 'barrier', + ['spikestrips'] = 'spikestrips', + ['box'] = 'box', + ['cash'] = 'box of cash', + -- ID Card Menu + ['name'] = 'name: %s', + ['job'] = 'job: %s', + ['sex'] = 'sex: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'height: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'unknown', + ['male'] = 'male', + ['female'] = 'female', + -- Body Search Menu + ['guns_label'] = '--- Guns ---', + ['inventory_label'] = '--- Inventory ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'confiscate %s', + ['confiscate_weapon'] = 'confiscate %s with %s bullets', + ['confiscate_inv'] = 'confiscate %sx %s', + ['confiscate_dirty'] = 'confiscate dirty money: $%s', + ['you_confiscated'] = 'you confiscated ~y~%sx~s~ ~b~%s~s~ from ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ were confiscated by ~y~%s~s~', + ['you_confiscated_account'] = 'you confiscated ~g~$%s~s~ (%s) from ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) was confiscated by ~y~%s~s~', + ['you_confiscated_weapon'] = 'you confiscated ~b~%s~s~ from ~b~%s~s~ with ~o~%s~s~ bullets', + ['got_confiscated_weapon'] = 'your ~b~%s~s~ with ~o~%s~s~ bullets was confiscated by ~y~%s~s~', + ['traffic_offense'] = 'traffic Offense', + ['minor_offense'] = 'minor Offense', + ['average_offense'] = 'average Offense', + ['major_offense'] = 'major Offense', + ['fine_total'] = 'fine: %s', + -- Vehicle Info Menu + ['plate'] = 'plate: %s', + ['owner_unknown'] = 'owner: Unknown', + ['owner'] = 'owner: %s', + -- Boss Menu + ['open_bossmenu'] = 'press ~INPUT_CONTEXT~ to open the menu', + ['quantity_invalid'] = 'invalid quantity', + ['have_withdrawn'] = 'you have withdrawn ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'you have deposited ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'quantity', + ['inventory'] = 'inventory', + ['police_stock'] = 'police Stock', + -- Misc + ['remove_prop'] = 'press ~INPUT_CONTEXT~ to delete the object', + ['map_blip'] = 'police Station', + ['unrestrained_timer'] = 'you feel your handcuffs slowly losing grip and fading away.', + -- Notifications + ['alert_police'] = 'police alert', + ['phone_police'] = 'police', +} diff --git a/modules/job_police/data/locales/es.lua b/modules/job_police/data/locales/es.lua new file mode 100644 index 00000000..21a9af87 --- /dev/null +++ b/modules/job_police/data/locales/es.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'Taquilla', + ['citizen_wear'] = 'Ropa civil', + ['police_wear'] = 'Ropa CNP', + ['gilet_wear'] = 'orange reflective jacket', + ['bullet_wear'] = 'bulletproof vest', + ['no_outfit'] = 'there\'s no uniform that fits you!', + ['open_cloackroom'] = 'Presionar ~INPUT_CONTEXT~ para abrir la taquilla', + -- Armory + ['remove_object'] = 'take object', + ['deposit_object'] = 'deposit object', + ['get_weapon'] = 'Coger arma', + ['put_weapon'] = 'Depositar arma', + ['buy_weapons'] = 'Comprar armas', + ['armory'] = 'Arsenal', + ['open_armory'] = 'Presionarr ~INPUT_CONTEXT~ para acceder a la armeria', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~r~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'you cannot enter service, max officers in service: %s/%s', + ['service_not'] = 'you have not entered service! You\'ll have to get changed first.', + ['service_anonunce'] = 'service information', + ['service_in'] = 'you\'ve entered service, welcome!', + ['service_in_announce'] = 'operator ~y~%s~s~ has entered service!', + ['service_out'] = 'you have left service.', + ['service_out_announce'] = 'operator ~y~%s~s~ has left their service.', + -- Action Menu + ['citizen_interaction'] = 'Interacción ciudadana', + ['vehicle_interaction'] = 'Interacción vehículo', + ['object_spawner'] = 'Colocar objetos', + + ['id_card'] = 'Documento de identidad', + ['search'] = 'Buscar', + ['handcuff'] = 'Poner/quitar Esposas', + ['drag'] = 'escoltar', + ['put_in_vehicle'] = 'Meter en el vehículo', + ['out_the_vehicle'] = 'Sacar del vehículo', + ['fine'] = 'Multa', + ['unpaid_bills'] = 'manage unpaid bills', + ['license_check'] = 'manage license', + ['license_revoke'] = 'revoke license', + ['license_revoked'] = 'your ~b~%s~s~ has been ~y~revoked~s~!', + ['licence_you_revoked'] = 'you revoked a ~b~%s~s~ which belonged to ~y~%s~s~', + ['no_players_nearby'] = 'no hay jugadores cerca', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'Información del vehículo', + ['pick_lock'] = 'Forzar coche', + ['vehicle_unlocked'] = 'Vehículo desbloqueado~s~', + ['no_vehicles_nearby'] = 'No hay vehículos cerca', + ['impound'] = 'impound vehicle', + ['impound_prompt'] = 'press ~INPUT_CONTEXT~ to cancel the ~y~impound~s~', + ['impound_canceled'] = 'you canceled the impound', + ['impound_canceled_moved'] = 'the impound has been canceled because the vehicle moved', + ['impound_successful'] = 'you have impounded the vehicle', + ['search_database'] = 'vehicle information', + ['search_database_title'] = 'vehicle information - search with registration number', + ['search_database_error_invalid'] = 'that is ~r~not~s~ a ~y~valid~s~ registration number', + -- Traffic interaction + ['traffic_interaction'] = 'Rutas de interacción', + ['cone'] = 'Cono', + ['barrier'] = 'Barrera', + ['spikestrips'] = 'Grada', + ['box'] = 'Caja', + ['cash'] = 'Dinero', + -- ID Card Menu + ['name'] = 'name: %s', + ['job'] = 'job: %s', + ['sex'] = 'sex: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'height: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'unknown', + ['male'] = 'male', + ['female'] = 'female', + -- Body Search Menu + ['guns_label'] = '--- Armas ---', + ['inventory_label'] = '--- Inventario ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'confiscar %s', + ['confiscate_weapon'] = 'confiscate %s with %s bullets', + ['confiscate_inv'] = 'confiscar %sx %s', + ['confiscate_dirty'] = 'confiscar dinero negro: €%s', + ['you_confiscated'] = 'you confiscated ~y~%sx~s~ ~b~%s~s~ from ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ were confiscated by ~y~%s~s~', + ['you_confiscated_account'] = 'you confiscated ~g~€%s~s~ (%s) from ~b~%s~s~', + ['got_confiscated_account'] = '~g~€%s~s~ (%s) was confiscated by ~y~%s~s~', + ['you_confiscated_weapon'] = 'you confiscated ~b~%s~s~ from ~b~%s~s~ with ~o~%s~s~ bullets', + ['got_confiscated_weapon'] = 'your ~b~%s~s~ with ~o~%s~s~ bullets was confiscated by ~y~%s~s~', + ['traffic_offense'] = 'Delito de tráfico', + ['minor_offense'] = 'Delito menor', + ['average_offense'] = 'Delito medio', + ['major_offense'] = 'Delito grave', + ['fine_total'] = 'Multa total: %s', + -- Vehicle Info Menu + ['plate'] = 'n°: %s', + ['owner_unknown'] = 'propietario: Desconocido', + ['owner'] = 'propietario: %s', + -- Boss Menu + ['open_bossmenu'] = 'presionar ~INPUT_CONTEXT~ para abrir el menú', + ['quantity_invalid'] = 'cantidad invalida', + ['have_withdrawn'] = 'you have withdrawn ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'you have deposited ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'cantidad', + ['inventory'] = 'inventario', + ['police_stock'] = 'almacen Policial', + -- Misc + ['remove_prop'] = 'presionar ~INPUT_CONTEXT~ para eliminar el objeto', + ['map_blip'] = 'comisaría de policía', + ['unrestrained_timer'] = 'you feel your handcuffs slowly losing grip and fading away.', + -- Notifications + ['alert_police'] = 'alerta policia', + ['phone_police'] = 'policia', +} diff --git a/modules/job_police/data/locales/fi.lua b/modules/job_police/data/locales/fi.lua new file mode 100644 index 00000000..732f1db7 --- /dev/null +++ b/modules/job_police/data/locales/fi.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'vaatelokero', + ['citizen_wear'] = 'siviiliasu', + ['police_wear'] = 'poliisiasu', + ['gilet_wear'] = 'huomioliivi', + ['bullet_wear'] = 'luotiliivi', + ['no_outfit'] = 'täällä ei ole sinulle sopivaa asua', + ['open_cloackroom'] = 'paina ~INPUT_CONTEXT~ vaihtaaksesi ~y~vaatteita~s~.', + -- Armory + ['remove_object'] = 'ota esine', + ['deposit_object'] = 'talleta esine', + ['get_weapon'] = 'ota ase', + ['put_weapon'] = 'laita ase pois', + ['buy_weapons'] = 'osta aseita', + ['armory'] = 'asevarasto', + ['open_armory'] = 'paina ~INPUT_CONTEXT~ avataksesi asevarasto', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~r~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'you cannot enter service, max officers in service: %s/%s', + ['service_not'] = 'you have not entered service! You\'ll have to get changed first.', + ['service_anonunce'] = 'service information', + ['service_in'] = 'you\'ve entered service, welcome!', + ['service_in_announce'] = 'operator ~y~%s~s~ has entered service!', + ['service_out'] = 'you have left service.', + ['service_out_announce'] = 'operator ~y~%s~s~ has left their service.', + -- Action Menu + ['citizen_interaction'] = 'siviilin vuorovaikutus', + ['vehicle_interaction'] = 'ajoneuvon vuorovaikutus', + ['object_spawner'] = 'objekti spawneri', + + ['id_card'] = 'henkilöllisyystodistus', + ['search'] = 'tutki', + ['handcuff'] = 'raudat On/Off', + ['drag'] = 'raahaa', + ['put_in_vehicle'] = 'laita ajoneuvoon', + ['out_the_vehicle'] = 'ota ulos ajoneuvosta', + ['fine'] = 'sakko', + ['unpaid_bills'] = 'hallinoi maksamattomia laskuja', + ['license_check'] = 'hallitse lisenssejä', + ['license_revoke'] = 'kumoa lisenssi', + ['license_revoked'] = 'sinun ~b~%s~s~ ~y~kumottiin~s~!', + ['licence_you_revoked'] = 'sinä kumosit ~b~%s~s~ mikä kuului henkilölle ~y~%s~s~', + ['no_players_nearby'] = 'ei pelaajia lähettyvillä', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'ajoneuvon tiedot', + ['pick_lock'] = 'tiirikoi ovet', + ['vehicle_unlocked'] = 'ajoneuvo ~g~Avattu~s~', + ['no_vehicles_nearby'] = 'ei ajoneuvoja lähettyvillä', + ['impound'] = 'takavarikoi ajoneuvo', + ['impound_prompt'] = 'paina ~INPUT_CONTEXT~ peruaksesi ~y~takavarikointi~s~', + ['impound_canceled'] = 'sinä peruit takavarikoinnin', + ['impound_canceled_moved'] = 'takavarikointi peruuntui koska ajoneuvo liikku', + ['impound_successful'] = 'takavarikoit ajoneuvon', + ['search_database'] = 'ajoneuvon tiedot', + ['search_database_title'] = 'ajoneuvon tiedot - etsi rekisterinumerolla', + ['search_database_error_invalid'] = 'tämä ~r~ei ole~s~ ~y~voimassa oleva~s~ rekisterinumero', + -- Traffic interaction + ['traffic_interaction'] = 'liikenteen vuorovaikutus', + ['cone'] = 'kartio', + ['barrier'] = 'este', + ['spikestrips'] = 'piikkimatto', + ['box'] = 'laatikko', + ['cash'] = 'rahalaatikko', + -- ID Card Menu + ['name'] = 'nimi: %s', + ['job'] = 'työ: %s', + ['sex'] = 'sukupuoli: %s', + ['dob'] = 'syntymäaika: %s', + ['height'] = 'pituus: %s', + ['bac'] = 'alkometri: %s', + ['unknown'] = 'tuntematon', + ['male'] = 'mies', + ['female'] = 'nainen', + -- Body Search Menu + ['guns_label'] = '--- Aseet ---', + ['inventory_label'] = '--- Reppu ---', + ['license_label'] = ' --- Lisenssit ---', + ['confiscate'] = 'takavarikoi %s', + ['confiscate_weapon'] = 'confiscate %s with %s bullets', + ['confiscate_inv'] = 'takavarikoi %sx %s', + ['confiscate_dirty'] = 'takavarikoi likainen raha: $%s', + ['you_confiscated'] = 'sinä takavarioit ~y~%sx~s~ ~b~%s~s~ pelaajalta ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ takavarikoitiin sinulta pelaajan ~y~%s~s~ toimesta', + ['you_confiscated_account'] = 'sinä takavarikoit ~g~$%s~s~ (%s) pelaajalta ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) takavarikoitiin sinulta pelaajan ~y~%s~s~ toimesta', + ['you_confiscated_weapon'] = 'sinä takavarikoit ~b~%s~s~ pelaajalta ~b~%s~s~ jossa oli ~o~%s~s~ panosta', + ['got_confiscated_weapon'] = 'sinun ~b~%s~s~ jossa oli ~o~%s~s~ panosta takavarikoitiin sinulta~y~%s~s~', + ['traffic_offense'] = 'liikenne rikokset', + ['minor_offense'] = 'lievät rikokset', + ['average_offense'] = 'keskisuuret rikokset', + ['major_offense'] = 'vakavat rikokset', + ['fine_total'] = 'sakko: %s', + --Vehicle Info Menu + ['plate'] = 'kilpi: %s', + ['owner_unknown'] = 'omistaja: Tuntematon', + ['owner'] = 'omistaja: %s', + --Boss Menu + ['open_bossmenu'] = 'paina ~INPUT_CONTEXT~ avataksesi valikon', + ['quantity_invalid'] = 'invalid quantity', + ['have_withdrawn'] = 'sinä otit varastosta ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'sinä talletit varastoon ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'määrä', + ['inventory'] = 'varasto', + ['police_stock'] = 'poliisin Varasto', + -- Misc + ['remove_prop'] = 'paina ~INPUT_CONTEXT~ poistaaksesi objektin', + ['map_blip'] = 'poliisilaitos', + ['unrestrained_timer'] = 'tunnet kuinka hitaasti käsiraudat alkavat löystyä ja irtoavat', + -- Notifications + ['alert_police'] = 'hälyytys Poliisi', + ['phone_police'] = 'poliisi', +} diff --git a/modules/job_police/data/locales/fr.lua b/modules/job_police/data/locales/fr.lua new file mode 100644 index 00000000..42ea497e --- /dev/null +++ b/modules/job_police/data/locales/fr.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'vestiaire', + ['citizen_wear'] = 'tenue Civil', + ['police_wear'] = 'tenue Policier', + ['gilet_wear'] = 'gilet orange', + ['bullet_wear'] = 'gilet pare-balles', + ['no_outfit'] = 'il n\'y a pas d\'uniforme à votre taille...', + ['open_cloackroom'] = 'appuyez sur ~INPUT_CONTEXT~ pour vous changer', + -- Armory + ['remove_object'] = 'prendre Objet', + ['deposit_object'] = 'déposer objet', + ['get_weapon'] = 'prendre Arme', + ['put_weapon'] = 'déposer Arme', + ['buy_weapons'] = 'acheter Armes', + ['armory'] = 'armurerie', + ['open_armory'] = 'appuyez sur ~INPUT_CONTEXT~ pour accéder à l\'armurerie', + ['armory_owned'] = 'possédé', + ['armory_free'] = 'gratuit', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armurerie - Acheter une arme', + ['armory_componenttitle'] = 'armurerie - Accessoires d\'armes', + ['armory_bought'] = 'vous achetez un ~y~%s~s~ pour ~g~$%s~s~', + ['armory_money'] = 'vous ne pouvez pas acheter cette arme', + ['armory_hascomponent'] = 'vous avez cet accessoire équipé!', + ['get_weapon_menu'] = 'armurerie - Retirer arme', + ['put_weapon_menu'] = 'armurerie - Stocker arme', + -- Vehicles + ['vehicle_menu'] = 'véhicule', + ['vehicle_blocked'] = 'tous les points de spawn sont bloqués!', + ['garage_prompt'] = 'appuyez sur ~INPUT_CONTEXT~ pour accéder aux ~y~Actions Véhicule~s~.', + ['garage_title'] = 'actions Véhicules', + ['garage_stored'] = 'rangé', + ['garage_notstored'] = 'sorti(e)', + ['garage_storing'] = 'tentative de suppression du véhicule, assurez-vous que personne ne soit autour.', + ['garage_has_stored'] = 'le véhicule a bien été rangé dans le garage', + ['garage_has_notstored'] = 'aucun véhicule dans le garage', + ['garage_notavailable'] = 'votre véhicule n\'est pas rangé dans le garage.', + ['garage_blocked'] = 'la sortie du garage est obstruée!', + ['garage_empty'] = 'vous n\'avez aucun véhicule dans le garage.', + ['garage_released'] = 'votre véhicule a été sorti.', + ['garage_store_nearby'] = 'aucun véhicule a proximité.', + ['garage_storeditem'] = 'ouvrir le garage', + ['garage_storeitem'] = 'ranger le véhicule', + ['garage_buyitem'] = 'magasin véhicule', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'appuyez sur ~INPUT_CONTEXT~ pour accéder aux ~y~Actions de l\'hélicoptère~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'magasin véhicule', + ['vehicleshop_confirm'] = 'voulez-vous acheter ce véhicule?', + ['vehicleshop_bought'] = 'vous avez acheté ~y~%s~s~ pour ~r~$%s~s~', + ['vehicleshop_money'] = 'vous ne pouvez pas acheter ce véhicule', + ['vehicleshop_awaiting_model'] = 'le véhicule est actuellement en ~g~PRÉPARATION~s~ veuillez patienter', + ['confirm_no'] = 'non', + ['confirm_yes'] = 'oui', + -- Service + ['service_max'] = 'vous ne pouvez pas entrer en service, officiers en service: %s/%s', + ['service_not'] = 'vous n\'êtes pas en service! Vous devez d\'abord enfiler votre tenue.', + ['service_anonunce'] = 'prise de service', + ['service_in'] = 'vous êtes en service, bon courage!', + ['service_in_announce'] = 'l\'officier ~y~%s~s~ est entré en service!', + ['service_out'] = 'vous avez terminé votre service.', + ['service_out_announce'] = 'l\'officier ~y~%s~s~ a quitté son service.', + -- Action Menu + ['citizen_interaction'] = 'interaction citoyen', + ['vehicle_interaction'] = 'interaction véhicule', + ['object_spawner'] = 'placer objets', + + ['id_card'] = 'carte d\'identité', + ['search'] = 'fouiller', + ['handcuff'] = 'menotter / Démenotter', + ['drag'] = 'escorter', + ['put_in_vehicle'] = 'mettre dans véhicule', + ['out_the_vehicle'] = 'sortir du véhicule', + ['fine'] = 'Amende', + ['unpaid_bills'] = 'gérer les amendes impayées', + ['license_check'] = 'gérer les licences', + ['license_revoke'] = 'révoquer la licence', + ['license_revoked'] = 'votre ~b~%s~s~ a été ~y~révoqué~s~!', + ['licence_you_revoked'] = 'vous avez révoqué un ~b~%s~s~ qui appartenait à ~y~%s~s~', + ['no_players_nearby'] = 'aucun joueur à proximité', + ['being_searched'] = 'vous êtes ~y~recherché(e)~s~ par la ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'infos véhicule', + ['pick_lock'] = 'crocheter véhicule', + ['vehicle_unlocked'] = 'véhicule ~g~déverouillé~s~', + ['no_vehicles_nearby'] = 'aucun véhicule à proximité', + ['impound'] = 'véhicule en fourrière', + ['impound_prompt'] = 'appuyez sur ~INPUT_CONTEXT~ pour annuler la ~y~saisie du véhicule~s~', + ['impound_canceled'] = 'vous avez annulé la saisie', + ['impound_canceled_moved'] = 'la saisie a été annulée parce que le véhicule a déménagé', + ['impound_successful'] = 'vous avez saisi le véhicule', + ['search_database'] = 'vehicle information', + ['search_database_title'] = 'informations sur le véhicule - recherche avec numéro d\'enregistrement', + ['search_database_error_invalid'] = 'Ce n\'est ~r~pas~s~ un ~y~numéro d\'enregistrement valide~s~', + -- Traffic interaction + ['traffic_interaction'] = 'interaction routière', + ['cone'] = 'plot', + ['barrier'] = 'barrière', + ['spikestrips'] = 'herse', + ['box'] = 'caisse', + ['cash'] = 'caisse', + -- ID Card Menu + ['name'] = 'nom: %s', + ['job'] = 'métier: %s', + ['sex'] = 'sexe: %s', + ['dob'] = 'DOB: %s', + ['height'] = 'taille: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'inconnu', + ['male'] = 'homme', + ['female'] = 'femme', + -- Body Search Menu + ['guns_label'] = '--- Armes ---', + ['inventory_label'] = '--- Inventaire ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'confisquer %s', + ['confiscate_weapon'] = 'confisqué %s avec %s balles', + ['confiscate_inv'] = 'confisquer %sx %s', + ['confiscate_dirty'] = 'confisquer argent sale: €%s', + ['you_confiscated'] = 'vous avez confisqué ~y~%sx~s~ ~b~%s~s~ à ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ ont été confisqués par ~y~%s~s~', + ['you_confiscated_account'] = 'vous avez confisqué ~g~$%s~s~ (%s) à ~b~%s~s~', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) ont été confisqués par ~y~%s~s~', + ['you_confiscated_weapon'] = 'vous avez confisqué ~b~%s~s~ à ~b~%s~s~ avec ~o~%s~s~ balles', + ['got_confiscated_weapon'] = 'votre ~b~%s~s~ avec ~o~%s~s~ balles a été confisqué par ~y~%s~s~', + ['traffic_offense'] = 'code de la route', + ['minor_offense'] = 'délit mineur', + ['average_offense'] = 'délit moyen', + ['major_offense'] = 'délit grave', + ['fine_total'] = 'amende: %s', + -- Vehicle Info Menu + ['plate'] = 'n°: %s', + ['owner_unknown'] = 'propriétaire: Inconnu', + ['owner'] = 'propriétaire: %s', + -- Boss Menu + ['open_bossmenu'] = 'appuyez sur ~INPUT_CONTEXT~ pour ouvrir le menu', + ['quantity_invalid'] = 'quantité invalide', + ['have_withdrawn'] = 'vous avez retiré ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'vous avez déposé ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'quantité', + ['inventory'] = 'inventaire', + ['police_stock'] = 'coffre de la police', + -- Misc + ['remove_prop'] = 'appuyez sur ~INPUT_CONTEXT~ pour enlever l\'objet', + ['map_blip'] = 'Commissariat', + ['unrestrained_timer'] = 'vous sentez que vos menottes deviennent fragiles.', + -- Notifications + ['alert_police'] = 'alerte police', + ['phone_police'] = 'police', +} diff --git a/modules/job_police/data/locales/ko.lua b/modules/job_police/data/locales/ko.lua new file mode 100644 index 00000000..29ef383d --- /dev/null +++ b/modules/job_police/data/locales/ko.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = '라커룸', + ['citizen_wear'] = '민간인 복장', + ['police_wear'] = '경찰 복장', + ['gilet_wear'] = '오렌지 반사 재킷', + ['bullet_wear'] = '방탄 조끼', + ['no_outfit'] = '당신에게 맞는 유니폼이 없습니다!', + ['open_cloackroom'] = '~y~옷~s~을 변경하려면 ~INPUT_CONTEXT~를 누르십시오.', + -- Armory + ['remove_object'] = '오브젝트를 빼다', + ['deposit_object'] = '오브젝트를 두다', + ['get_weapon'] = '병기고에서 무기를 빼다', + ['put_weapon'] = '병기고에 무기를 넣다', + ['buy_weapons'] = '무기 구매', + ['armory'] = '병기고', + ['open_armory'] = '~INPUT_CONTEXT~를 눌러 ~y~병기고~s~에 접근하십시오.', + ['armory_owned'] = '소유', + ['armory_free'] = '자유', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = '병기고 - 무기 구매', + ['armory_componenttitle'] = '병기고 - 무기 부착물', + ['armory_bought'] = '당신은 ~g~$%s~s~에 ~y~%s~s~를 구매했습니다', + ['armory_money'] = '당신은 이 무기를 살 수 없습니다', + ['armory_hascomponent'] = '이 부착물이 장착되어 있습니다!', + ['get_weapon_menu'] = '병기고 - 무기 빼다', + ['put_weapon_menu'] = '병기고 - 무기 넣다', + -- Vehicles + ['vehicle_menu'] = '차량', + ['vehicle_blocked'] = '모든 스폰 지점이 차단되었습니다!', + ['garage_prompt'] = '~INPUT_CONTEXT~를 눌러 ~y~차량 동작~s~에 액세스하십시오.', + ['garage_title'] = '차량 행동', + ['garage_stored'] = '저장됨', + ['garage_notstored'] = '차고가 아님', + ['garage_storing'] = '차량을 제거하려고 합니다. 주변에 아무도 없는지 확인하십시오.', + ['garage_has_stored'] = '차량이 차고에 보관되었습니다', + ['garage_has_notstored'] = '차고에 차량이 없습니다', + ['garage_notavailable'] = '차량이 차고에 저장되어 있지 않습니다', + ['garage_blocked'] = '차고 출구가 막혔습니다!', + ['garage_empty'] = '차고에 차량이 없습니다.', + ['garage_released'] = '차량이 출시되었습니다', + ['garage_store_nearby'] = '주변에 차량이 없습니다.', + ['garage_storeditem'] = '차고 열기', + ['garage_storeitem'] = '차량 정리', + ['garage_buyitem'] = '차량 상점', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = '~y~헬리콥터 동작~s~에 액세스하려면 ~INPUT_CONTEXT~를 누릅니다.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = '차량 판매점', + ['vehicleshop_confirm'] = '이 차량을 사고 싶습니까?', + ['vehicleshop_bought'] = '당신은 ~r~$%s~s~에 ~y~%s~s~를 구매했습니다', + ['vehicleshop_money'] = '이 차량을 살 수 없습니다', + ['vehicleshop_awaiting_model'] = '차량이 현재 ~g~다운로드 및 로딩중입니다~s~. 잠시만 기다려주십시오', + ['confirm_no'] = '아니요', + ['confirm_yes'] = '예', + -- Service + ['service_max'] = '서비스에 진입 할 수 없습니다. 최대 임원 : %s/%s', + ['service_not'] = '당신은 서비스를 입력하지 않았습니다! 먼저 변경해야합니다.', + ['service_anonunce'] = '서비스 정보', + ['service_in'] = '당신은 서비스에 들어갔다, 환영합니다!', + ['service_in_announce'] = '~y~%s~s~가 서비스에 들어 왔습니다!', + ['service_out'] = '당신은 서비스를 떠났습니다.', + ['service_out_announce'] = '~y~%s~s~가 서비스를 떠났습니다.', + -- Action Menu + ['citizen_interaction'] = '시민 상호 작용', + ['vehicle_interaction'] = '차량 상호 작용', + ['object_spawner'] = '오브젝트 Spawner', + + ['id_card'] = '신분증', + ['search'] = '수색', + ['handcuff'] = '수갑을 채우다 / 수갑을 풀어주다', + ['drag'] = '호위', + ['put_in_vehicle'] = '차량에 넣다', + ['out_the_vehicle'] = '차량을 끌다', + ['fine'] = '벌금', + ['unpaid_bills'] = '미지급 벌금 관리', + ['license_check'] = '라이선스 관리', + ['license_revoke'] = '라이선스 취소', + ['license_revoked'] = '~b~%s~s~는 ~y~취소~s~입니다!', + ['licence_you_revoked'] = '~y~%s~s~에 속하는 ~b~%s~s~를 취소했습니다.', + ['no_players_nearby'] = '근처에 플레이어가 없습니다!', + ['being_searched'] = '~b~경찰~s~이 당신을 ~y~수색~s~', + -- Vehicle interaction + ['vehicle_info'] = '차량 정보', + ['pick_lock'] = '차량 락픽', + ['vehicle_unlocked'] = '차량 ~g~잠금 해제~s~', + ['no_vehicles_nearby'] = '근처에 차량이 없습니다', + ['impound'] = '차량을 견인하다', + ['impound_prompt'] = '~y~견인~s~을 취소하려면 ~INPUT_CONTEXT~를 누릅니다', + ['impound_canceled'] = '당신은 견인을 취소했습니다', + ['impound_canceled_moved'] = '차량이 움직였기 때문에 견인이 취소되었습니다', + ['impound_successful'] = '당신은 차량을 견인했습니다', + ['search_database'] = '차량 정보', + ['search_database_title'] = '차량 정보 - 등록번호로 검색', + ['search_database_error_invalid'] = '~y~유효한~s~ 등록 번호가 ~r~아닙니다.~s~', + -- Traffic interaction + ['traffic_interaction'] = '교통 상호 작용', + ['cone'] = '원뿔', + ['barrier'] = '장벽', + ['spikestrips'] = '스파이크 스트립', + ['box'] = '상자', + ['cash'] = '현금 상자', + -- ID Card Menu + ['name'] = '이름: %s', + ['job'] = '직업: %s', + ['sex'] = '성별: %s', + ['dob'] = '생일: %s', + ['height'] = '키: %s', + ['bac'] = '혈중 알코올 농도: %s', + ['unknown'] = '알 수 없는', + ['male'] = '남자', + ['female'] = '여자', + -- Body Search Menu + ['guns_label'] = '--- 총 ---', + ['inventory_label'] = '--- 인벤토리 ---', + ['license_label'] = ' --- 라이선스 ---', + ['confiscate'] = '%s 을 압수', + ['confiscate_weapon'] = '%s 와 %s 총알을 압수', + ['confiscate_inv'] = '%sx %s 을 압수', + ['confiscate_dirty'] = '더러운 돈을 압수: $%s', + ['you_confiscated'] = '당신은 ~y~%sx~s~ ~b~%s~s~을 ~b~%s~s~에게서 압수했습니다', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~이(가) ~y~%s~s~에 압수되었습니다', + ['you_confiscated_account'] = '당신은 ~g~$%s~s~ (%s) 를 ~b~%s~s~ 에게서 압수했습니다.', + ['got_confiscated_account'] = '~g~$%s~s~ (%s) 이(가) ~y~%s~s~에 압수되었습니다', + ['you_confiscated_weapon'] = '당신은 ~b~%s~s~을 ~b~%s~s~에게서 압수하고 ~o~%s~s~ 총알도 압수했습니다.', + ['got_confiscated_weapon'] = '당신의 ~b~%s~s~와 ~o~%s~s~ 총알이 ~y~%s~s~에 의해 압수되었습니다.', + ['traffic_offense'] = '교통 위반', + ['minor_offense'] = '경범죄', + ['average_offense'] = '일반 범죄', + ['major_offense'] = '심각한 범죄', + ['fine_total'] = '벌금: %s', + -- Vehicle Info Menu + ['plate'] = '번호판: %s', + ['owner_unknown'] = '소유자: 알 수 없는', + ['owner'] = '소유자: %s', + -- Boss Menu + ['open_bossmenu'] = '~INPUT_CONTEXT~를 눌러 메뉴를 엽니다.', + ['quantity_invalid'] = '유효하지 않은 수량', + ['have_withdrawn'] = '당신은 ~y~%sx~s~ ~b~%s~s~ 뺐다 ', + ['have_deposited'] = '당신은 ~y~%sx~s~ ~b~%s~s~ 넣었다', + ['quantity'] = '수량', + ['inventory'] = '인벤토리', + ['police_stock'] = '경찰 자리', + -- Misc + ['remove_prop'] = '~INPUT_CONTEXT~를 눌러 오브젝트를 삭제하십시오.', + ['map_blip'] = '경찰서', + ['unrestrained_timer'] = '당신의 수갑이 천천히 풀리는 것을 느낍니다.', + -- Notifications + ['alert_police'] = '경찰 경보', + ['phone_police'] = '경찰', +} diff --git a/modules/job_police/data/locales/pl.lua b/modules/job_police/data/locales/pl.lua new file mode 100644 index 00000000..f85d4fa3 --- /dev/null +++ b/modules/job_police/data/locales/pl.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'szatnia', + ['citizen_wear'] = 'ubranie Cywilne', + ['police_wear'] = 'mundur', + ['gilet_wear'] = 'kamizelka odblaskowa', + ['bullet_wear'] = 'kamizelka kuloodporna', + ['no_outfit'] = 'brak ubrania', + ['open_cloackroom'] = 'naciśnij ~INPUT_CONTEXT~ aby zmienić ~y~ubranie~s~.', + -- Armory + ['remove_object'] = 'weź przedmiot', + ['deposit_object'] = 'zdeponuj przedmiot', + ['get_weapon'] = 'weź broń', + ['put_weapon'] = 'odłóż broń', + ['buy_weapons'] = 'kup Broń', + ['armory'] = 'zbrojownia', + ['open_armory'] = 'naciśnij ~INPUT_CONTEXT~ żeby uzyskać dostęp do zbrojowni', + ['armory_owned'] = 'owned', + ['armory_free'] = 'free', + ['armory_item'] = '$%s', + ['armory_weapontitle'] = 'armory - Buy weapon', + ['armory_componenttitle'] = 'armory - Weapon attatchments', + ['armory_bought'] = 'you bought an ~y~%s~s~ for ~g~$%s~s~', + ['armory_money'] = 'you cannot afford that weapon', + ['armory_hascomponent'] = 'you have that attatchment equiped!', + ['get_weapon_menu'] = 'armory - Withdraw Weapon', + ['put_weapon_menu'] = 'armory - Store Weapon', + -- Vehicles + ['vehicle_menu'] = 'vehicle', + ['vehicle_blocked'] = 'all available spawn points are currently blocked!', + ['garage_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Vehicle Actions~s~.', + ['garage_title'] = 'vehicle Actions', + ['garage_stored'] = 'stored', + ['garage_notstored'] = 'not in garage', + ['garage_storing'] = 'we\'re attempting to remove the vehicle, make sure no players are around it.', + ['garage_has_stored'] = 'the vehicle has been stored in your garage', + ['garage_has_notstored'] = 'no nearby owned vehicles were found', + ['garage_notavailable'] = 'your vehicle is not stored in the garage.', + ['garage_blocked'] = 'there\'s no available spawn points!', + ['garage_empty'] = 'you dont have any vehicles in your garage.', + ['garage_released'] = 'your vehicle has been released from the garage.', + ['garage_store_nearby'] = 'there is no nearby vehicles.', + ['garage_storeditem'] = 'open garage', + ['garage_storeitem'] = 'store vehicle in garage', + ['garage_buyitem'] = 'vehicle shop', + ['garage_notauthorized'] = 'you\'re not authorized to buy this kind of vehicles.', + ['helicopter_prompt'] = 'press ~INPUT_CONTEXT~ to access the ~y~Helicopter Actions~s~.', + ['shop_item'] = '$%s', + ['vehicleshop_title'] = 'vehicle Shop', + ['vehicleshop_confirm'] = 'do you want to buy this vehicle?', + ['vehicleshop_bought'] = 'you have bought ~y~%s~s~ for ~r~$%s~s~', + ['vehicleshop_money'] = 'you cannot afford that vehicle', + ['vehicleshop_awaiting_model'] = 'the vehicle is currently ~g~DOWNLOADING & LOADING~s~ please wait', + ['confirm_no'] = 'no', + ['confirm_yes'] = 'yes', + -- Service + ['service_max'] = 'nie możesz wejść do służby, maksymalna liczba oficerów w służbie: %s/%s', + ['service_not'] = 'nie rozpoczynasz służby! Najpierw musisz się przebrać.', + ['service_anonunce'] = 'informacje o służbie', + ['service_in'] = 'rozpoczynasz służbe, Witaj!', + ['service_in_announce'] = 'operator ~y~%s~s~ rozpoczyna służbę!', + ['service_out'] = 'opuszczasz służbę.', + ['service_out_announce'] = 'operator ~y~%s~s~ opuszcza służbe.', + -- Action Menu + ['citizen_interaction'] = 'interakcja z cywilami', + ['vehicle_interaction'] = 'interakcja z pojazdami', + ['object_spawner'] = 'przedmioty do postawienia', + + ['id_card'] = 'dowód osobisty', + ['search'] = 'przeszukaj', + ['handcuff'] = 'zakuj/Rozkuj Kajdanki ', + ['drag'] = 'przemieść podejrzanego', + ['put_in_vehicle'] = 'wsadź do pojazdu', + ['out_the_vehicle'] = 'wyciągnij z pojazdu', + ['fine'] = 'mandaty', + ['unpaid_bills'] = 'zarządzaj niezapłaconymi rachunkami', + ['license_check'] = 'zarządzaj licencjami', + ['license_revoke'] = 'unieważnij licencje', + ['license_revoked'] = 'twoja licencja ~b~%s~s~ została ~y~unieważniona~s~!', + ['licence_you_revoked'] = 'unieważniasz ~b~%s~s~ które należały do ~y~%s~s~', + ['no_players_nearby'] = 'brak graczy w pobliżu', + ['being_searched'] = 'you are being ~y~searched~s~ by the ~b~Police~s~', + -- Vehicle interaction + ['vehicle_info'] = 'informacje o pojeździe', + ['pick_lock'] = 'odblokuj pojazd', + ['vehicle_unlocked'] = 'pojazd ~g~Odblokowany~s~', + ['no_vehicles_nearby'] = 'brak pojazdu w pobliżu', + ['impound'] = 'zajmij pojazd', + ['impound_prompt'] = 'naciśnij ~INPUT_CONTEXT~ żeby unieważnić ~y~zajęcie~s~', + ['impound_canceled'] = 'unieważniasz zajęcie', + ['impound_canceled_moved'] = 'zajęcie zostało anulowane, ponieważ pojazd przemieścił się', + ['impound_successful'] = 'zajmujesz pojazd', + ['search_database'] = 'informacje o pojeździe', + ['search_database_title'] = 'informacjeo pojeździe - przeszukaj używając numeru rejestracyjnego', + ['search_database_error_invalid'] = 'to ~r~nie~s~ jest ~y~poprawny~s~ rnumer rejestracyjny', + -- Traffic interaction + ['traffic_interaction'] = 'interakcje dla ruchu drogowego', + ['cone'] = 'pachołek', + ['barrier'] = 'barierka', + ['spikestrips'] = 'kolczatka', + ['box'] = 'pudła', + ['cash'] = 'paleta z pieniędzmi', + -- ID Card Menu + ['name'] = 'name: %s', + ['job'] = 'praca: %s', + ['sex'] = 'płeć: %s', + ['dob'] = 'data urodzenia: %s', + ['height'] = 'wzrost: %s', + ['bac'] = 'BAC: %s', + ['unknown'] = 'nieznany', + ['male'] = 'mężczyzna', + ['female'] = 'kobieta', + -- Body Search Menu + ['guns_label'] = '--- Bronie ---', + ['inventory_label'] = '--- Ekwipunek ---', + ['license_label'] = ' --- Licenses ---', + ['confiscate'] = 'skonfiskuj %s', + ['confiscate_weapon'] = 'skonfiskuj %s z %s kulami', + ['confiscate_inv'] = 'skonfiskuj %s x %s', + ['confiscate_dirty'] = 'skonfiskuj brudne pieniądze: $%s', + ['you_confiscated'] = 'skonfiskowałeś ~y~%sx~s~ ~b~%s~s~ od ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ zostały skonfiskowane przez ~y~%s~s~', + ['you_confiscated_account'] = 'skonfiskowałeś ~g~%s$~s~ (%s) od ~b~%s~s~', + ['got_confiscated_account'] = '~g~%s$~s~ (%s) zostały skonfiskowane przez ~y~%s~s~', + ['you_confiscated_weapon'] = 'skonfiskowałeś ~b~%s~s~ od ~b~%s~s~ z ~o~%s~s~ pociskami', + ['got_confiscated_weapon'] = 'twój ~b~%s~s~ z ~o~%s~s~ kulami został skonfiskowany przez ~y~%s~s~', + ['traffic_offense'] = 'wykroczenia drogowe', + ['minor_offense'] = 'niewielkie wykroczenia', + ['average_offense'] = 'średnie wykroczenia', + ['major_offense'] = 'duże wykroczenia', + ['fine_total'] = 'mandat: %s', + -- Vehicle Info Menu + ['plate'] = 'tablica rejestracyjna: %s', + ['owner_unknown'] = 'właściciel: Nieznany', + ['owner'] = 'właściciel: %s', + -- Boss Menu + ['open_bossmenu'] = 'naciśnij ~INPUT_CONTEXT~ aby otworzyć menu', + ['quantity_invalid'] = 'nieprawidłowa ilość', + ['have_withdrawn'] = 'wyjmujesz z depozytu ~y~%sx~s~ ~b~%s~s~', + ['have_deposited'] = 'zdeponowano ~y~%sx~s~ ~b~%s~s~', + ['quantity'] = 'ilość', + ['inventory'] = 'ekwipunek', + ['police_stock'] = 'zapasy policji', + -- Misc + ['remove_prop'] = 'naciśnij ~INPUT_CONTEXT~ aby usunąć ten obiekt', + ['map_blip'] = 'komisariat Policji', + ['unrestrained_timer'] = 'czujesz, że twoje kajdanki powoli tracą przyczepność i znikają.', + -- Notifications + ['alert_police'] = 'ostrzeż policję', + ['phone_police'] = 'police', +} diff --git a/modules/job_police/data/locales/sv.lua b/modules/job_police/data/locales/sv.lua new file mode 100644 index 00000000..e1ac59d1 --- /dev/null +++ b/modules/job_police/data/locales/sv.lua @@ -0,0 +1,151 @@ +Translations = { + -- Cloakroom + ['cloakroom'] = 'omklädningsrum', + ['citizen_wear'] = 'civila kläder', + ['police_wear'] = 'polisuniform', + ['gilet_wear'] = 'reflektiv väst', + ['bullet_wear'] = 'skottsäker väst', + ['no_outfit'] = 'det finns ingen uniform som passar dig!', + ['open_cloackroom'] = 'tryck ~INPUT_CONTEXT~ för att välja ~y~kläder~s~.', + -- Armory + ['remove_object'] = 'ta ut objekt', + ['deposit_object'] = 'lägg in objekt', + ['get_weapon'] = 'ta ut vapen', + ['put_weapon'] = 'lägg in vapen', + ['buy_weapons'] = 'köp vapen', + ['armory'] = 'vapenförråd', + ['open_armory'] = 'tryck ~INPUT_CONTEXT~ för att komma åt ~y~vapenförrådet~s~.', + ['armory_owned'] = 'ägd', + ['armory_free'] = 'gratis', + ['armory_item'] = '%s SEK', + ['armory_weapontitle'] = 'vapenförråd - Köp vapen', + ['armory_componenttitle'] = 'vapenförråd - Vapen tillbehör', + ['armory_bought'] = 'du köpte ~y~%s~s~ för ~g~%s SEK~s~', + ['armory_money'] = 'du har inte råd med det vapnet', + ['armory_hascomponent'] = 'du har redan det tillbehöret!', + ['get_weapon_menu'] = 'vapenförråd - Ta ut vapen', + ['put_weapon_menu'] = 'vapenförråd - Spara vapen', + -- Vehicles + ['vehicle_menu'] = 'fordon', + ['vehicle_blocked'] = 'det finns ingen tillgänglig plats att ställa ut fordonet på!', + ['garage_prompt'] = 'tryck ~INPUT_CONTEXT~ för att komma åt ~y~garaget~s~.', + ['garage_title'] = 'garage', + ['garage_stored'] = 'inställt', + ['garage_notstored'] = 'uttaget', + ['garage_storing'] = 'vi håller på att ställa in ditt fordon, se till att ingen är i närheten.', + ['garage_has_stored'] = 'fordonet har ställts in i garaget', + ['garage_has_notstored'] = 'inget ägt fordon finns i närheten', + ['garage_notavailable'] = 'ditt fordon är inte inställt i ditt garage.', + ['garage_blocked'] = 'det finns ingen tillgänglig plats att ställa ut fordonet på!', + ['garage_empty'] = 'du har inga fordon i ditt garage.', + ['garage_released'] = 'ditt fordon har tagits ut från garaget.', + ['garage_store_nearby'] = 'det finns inget fordon i närheten.', + ['garage_storeditem'] = 'öppna garage', + ['garage_storeitem'] = 'ställ in fordon', + ['garage_buyitem'] = 'fordonshandel', + ['garage_notauthorized'] = 'du har inte tillgång till att köpa dessa fordon.', + ['helicopter_prompt'] = 'tryck ~INPUT_CONTEXT~ för att komma åt ~y~helikoptergaraget~s~.', + ['shop_item'] = '%s SEK', + ['vehicleshop_title'] = 'fordonshandel', + ['vehicleshop_confirm'] = 'vill du köpa detta fordon?', + ['vehicleshop_bought'] = 'du köpte ~y~%s~s~ för ~g~%s SEK~s~', + ['vehicleshop_money'] = 'du har inte råd med detta fordon', + ['vehicleshop_awaiting_model'] = 'fordonet ~g~LADDAS NED OCH LADDAS IN~s~ var god vänta', + ['confirm_no'] = 'nej', + ['confirm_yes'] = 'ja', + -- Service + ['service_max'] = 'du kan inte gå tjänst, poliser i tjänst: %s/%s', + ['service_not'] = 'du är inte i tjänst! Byt om för att gå in i tjänst.', + ['service_anonunce'] = 'tjänsteinformation', + ['service_in'] = 'du deltog i tjänst, välkommen!', + ['service_in_announce'] = 'operatör ~y~%s~s~ har deltagit tjänst!', + ['service_out'] = 'du har lämnat tjänst.', + ['service_out_announce'] = 'operatör ~y~%s~s~ har lämnat deras tjänst.', + -- Action Menu + ['citizen_interaction'] = 'handlingar mot civila', + ['vehicle_interaction'] = 'handlingar på bilar', + ['object_spawner'] = 'ta fram ett objekt', + + ['id_card'] = 'ID-Kort', + ['search'] = 'sök igenom', + ['handcuff'] = 'handbojor', + ['drag'] = 'dra', + ['put_in_vehicle'] = 'sätt in i fordon', + ['out_the_vehicle'] = 'dra ut ur fordon', + ['fine'] = 'Ge böter', + ['unpaid_bills'] = 'se obetalda räkningar', + ['license_check'] = 'se licenser', + ['license_revoke'] = 'återkalla licenser', + ['license_revoked'] = 'ditt ~b~%s~s~ har blivit ~y~återkallat~s~!', + ['licence_you_revoked'] = 'du återkallade ett ~b~%s~s~ som tillhörde ~y~%s~s~', + ['no_players_nearby'] = 'det finns ingen i närheten', + ['being_searched'] = 'du blir ~y~visiterad~s~ av ~b~Polisen~s~', + -- Vehicle interaction + ['vehicle_info'] = 'fordon', + ['pick_lock'] = 'bryt upp fordon', + ['vehicle_unlocked'] = 'fordonet har ~g~låsts upp~s~', + ['no_vehicles_nearby'] = 'inga fordon i närheten', + ['impound'] = 'bärga fordonet', + ['impound_prompt'] = 'tryck ~INPUT_CONTEXT~ för att avbryta ~y~bärgningen~s~', + ['impound_canceled'] = 'du avbröt bärgningen', + ['impound_canceled_moved'] = 'bärgningen avbröts på grund av att fordonet har rört sig', + ['impound_successful'] = 'du har bärgat fordonet', + ['search_database'] = 'fordonsuppgifter', + ['search_database_title'] = 'fordonsuppgifter - sök med registreringsnummer', + ['search_database_error_invalid'] = 'det är ~r~inte~s~ ett ~y~giltigt~s~ registreringsnummer', + -- Traffic interaction + ['traffic_interaction'] = 'trafiksåtgärder', + ['cone'] = 'kon', + ['barrier'] = 'barriär', + ['spikestrips'] = 'spikmatta', + ['box'] = 'låda', + ['cash'] = 'låda med pengar', + -- ID Card Menu + ['name'] = 'namn: %s', + ['job'] = 'jobb: %s', + ['sex'] = 'kön: %s', + ['dob'] = 'födelsedatum: %s', + ['height'] = 'längd: %s', + ['bac'] = 'alkohol i blodet: %s', + ['unknown'] = 'okänt', + ['male'] = 'man', + ['female'] = 'kvinna', + -- Body Search Menu + ['guns_label'] = '--- Vapen ---', + ['inventory_label'] = '--- Inventory ---', + ['license_label'] = ' --- Licenser ---', + ['confiscate'] = 'beslagta %s', + ['confiscate_weapon'] = 'beslagta %s med %s skott', + ['confiscate_inv'] = 'beslagta %sx %s', + ['confiscate_dirty'] = 'beslagta svarta pengar: %s SEK', + ['you_confiscated'] = 'du beslagtog ~y~%sx~s~ ~b~%s~s~ från ~b~%s~s~', + ['got_confiscated'] = '~y~%sx~s~ ~b~%s~s~ beslagtogs av ~y~%s~s~', + ['you_confiscated_account'] = 'du beslagtog ~g~%s SEK~s~ (%s) från ~b~%s~s~', + ['got_confiscated_account'] = '~g~%s SEK~s~ (%s) beslagtogs av ~y~%s~s~', + ['you_confiscated_weapon'] = 'du beslagtog ~b~%s~s~ från ~b~%s~s~ med ~o~%s~s~ skott', + ['got_confiscated_weapon'] = 'din ~b~%s~s~ med ~o~%s~s~ skott beslagtogs av ~y~%s~s~', + ['traffic_offense'] = 'brott mot trafikregler', + ['minor_offense'] = 'mindre lagbrott', + ['average_offense'] = 'medel lagbrott', + ['major_offense'] = 'grovt lagbrott', + ['fine_total'] = 'böter: %s', + -- Vehicle Info Menu + ['plate'] = 'reg nummer: %s', + ['owner_unknown'] = 'ägare: Okänt', + ['owner'] = 'ägare: %s', + -- Boss Menu + ['open_bossmenu'] = 'tryck ~INPUT_CONTEXT~ för att öppna menyn', + ['quantity_invalid'] = 'otillgängligt antal', + ['have_withdrawn'] = 'du har tagit ut ~y~x%s~s~ ~b~%s~s~', + ['have_deposited'] = 'du har lagrat ~y~x%s~s~ ~b~%s~s~', + ['quantity'] = 'antal', + ['inventory'] = 'förråd', + ['police_stock'] = 'polisförråd', + -- Misc + ['remove_prop'] = 'tryck ~INPUT_CONTEXT~ för att ta bort objektet', + ['map_blip'] = 'polisstation', + ['unrestrained_timer'] = 'dina handklovar har försvunnit', + -- Notifications + ['alert_police'] = 'meddela polisen', + ['phone_police'] = 'polisen', +} diff --git a/modules/job_police/server/events.lua b/modules/job_police/server/events.lua new file mode 100644 index 00000000..4b2d0d87 --- /dev/null +++ b/modules/job_police/server/events.lua @@ -0,0 +1,515 @@ +local self = ESX.Modules['job_police'] + +RegisterNetEvent('esx_policejob:confiscatePlayerItem') +AddEventHandler('esx_policejob:confiscatePlayerItem', function(target, itemType, itemName, amount) + local _source = source + local sourceXPlayer = ESX.GetPlayerFromId(_source) + local targetXPlayer = ESX.GetPlayerFromId(target) + + if sourceXPlayer.job.name ~= 'police' then + print(('esx_policejob: %s attempted to confiscate!'):format(xPlayer.identifier)) + return + end + + if itemType == 'item_standard' then + local targetItem = targetXPlayer.getInventoryItem(itemName) + local sourceItem = sourceXPlayer.getInventoryItem(itemName) + + -- does the target player have enough in their inventory? + if targetItem.count > 0 and targetItem.count <= amount then + + -- can the player carry the said amount of x item? + if sourceXPlayer.canCarryItem(itemName, sourceItem.count) then + targetXPlayer.removeInventoryItem(itemName, amount) + sourceXPlayer.addInventoryItem (itemName, amount) + sourceXPlayer.showNotification(_U('you_confiscated', amount, sourceItem.label, targetXPlayer.name)) + targetXPlayer.showNotification(_U('got_confiscated', amount, sourceItem.label, sourceXPlayer.name)) + else + sourceXPlayer.showNotification(_U('quantity_invalid')) + end + else + sourceXPlayer.showNotification(_U('quantity_invalid')) + end + + elseif itemType == 'item_account' then + targetXPlayer.removeAccountMoney(itemName, amount) + sourceXPlayer.addAccountMoney (itemName, amount) + + sourceXPlayer.showNotification(_U('you_confiscated_account', amount, itemName, targetXPlayer.name)) + targetXPlayer.showNotification(_U('got_confiscated_account', amount, itemName, sourceXPlayer.name)) + + elseif itemType == 'item_weapon' then + if amount == nil then amount = 0 end + targetXPlayer.removeWeapon(itemName, amount) + sourceXPlayer.addWeapon (itemName, amount) + + sourceXPlayer.showNotification(_U('you_confiscated_weapon', ESX.GetWeaponLabel(itemName), targetXPlayer.name, amount)) + targetXPlayer.showNotification(_U('got_confiscated_weapon', ESX.GetWeaponLabel(itemName), amount, sourceXPlayer.name)) + end +end) + +RegisterNetEvent('esx_policejob:handcuff') +AddEventHandler('esx_policejob:handcuff', function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == 'police' then + TriggerClientEvent('esx_policejob:handcuff', target) + else + print(('esx_policejob: %s attempted to handcuff a player (not cop)!'):format(xPlayer.identifier)) + end +end) + +RegisterNetEvent('esx_policejob:drag') +AddEventHandler('esx_policejob:drag', function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == 'police' then + TriggerClientEvent('esx_policejob:drag', target, source) + else + print(('esx_policejob: %s attempted to drag (not cop)!'):format(xPlayer.identifier)) + end +end) + +RegisterNetEvent('esx_policejob:putInVehicle') +AddEventHandler('esx_policejob:putInVehicle', function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == 'police' then + TriggerClientEvent('esx_policejob:putInVehicle', target) + else + print(('esx_policejob: %s attempted to put in vehicle (not cop)!'):format(xPlayer.identifier)) + end +end) + +RegisterNetEvent('esx_policejob:OutVehicle') +AddEventHandler('esx_policejob:OutVehicle', function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == 'police' then + TriggerClientEvent('esx_policejob:OutVehicle', target) + else + print(('esx_policejob: %s attempted to drag out from vehicle (not cop)!'):format(xPlayer.identifier)) + end +end) + +RegisterNetEvent('esx_policejob:getStockItem') +AddEventHandler('esx_policejob:getStockItem', function(itemName, count) + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + + TriggerEvent('esx_addoninventory:getSharedInventory', 'society_police', function(inventory) + local inventoryItem = inventory.getItem(itemName) + + -- is there enough in the society? + if count > 0 and inventoryItem.count >= count then + + -- can the player carry the said amount of x item? + if xPlayer.canCarryItem(itemName, count) then + inventory.removeItem(itemName, count) + xPlayer.addInventoryItem(itemName, count) + xPlayer.showNotification(_U('have_withdrawn', count, inventoryItem.label)) + else + xPlayer.showNotification(_U('quantity_invalid')) + end + else + xPlayer.showNotification(_U('quantity_invalid')) + end + end) +end) + +RegisterNetEvent('esx_policejob:putStockItems') +AddEventHandler('esx_policejob:putStockItems', function(itemName, count) + local xPlayer = ESX.GetPlayerFromId(source) + local sourceItem = xPlayer.getInventoryItem(itemName) + + TriggerEvent('esx_addoninventory:getSharedInventory', 'society_police', function(inventory) + local inventoryItem = inventory.getItem(itemName) + + -- does the player have enough of the item? + if sourceItem.count >= count and count > 0 then + xPlayer.removeInventoryItem(itemName, count) + inventory.addItem(itemName, count) + xPlayer.showNotification(_U('have_deposited', count, inventoryItem.label)) + else + xPlayer.showNotification(_U('quantity_invalid')) + end + end) +end) + +ESX.RegisterServerCallback('esx_policejob:getOtherPlayerData', function(source, cb, target, notify) + local xPlayer = ESX.GetPlayerFromId(target) + + if notify then + xPlayer.showNotification(_U('being_searched')) + end + + if xPlayer then + local data = { + name = xPlayer.getName(), + job = xPlayer.job.label, + grade = xPlayer.job.grade_label, + inventory = xPlayer.getInventory(), + accounts = xPlayer.getAccounts(), + weapons = xPlayer.getLoadout() + } + + if self.Config.EnableESXIdentity then + data.dob = xPlayer.get('dateofbirth') + data.height = xPlayer.get('height') + + if xPlayer.get('sex') == 'm' then data.sex = 'male' else data.sex = 'female' end + end + + TriggerEvent('esx_status:getStatus', target, 'drunk', function(status) + if status then + data.drunk = ESX.Math.Round(status.percent) + end + + if self.Config.EnableLicenses then + TriggerEvent('esx_license:getLicenses', target, function(licenses) + data.licenses = licenses + cb(data) + end) + else + cb(data) + end + end) + end +end) + +ESX.RegisterServerCallback('esx_policejob:getFineList', function(source, cb, category) + MySQL.Async.fetchAll('SELECT * FROM fine_types WHERE category = @category', { + ['@category'] = category + }, function(fines) + cb(fines) + end) +end) + +ESX.RegisterServerCallback('esx_policejob:getVehicleInfos', function(source, cb, plate) + MySQL.Async.fetchAll('SELECT owner FROM owned_vehicles WHERE plate = @plate', { + ['@plate'] = plate + }, function(result) + local retrivedInfo = {plate = plate} + + if result[1] then + local xPlayer = ESX.GetPlayerFromIdentifier(result[1].owner) + + -- is the owner online? + if xPlayer then + retrivedInfo.owner = xPlayer.getName() + cb(retrivedInfo) + elseif self.Config.EnableESXIdentity then + MySQL.Async.fetchAll('SELECT firstname, lastname FROM users WHERE identifier = @identifier', { + ['@identifier'] = result[1].owner + }, function(result2) + if result2[1] then + retrivedInfo.owner = ('%s %s'):format(result2[1].firstname, result2[1].lastname) + cb(retrivedInfo) + else + cb(retrivedInfo) + end + end) + else + cb(retrivedInfo) + end + else + cb(retrivedInfo) + end + end) +end) + +ESX.RegisterServerCallback('esx_policejob:getArmoryWeapons', function(source, cb) + TriggerEvent('esx_datastore:getSharedDataStore', 'society_police', function(store) + local weapons = store.get('weapons') + + if weapons == nil then + weapons = {} + end + + cb(weapons) + end) +end) + +ESX.RegisterServerCallback('esx_policejob:addArmoryWeapon', function(source, cb, weaponName, removeWeapon) + local xPlayer = ESX.GetPlayerFromId(source) + + if removeWeapon then + xPlayer.removeWeapon(weaponName) + end + + TriggerEvent('esx_datastore:getSharedDataStore', 'society_police', function(store) + local weapons = store.get('weapons') or {} + local foundWeapon = false + + for i=1, #weapons, 1 do + if weapons[i].name == weaponName then + weapons[i].count = weapons[i].count + 1 + foundWeapon = true + break + end + end + + if not foundWeapon then + table.insert(weapons, { + name = weaponName, + count = 1 + }) + end + + store.set('weapons', weapons) + cb() + end) +end) + +ESX.RegisterServerCallback('esx_policejob:removeArmoryWeapon', function(source, cb, weaponName) + local xPlayer = ESX.GetPlayerFromId(source) + xPlayer.addWeapon(weaponName, 500) + + TriggerEvent('esx_datastore:getSharedDataStore', 'society_police', function(store) + local weapons = store.get('weapons') or {} + + local foundWeapon = false + + for i=1, #weapons, 1 do + if weapons[i].name == weaponName then + weapons[i].count = (weapons[i].count > 0 and weapons[i].count - 1 or 0) + foundWeapon = true + break + end + end + + if not foundWeapon then + table.insert(weapons, { + name = weaponName, + count = 0 + }) + end + + store.set('weapons', weapons) + cb() + end) +end) + +ESX.RegisterServerCallback('esx_policejob:buyWeapon', function(source, cb, weaponName, type, componentNum) + + local xPlayer = ESX.GetPlayerFromId(source) + local authorizedWeapons = {} + + for i=1, xPlayer.job.grade, 1 do + + local weapons = self.Config.AuthorizedWeapons[i] + + for j=1, #weapons, 1 do + authorizedWeapons[#authorizedWeapons + 1] = weapons[j] + end + + end + + for k,v in ipairs(authorizedWeapons) do + if v.weapon == weaponName then + selectedWeapon = v + break + end + end + + if not selectedWeapon then + print(('esx_policejob: %s attempted to buy an invalid weapon.'):format(xPlayer.identifier)) + cb(false) + else + + TriggerEvent('esx_addonaccount:getSharedAccount', 'society_police', function(account) + + -- Weapon + if type == 1 then + + if account.money >= selectedWeapon.price then + + account.removeMoney(selectedWeapon.price) + xPlayer.addWeapon(weaponName, 100) + + cb(true) + + else + cb(false) + end + + -- Weapon Component + elseif type == 2 then + local price = selectedWeapon.components[componentNum] + local weaponNum, weapon = ESX.GetWeapon(weaponName) + local component = weapon.components[componentNum] + + if component then + if account.money >= price then + + account.removeMoney(price) + xPlayer.addWeaponComponent(weaponName, component.name) + + cb(true) + + else + cb(false) + end + else + print(('esx_policejob: %s attempted to buy an invalid weapon component.'):format(xPlayer.identifier)) + cb(false) + end + end + + end) + + end +end) + +ESX.RegisterServerCallback('esx_policejob:canBuyVehicle', function(source, cb, model, type) + + local xPlayer = ESX.GetPlayerFromId(source) + local price = self.GetPriceFromHash(GetHashKey(model), xPlayer.job.grade, type) + + -- vehicle model not found + if price == -1 then + cb(false) + else + + TriggerEvent('esx_addonaccount:getSharedAccount', 'society_police', function(account) + + if account.money >= price then + cb(true) + else + cb(false) + end + + end) + + end + +end) + +RegisterNetEvent('esx_policejob:buyJobVehicle') +AddEventHandler('esx_policejob:buyJobVehicle', function(vehicleProps, type) + + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + local price = self.GetPriceFromHash(vehicleProps.model, xPlayer.job.grade, type) + + -- vehicle model not found + if price == -1 then + print(('esx_policejob: %s attempted to exploit the shop! (invalid vehicle model)'):format(xPlayer.identifier)) + else + + TriggerEvent('esx_addonaccount:getSharedAccount', 'society_police', function(account) + + if account.money >= price then + + account.removeMoney(price) + + MySQL.Async.execute('INSERT INTO owned_vehicles (owner, vehicle, plate, type, job, `stored`) VALUES (@owner, @vehicle, @plate, @type, @job, @stored)', { + ['@owner'] = xPlayer.identifier, + ['@vehicle'] = json.encode(vehicleProps), + ['@plate'] = vehicleProps.plate, + ['@type'] = type, + ['@job'] = xPlayer.job.name, + ['@stored'] = true + }) + + else + print(('esx_policejob: %s attempted to exploit the shop! (not enough money)'):format(xPlayer.identifier)) + end + + end) + + end + +end) + +ESX.RegisterServerCallback('esx_policejob:storeNearbyVehicle', function(source, cb, nearbyVehicles) + local xPlayer = ESX.GetPlayerFromId(source) + local foundPlate, foundNum + + for k,v in ipairs(nearbyVehicles) do + local result = MySQL.Sync.fetchAll('SELECT plate FROM owned_vehicles WHERE owner = @owner AND plate = @plate AND job = @job', { + ['@owner'] = xPlayer.identifier, + ['@plate'] = v.plate, + ['@job'] = xPlayer.job.name + }) + + if result[1] then + foundPlate, foundNum = result[1].plate, k + break + end + end + + if not foundPlate then + cb(false) + else + MySQL.Async.execute('UPDATE owned_vehicles SET `stored` = true WHERE owner = @owner AND plate = @plate AND job = @job', { + ['@owner'] = xPlayer.identifier, + ['@plate'] = foundPlate, + ['@job'] = xPlayer.job.name + }, function (rowsChanged) + if rowsChanged == 0 then + print(('esx_policejob: %s has exploited the garage!'):format(xPlayer.identifier)) + cb(false) + else + cb(true, foundNum) + end + end) + end +end) + +ESX.RegisterServerCallback('esx_policejob:getStockItems', function(source, cb) + TriggerEvent('esx_addoninventory:getSharedInventory', 'society_police', function(inventory) + cb(inventory.items) + end) +end) + +ESX.RegisterServerCallback('esx_policejob:getPlayerInventory', function(source, cb) + local xPlayer = ESX.GetPlayerFromId(source) + local items = xPlayer.inventory + + cb({items = items}) +end) + +AddEventHandler('playerDropped', function() + -- Save the source in case we lose it (which happens a lot) + local playerId = source + + -- Did the player ever join? + if playerId then + local xPlayer = ESX.GetPlayerFromId(playerId) + + -- Is it worth telling all clients to refresh? + if xPlayer and xPlayer.job.name == 'police' then + Citizen.Wait(5000) + TriggerClientEvent('esx_policejob:updateBlip', -1) + end + end +end) + +RegisterNetEvent('esx_policejob:spawned') +AddEventHandler('esx_policejob:spawned', function() + local xPlayer = ESX.GetPlayerFromId(playerId) + + if xPlayer and xPlayer.job.name == 'police' then + Citizen.Wait(5000) + TriggerClientEvent('esx_policejob:updateBlip', -1) + end +end) + +RegisterNetEvent('esx_policejob:forceBlip') +AddEventHandler('esx_policejob:forceBlip', function() + TriggerClientEvent('esx_policejob:updateBlip', -1) +end) + +AddEventHandler('onResourceStart', function(resource) + if resource == GetCurrentResourceName() then + Citizen.Wait(5000) + TriggerClientEvent('esx_policejob:updateBlip', -1) + end +end) + +AddEventHandler('onResourceStop', function(resource) + if resource == GetCurrentResourceName() then + TriggerEvent('esx_phone:removeNumber', 'police') + end +end) diff --git a/modules/job_police/server/main.lua b/modules/job_police/server/main.lua new file mode 100644 index 00000000..449ba44d --- /dev/null +++ b/modules/job_police/server/main.lua @@ -0,0 +1,15 @@ +local self = ESX.Modules['job_police'] + +if self.Config.EnableESXService then + TriggerEvent('esx_service:activateService', 'police', self.Config.MaxInService) +end + +AddEventHandler('onResourceStart', function(resource) + + if resource == 'esx_society' then + TriggerEvent('esx_society:registerSociety', 'police', 'Police', 'society_police', 'society_police', 'society_police', {type = 'public'}) + elseif resource == 'esx_phone' then + TriggerEvent('esx_phone:registerNumber', 'police', _U('alert_police'), true, true) + end + +end) diff --git a/modules/job_police/server/module.lua b/modules/job_police/server/module.lua new file mode 100644 index 00000000..2c8a7409 --- /dev/null +++ b/modules/job_police/server/module.lua @@ -0,0 +1,31 @@ +ESX.Modules['job_police'] = {}; +local self = ESX.Modules['job_police'] + +-- Properties +self.Config = ESX.EvalFile(GetCurrentResourceName(), 'modules/job_police/data/config.lua', { + vector3 = vector3 +})['Config'] + +self.GetPriceFromHash = function(vehicleHash, jobGrade, type) + + local authorizedVehicles = {} + + for i=1, jobGrade, 1 do + + local vehicles = self.Config.AuthorizedVehicles[type][i] + + for j=1, #vehicles, 1 do + authorizedVehicles[#authorizedVehicles + 1] = vehicles[j] + end + + end + + for k,v in ipairs(authorizedVehicles) do + if GetHashKey(v.model) == vehicleHash then + return v.price + end + end + + return -1 + +end diff --git a/modules/menu_default/client/events.lua b/modules/menu_default/client/events.lua new file mode 100644 index 00000000..7d8347e7 --- /dev/null +++ b/modules/menu_default/client/events.lua @@ -0,0 +1,71 @@ +local self = ESX.Modules['menu_default'] + +AddEventHandler('esx:nui_ready', function() + ESX.CreateFrame('menu_default', 'nui://' .. GetCurrentResourceName() .. '/modules/menu_default/data/html/ui.html') +end) + +ESX.Modules['input'].On('pressed', 0, 18, function(lastTime) + if (GetGameTimer() - lastTime) < 150 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'ENTER'}) +end) + +ESX.Modules['input'].On('pressed', 0, 177, function(lastTime) + if (GetGameTimer() - lastTime) < 150 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'BACKSPACE'}) +end) + +ESX.Modules['input'].On('pressed', 0, 27, function(lastTime) + if (GetGameTimer() - lastTime) < 300 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'TOP'}) +end) + +ESX.Modules['input'].On('pressed', 0, 173, function(lastTime) + if (GetGameTimer() - lastTime) < 300 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'DOWN'}) +end) + +ESX.Modules['input'].On('pressed', 0, 174, function(lastTime) + if (GetGameTimer() - lastTime) < 300 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'LEFT'}) +end) + +ESX.Modules['input'].On('pressed', 0, 175, function(lastTime) + if (GetGameTimer() - lastTime) < 300 then return end + ESX.SendFrameMessage('menu_default', {action = 'controlPressed', control = 'RIGHT'}) +end) + + +AddEventHandler('menu_default:message:menu_submit', function(data) + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + + if menu.submit ~= nil then + menu.submit(data, menu) + end +end) + +AddEventHandler('menu_default:message:menu_cancel', function(data) + + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + + if menu.cancel ~= nil then + menu.cancel(data, menu) + end +end) + +AddEventHandler('menu_default:message:menu_change', function(data) + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + + for i=1, #data.elements, 1 do + menu.setElement(i, 'value', data.elements[i].value) + + if data.elements[i].selected then + menu.setElement(i, 'selected', true) + else + menu.setElement(i, 'selected', false) + end + end + + if menu.change ~= nil then + menu.change(data, menu) + end +end) diff --git a/modules/menu_default/client/main.lua b/modules/menu_default/client/main.lua new file mode 100644 index 00000000..332fbded --- /dev/null +++ b/modules/menu_default/client/main.lua @@ -0,0 +1,11 @@ + +local self = ESX.Modules['menu_default'] + +ESX.UI.Menu.RegisterType(self.MenuType, self.OpenMenu, self.CloseMenu) + +ESX.Modules['input'].RegisterControl(0, 18) +ESX.Modules['input'].RegisterControl(0, 177) +ESX.Modules['input'].RegisterControl(0, 27) +ESX.Modules['input'].RegisterControl(0, 173) +ESX.Modules['input'].RegisterControl(0, 174) +ESX.Modules['input'].RegisterControl(0, 175) diff --git a/modules/menu_default/client/module.lua b/modules/menu_default/client/module.lua new file mode 100644 index 00000000..87355a79 --- /dev/null +++ b/modules/menu_default/client/module.lua @@ -0,0 +1,26 @@ +ESX.Modules['menu_default'] = {}; +local self = ESX.Modules['menu_default'] + +self.GUI = {} +self.GUI.Time = 0 +self.MenuType = 'default' + +self.OpenMenu = function(namespace, name, data) + ESX.SendFrameMessage('menu_default', { + action = 'openMenu', + namespace = namespace, + name = name, + data = data + }) +end + +self.CloseMenu = function(namespace, name) + ESX.SendFrameMessage('menu_default', { + action = 'closeMenu', + namespace = namespace, + name = name, + data = data + }) +end + + diff --git a/modules/menu_default/data/html/css/app.css b/modules/menu_default/data/html/css/app.css new file mode 100644 index 00000000..4ad1a0fb --- /dev/null +++ b/modules/menu_default/data/html/css/app.css @@ -0,0 +1,94 @@ +@font-face { + font-family: bankgothic; + src: url('../fonts/bankgothic.ttf'); +} + +@font-face { + font-family: pcdown; + src: url('../fonts/pdown.ttf'); +} + +.menu { + font-family: bankgothic; + min-width: 400px; + color: #fff; + box-shadow: 0px 0px 50px 0px #000; + position: absolute; +} + +.menu.align-left { + left: 40; + top: 50%; + transform: translate(0, -50%); +} + +.menu.align-top-left { + left: 40; + top: 40; +} + +.menu.align-top { + left: 50%; + top: 40; + transform: translate(-50%, 0); +} + +.menu.align-top-right { + right: 10; + top: 40; +} + +.menu.align-right { + right: 40; + top: 50%; + transform: translate(0, -50%); +} + +.menu.align-bottom-right { + right: 40; + bottom: 40; +} + +.menu.align-bottom { + left: 50%; + bottom: 40; + transform: translate(-50%, 0); +} + +.menu.align-bottom-left { + left: 40; + bottom: 40; +} + +.menu.align-center { + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +.menu .head { + background-color: #506be6; + text-align: center; + height: 40px; + line-height: 40px; +} + +.menu .menu-items { + max-height: 600px; + overflow-y: auto; +} + +.menu .menu-items .menu-item { + height: 40px; + display: block; + background-color: #f1f1f1; + box-shadow: inset 1px 0px 0px 1px #b8b8b8; + height: 32px; + line-height: 32px; + color: #3A3A3A; + text-align: center; +} + +.menu .menu-items .menu-item.selected { + background-color: #d0d0d0; +} diff --git a/modules/menu_default/data/html/fonts/bankgothic.ttf b/modules/menu_default/data/html/fonts/bankgothic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f3d8049b052a1f9cfd27557eb3675bc85ce4b9fc GIT binary patch literal 36272 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 D`#l06 literal 0 HcmV?d00001 diff --git a/modules/menu_default/data/html/fonts/pdown.ttf b/modules/menu_default/data/html/fonts/pdown.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69c76cf3f2a6bbc93f570124554fec06d7bbac25 GIT binary patch literal 151512 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 literal 0 HcmV?d00001 diff --git a/modules/menu_default/data/html/js/app.js b/modules/menu_default/data/html/js/app.js new file mode 100644 index 00000000..a397695f --- /dev/null +++ b/modules/menu_default/data/html/js/app.js @@ -0,0 +1,346 @@ +(function(){ + let MenuTpl = + '' + + '' + ; + + window.ESX_MENU = {}; + ESX_MENU.ResourceName = 'menu_default'; + ESX_MENU.opened = {}; + ESX_MENU.focus = []; + ESX_MENU.pos = {}; + + ESX_MENU.open = function(namespace, name, data) { + if (typeof ESX_MENU.opened[namespace] == 'undefined') { + ESX_MENU.opened[namespace] = {}; + } + + if (typeof ESX_MENU.opened[namespace][name] != 'undefined') { + ESX_MENU.close(namespace, name); + } + + if (typeof ESX_MENU.pos[namespace] == 'undefined') { + ESX_MENU.pos[namespace] = {}; + } + + for (let i=0; i { + switch (data.action) { + + case 'openMenu': { + ESX_MENU.open(data.namespace, data.name, data.data); + break; + } + + case 'closeMenu': { + ESX_MENU.close(data.namespace, data.name); + break; + } + + case 'controlPressed': { + switch (data.control) { + + case 'ENTER': { + let focused = ESX_MENU.getFocused(); + + if (typeof focused != 'undefined') { + let menu = ESX_MENU.opened[focused.namespace][focused.name]; + let pos = ESX_MENU.pos[focused.namespace][focused.name]; + let elem = menu.elements[pos]; + + if (menu.elements.length > 0) { + ESX_MENU.submit(focused.namespace, focused.name, {...elem, index: pos + 1}); + } + } + + break; + } + + case 'BACKSPACE': { + let focused = ESX_MENU.getFocused(); + + if (typeof focused != 'undefined') { + ESX_MENU.cancel(focused.namespace, focused.name); + } + + break; + } + + case 'TOP': { + let focused = ESX_MENU.getFocused(); + + if (typeof focused != 'undefined') { + let menu = ESX_MENU.opened[focused.namespace][focused.name]; + let pos = ESX_MENU.pos[focused.namespace][focused.name]; + + if (pos > 0) { + ESX_MENU.pos[focused.namespace][focused.name]--; + } else { + ESX_MENU.pos[focused.namespace][focused.name] = menu.elements.length - 1; + } + + let elem = menu.elements[ESX_MENU.pos[focused.namespace][focused.name]]; + + for (let i=0; i min) { + elem.value--; + ESX_MENU.change(focused.namespace, focused.name, elem); + } + + ESX_MENU.render(); + break; + } + + default: break; + } + + $('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView(); + } + + break; + } + + case 'RIGHT': { + let focused = ESX_MENU.getFocused(); + + if (typeof focused != 'undefined') { + let menu = ESX_MENU.opened[focused.namespace][focused.name]; + let pos = ESX_MENU.pos[focused.namespace][focused.name]; + let elem = menu.elements[pos]; + + switch(elem.type) { + case 'default': break; + + case 'slider': { + if (typeof elem.options != 'undefined' && elem.value < elem.options.length - 1) { + elem.value++; + ESX_MENU.change(focused.namespace, focused.name, elem); + } + + if (typeof elem.max != 'undefined' && elem.value < elem.max) { + elem.value++; + ESX_MENU.change(focused.namespace, focused.name, elem); + } + + ESX_MENU.render(); + break; + } + + default: break; + } + + $('#menu_' + focused.namespace + '_' + focused.name).find('.menu-item.selected')[0].scrollIntoView(); + } + + break; + } + + default: break; + } + + break; + } + } + }; + + window.onload = function(e){ + window.addEventListener('message', (event) => { + onData(event.data); + }); + }; + +})(); diff --git a/modules/menu_default/data/html/js/mustache.min.js b/modules/menu_default/data/html/js/mustache.min.js new file mode 100644 index 00000000..520cfcb9 --- /dev/null +++ b/modules/menu_default/data/html/js/mustache.min.js @@ -0,0 +1 @@ +(function defineMustache(global,factory){if(typeof exports==="object"&&exports&&typeof exports.nodeName!=="string"){factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],factory)}else{global.Mustache={};factory(global.Mustache)}})(this,function mustacheFactory(mustache){var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function eos(){return this.tail===""};Scanner.prototype.scan=function scan(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function scanUntil(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function push(view){return new Context(view,this)};Context.prototype.lookup=function lookup(name){var cache=this.cache;var value;if(cache.hasOwnProperty(name)){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index")value=this.renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this.unescapedValue(token,context);else if(symbol==="name")value=this.escapedValue(token,context);else if(symbol==="text")value=this.rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype.renderSection=function renderSection(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;j + + + + + + + + + + + + + + + + diff --git a/modules/menu_default/server/events.lua b/modules/menu_default/server/events.lua new file mode 100644 index 00000000..72967122 --- /dev/null +++ b/modules/menu_default/server/events.lua @@ -0,0 +1,2 @@ +local self = ESX.Modules['menu_default'] + diff --git a/modules/menu_default/server/main.lua b/modules/menu_default/server/main.lua new file mode 100644 index 00000000..cc5d2c39 --- /dev/null +++ b/modules/menu_default/server/main.lua @@ -0,0 +1,3 @@ + +local self = ESX.Modules['menu_default'] + diff --git a/modules/menu_default/server/module.lua b/modules/menu_default/server/module.lua new file mode 100644 index 00000000..df30dce4 --- /dev/null +++ b/modules/menu_default/server/module.lua @@ -0,0 +1,3 @@ +ESX.Modules['menu_default'] = {}; +local self = ESX.Modules['menu_default'] + diff --git a/modules/menu_dialog/client/events.lua b/modules/menu_dialog/client/events.lua new file mode 100644 index 00000000..c1bc558a --- /dev/null +++ b/modules/menu_dialog/client/events.lua @@ -0,0 +1,48 @@ +local self = ESX.Modules['menu_dialog'] + +AddEventHandler('esx:nui_ready', function() + ESX.CreateFrame('menu_dialog', 'nui://' .. GetCurrentResourceName() .. '/modules/menu_dialog/data/html/ui.html') +end) + +AddEventHandler('menu_dialog:message:menu_submit', function(data) + + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + local cancel = false + + if menu.submit then + -- is the submitted data a number? + if tonumber(data.value) then + data.value = ESX.Math.Round(tonumber(data.value)) + + -- check for negative value + if tonumber(data.value) <= 0 then + cancel = true + end + end + + data.value = ESX.Math.Trim(data.value) + + -- don't submit if the value is negative or if it's 0 + if cancel then + ESX.ShowNotification('That input is not allowed!') + else + menu.submit(data, menu) + end + end +end) + +AddEventHandler('menu_dialog:message:menu_cancel', function(data) + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + + if menu.cancel ~= nil then + menu.cancel(data, menu) + end +end) + +AddEventHandler('menu_dialog:message:menu_change', function(data) + local menu = ESX.UI.Menu.GetOpened(self.MenuType, data._namespace, data._name) + + if menu.change ~= nil then + menu.change(data, menu) + end +end) \ No newline at end of file diff --git a/modules/menu_dialog/client/main.lua b/modules/menu_dialog/client/main.lua new file mode 100644 index 00000000..60051150 --- /dev/null +++ b/modules/menu_dialog/client/main.lua @@ -0,0 +1,24 @@ + +local self = ESX.Modules['menu_dialog'] + +ESX.UI.Menu.RegisterType(self.MenuType, self.openMenu, self.closeMenu) + +Citizen.CreateThread(function() + while true do + Citizen.Wait(10) + + if ESX.Table.SizeOf(self.OpenedMenus) > 0 then + DisableControlAction(0, 1, true) -- LookLeftRight + DisableControlAction(0, 2, true) -- LookUpDown + DisableControlAction(0, 142, true) -- MeleeAttackAlternate + DisableControlAction(0, 106, true) -- VehicleMouseControlOverride + DisableControlAction(0, 12, true) -- WeaponWheelUpDown + DisableControlAction(0, 14, true) -- WeaponWheelNext + DisableControlAction(0, 15, true) -- WeaponWheelPrev + DisableControlAction(0, 16, true) -- SelectNextWeapon + DisableControlAction(0, 17, true) -- SelectPrevWeapon + else + Citizen.Wait(500) + end + end +end) diff --git a/modules/menu_dialog/client/module.lua b/modules/menu_dialog/client/module.lua new file mode 100644 index 00000000..1bfdd2c0 --- /dev/null +++ b/modules/menu_dialog/client/module.lua @@ -0,0 +1,46 @@ +ESX.Modules['menu_dialog'] = {}; +local self = ESX.Modules['menu_dialog'] + +self.Timeouts = {} +self.OpenedMenus = {} +self.MenuType = 'dialog' + +self.openMenu = function(namespace, name, data) + + for i=1, #self.Timeouts, 1 do + ESX.ClearTimeout(self.Timeouts[i]) + end + + self.OpenedMenus[namespace .. '_' .. name] = true + + ESX.SendFrameMessage('menu_dialog', { + action = 'openMenu', + namespace = namespace, + name = name, + data = data + }) + + local timeoutId = ESX.SetTimeout(200, function() + ESX.FocusFrame('menu_dialog', true, true) + end) + + table.insert(self.Timeouts, timeoutId) +end + +self.closeMenu = function(namespace, name) + + self.OpenedMenus[namespace .. '_' .. name] = nil + + ESX.SendFrameMessage('menu_dialog', { + action = 'closeMenu', + namespace = namespace, + name = name, + data = data + }) + + if ESX.Table.SizeOf(self.OpenedMenus) == 0 then + SetNuiFocus(false) + end + +end + diff --git a/modules/menu_dialog/data/html/css/app.css b/modules/menu_dialog/data/html/css/app.css new file mode 100644 index 00000000..e8f361b5 --- /dev/null +++ b/modules/menu_dialog/data/html/css/app.css @@ -0,0 +1,74 @@ +@font-face { + font-family: bankgothic; + src: url('../fonts/bankgothic.ttf'); +} + +@font-face { + font-family: pcdown; + src: url('../fonts/pdown.ttf'); +} + +#controls { + font-family: pcdown; + font-size: 3em; + color: #FFF; + position: absolute; + bottom: 40; + right: 40; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; +} + +.controls { + display: none; +} + +.dialog { + font-family: bankgothic; + background-color: #fff; + color: #fff; + box-shadow: 0px 0px 50px 0px #000; + position: absolute; + overflow: hidden; + top: 50%; + left: 50%; + width: 600px; + height: 104px; + transform: translate(-50%, -50%); +} + +.dialog.big { + height: 200px; +} + +.dialog .head { + background-color: #506be6; + text-align: center; + height: 40px; +} + +.dialog .head span:before { + content: ""; + display: inline-block; + height: 100%; + vertical-align: middle; +} + +.dialog input[type="text"] { + width: 100%; + height: 32px; +} + +.dialog textarea { + width: 100%; + height: 128px; +} + +.dialog button[name="submit"] { + width: 75%; + height: 32px; +} + +.dialog button[name="cancel"] { + width: 25%; + height: 32px; +} diff --git a/modules/menu_dialog/data/html/fonts/bankgothic.ttf b/modules/menu_dialog/data/html/fonts/bankgothic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f3d8049b052a1f9cfd27557eb3675bc85ce4b9fc GIT binary patch literal 36272 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 D`#l06 literal 0 HcmV?d00001 diff --git a/modules/menu_dialog/data/html/fonts/pdown.ttf b/modules/menu_dialog/data/html/fonts/pdown.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69c76cf3f2a6bbc93f570124554fec06d7bbac25 GIT binary patch literal 151512 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 literal 0 HcmV?d00001 diff --git a/modules/menu_dialog/data/html/js/app.js b/modules/menu_dialog/data/html/js/app.js new file mode 100644 index 00000000..c41f6c8b --- /dev/null +++ b/modules/menu_dialog/data/html/js/app.js @@ -0,0 +1,176 @@ +(function () { + let MenuTpl = + '