From 1f9d2396f05145a145a021ff6e981e88e4dff293 Mon Sep 17 00:00:00 2001 From: bitpredator <67551273+bitpredator@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:32:26 +0100 Subject: [PATCH] refactor: armory work reconstruction --- .../[bpt_addons]/bpt_ammujob/bpt_ammujob.sql | 2 +- .../[bpt_addons]/bpt_ammujob/client/main.lua | 1304 +++++++++++++---- .../bpt_ammujob/client/vehicle.lua | 320 ++++ .../[bpt_addons]/bpt_ammujob/config.lua | 113 +- .../[bpt_addons]/bpt_ammujob/fxmanifest.lua | 29 +- .../[bpt_addons]/bpt_ammujob/locales/en.lua | 178 ++- .../[bpt_addons]/bpt_ammujob/locales/it.lua | 177 ++- .../localization/bpt_ammujob_it.sql | 2 +- .../[bpt_addons]/bpt_ammujob/server/main.lua | 418 +++++- 9 files changed, 2120 insertions(+), 423 deletions(-) create mode 100644 server-data/resources/[bpt_addons]/bpt_ammujob/client/vehicle.lua diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/bpt_ammujob.sql b/server-data/resources/[bpt_addons]/bpt_ammujob/bpt_ammujob.sql index c95753506..a35152c03 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/bpt_ammujob.sql +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/bpt_ammujob.sql @@ -20,4 +20,4 @@ INSERT INTO `job_grades` (job_name, grade, name, label, salary, skin_male, skin_ ('ammu',2,'armorychief','Armory Chief',60,'{}','{}'), ('ammu',3,'deputydirector','Deputy Director',85,'{}','{}'), ('ammu',4,'boss','Boss',100,'{}','{}') -; +; \ No newline at end of file diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/client/main.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/client/main.lua index 7d8112936..2191b7c78 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/client/main.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/client/main.lua @@ -1,378 +1,1174 @@ -local HasAlreadyEnteredMarker -local CurrentAction, CurrentActionMsg, CurrentActionData = nil, "", {} -local LastZone - -RegisterNetEvent("esx:playerLoaded") -AddEventHandler("esx:playerLoaded", function(xPlayer) - ESX.PlayerData = xPlayer - ESX.PlayerLoaded = true -end) - -RegisterNetEvent("esx:onPlayerLogout") -AddEventHandler("esx:onPlayerLogout", function() - ESX.PlayerLoaded = false - ESX.PlayerData = {} -end) +---@diagnostic disable: undefined-global -RegisterNetEvent("esx:setJob") -AddEventHandler("esx:setJob", function(job) - ESX.PlayerData.job = job -end) +local CurrentActionData, handcuffTimer, dragStatus, blipsCops, currentTask = {}, {}, {}, {}, {} +local HasAlreadyEnteredMarker, isDead, isHandcuffed, hasAlreadyJoined, playerInService = false, false, false, false, false +local LastStation, LastPart, LastPartNum, LastEntity, CurrentAction, CurrentActionMsg +dragStatus.isDragged, IsInShopMenu = false, false -function DrawSub(msg, time) - ClearPrints() - BeginTextCommandPrint("STRING") - AddTextComponentSubstringPlayerName(msg) - EndTextCommandPrint(time, true) +function CleanPlayer(playerPed) + SetPedArmour(playerPed, 0) + ClearPedBloodDamage(playerPed) + ResetPedVisibleDamage(playerPed) + ClearPedLastWeaponDamage(playerPed) + ResetPedMovementClipset(playerPed, 0) end -function ShowLoadingPromt(msg, time, type) - CreateThread(function() - Wait(0) +function OpenArmoryMenu(station) + local elements + if Config.OxInventory then + exports.ox_inventory:openInventory("stash", { id = "society_ammu", owner = station }) + return ESX.CloseContext() + else + elements = { + { unselectable = true, icon = "fas fa-gun", title = TranslateCap("armory") }, + { icon = "fas fa-gun", title = TranslateCap("buy_weapons"), value = "buy_weapons" }, + } - BeginTextCommandBusyspinnerOn("STRING") - AddTextComponentSubstringPlayerName(msg) - EndTextCommandBusyspinnerOn(type) - Wait(time) + if Config.EnableArmoryManagement then + table.insert(elements, { icon = "fas fa-gun", title = TranslateCap("get_weapon"), value = "get_weapon" }) + table.insert(elements, { icon = "fas fa-gun", title = TranslateCap("put_weapon"), value = "put_weapon" }) + table.insert(elements, { icon = "fas fa-box", title = TranslateCap("remove_object"), value = "get_stock" }) + table.insert(elements, { icon = "fas fa-box", title = TranslateCap("deposit_object"), value = "put_stock" }) + end + end - BusyspinnerOff() + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + if data.current.value == "get_weapon" then + OpenGetWeaponMenu() + elseif data.current.value == "put_weapon" then + OpenPutWeaponMenu() + elseif data.current.value == "put_stock" then + OpenPutStocksMenu() + elseif data.current.value == "get_stock" then + OpenGetStocksMenu() + end + end, function(menu) + CurrentAction = "menu_armory" + CurrentActionMsg = TranslateCap("open_armory") + CurrentActionData = { station = station } end) end -function OpenCloakroom() +function OpenAmmuActionsMenu() local elements = { - { unselectable = true, icon = "fas fa-shirt", title = TranslateCap("cloakroom_menu") }, - { icon = "fas fa-shirt", title = TranslateCap("wear_citizen"), value = "wear_citizen" }, - { icon = "fas fa-shirt", title = TranslateCap("wear_work"), value = "wear_work" }, + { unselectable = true, icon = "fas fa-ammu", title = TranslateCap("menu_title") }, + { icon = "fas fa-user", title = TranslateCap("citizen_interaction"), value = "citizen_interaction" }, + { icon = "fas fa-car", title = TranslateCap("vehicle_interaction"), value = "vehicle_interaction" }, } - ESX.OpenContext("right", elements, function(_, element) - if element.value == "wear_citizen" then - ESX.TriggerServerCallback("esx_skin:getPlayerSkin", function(skin) - TriggerEvent("skinchanger:loadSkin", skin) + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + + if data.current.value == "citizen_interaction" then + local elements2 = { + { unselectable = true, icon = "fas fa-user", title = element.title }, + { icon = "fas fa-idkyet", title = TranslateCap("id_card"), value = "identity_card" }, + { icon = "fas fa-idkyet", title = TranslateCap("search"), value = "search" }, + { icon = "fas fa-idkyet", title = TranslateCap("handcuff"), value = "handcuff" }, + { icon = "fas fa-idkyet", title = TranslateCap("drag"), value = "drag" }, + { icon = "fas fa-idkyet", title = TranslateCap("put_in_vehicle"), value = "put_in_vehicle" }, + { icon = "fas fa-idkyet", title = TranslateCap("out_the_vehicle"), value = "out_the_vehicle" }, + { icon = "fas fa-idkyet", title = TranslateCap("fine"), value = "fine" }, + { icon = "fas fa-idkyet", title = TranslateCap("weapon"), value = "weapon" }, + } + + if Config.EnableLicenses then + elements2[#elements2 + 1] = { + icon = "fas fa-scroll", + title = TranslateCap("license_check"), + value = "license", + } + end + + ESX.OpenContext("right", elements2, function(menu2, element2) + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + if closestPlayer ~= -1 and closestDistance <= 3.0 then + local data2 = { current = element2 } + local action = data2.current.value + + if action == "identity_card" then + OpenIdentityCardMenu(closestPlayer) + elseif action == "search" then + OpenBodySearchMenu(closestPlayer) + elseif action == "handcuff" then + TriggerServerEvent("esx_cuffanimation:startArrest", GetPlayerServerId(closestPlayer)) + Citizen.Wait(3100) + TriggerServerEvent("bpt_ammujob:handcuff", GetPlayerServerId(closestPlayer)) + elseif action == "drag" then + TriggerServerEvent("bpt_ammujob:drag", GetPlayerServerId(closestPlayer)) + elseif action == "put_in_vehicle" then + TriggerServerEvent("bpt_ammujob:putInVehicle", GetPlayerServerId(closestPlayer)) + elseif action == "out_the_vehicle" then + TriggerServerEvent("bpt_ammujob:OutVehicle", GetPlayerServerId(closestPlayer)) + elseif action == "fine" then + OpenFineMenu(closestPlayer) + elseif action == "weapon" then + TriggerServerEvent("esx_license:addLicense", GetPlayerServerId(closestPlayer), "weapon") + ESX.ShowNotification(TranslateCap("released_gun_licence")) + TriggerServerEvent("bpt_ammujob:message", GetPlayerServerId(closestDistance), TranslateCap("received_firearms_license")) + elseif action == "license" then + ShowPlayerLicense(closestPlayer) + end + else + ESX.ShowNotification(TranslateCap("no_players_nearby")) + end + end, function() + OpenAmmuActionsMenu() end) - elseif element.value == "wear_work" then - ESX.TriggerServerCallback("esx_skin:getPlayerSkin", function(skin, jobSkin) - if skin.sex == 0 then - TriggerEvent("skinchanger:loadClothes", skin, jobSkin.skin_male) + elseif data.current.value == "vehicle_interaction" then + local elements3 = { + { unselectable = true, icon = "fas fa-car", title = element.title }, + } + local playerPed = PlayerPedId() + local vehicle = ESX.Game.GetVehicleInDirection() + + if DoesEntityExist(vehicle) then + elements3[#elements3 + 1] = { icon = "fas fa-car", title = TranslateCap("vehicle_info"), value = "vehicle_infos" } + elements3[#elements3 + 1] = { icon = "fas fa-car", title = TranslateCap("pick_lock"), value = "hijack_vehicle" } + elements3[#elements3 + 1] = { icon = "fas fa-car", title = TranslateCap("impound"), value = "impound" } + end + + elements3[#elements3 + 1] = { + icon = "fas fa-scroll", + title = TranslateCap("search_database"), + value = "search_database", + } + + ESX.OpenContext("right", elements3, function(menu3, element3) + local data2 = { current = element3 } + local coords = GetEntityCoords(playerPed) + vehicle = ESX.Game.GetVehicleInDirection() + local action = data2.current.value + + if action == "search_database" then + LookupVehicle(element3) + 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) + Wait(20000) + ClearPedTasksImmediately(playerPed) + + SetVehicleDoorsLocked(vehicle, 1) + SetVehicleDoorsLockedForAllPlayers(vehicle, false) + ESX.ShowNotification(TranslateCap("vehicle_unlocked")) + end + elseif action == "impound" then + if currentTask.busy then + return + end + + ESX.ShowHelpNotification(TranslateCap("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) + Wait(100) + end) + + CreateThread(function() + while currentTask.busy do + Wait(1000) + + vehicle = GetClosestVehicle(coords.x, coords.y, coords.z, 3.0, 0, 71) + if not DoesEntityExist(vehicle) and currentTask.busy then + ESX.ShowNotification(TranslateCap("impound_canceled_moved")) + ESX.ClearTimeout(currentTask.task) + ClearPedTasks(playerPed) + currentTask.busy = false + break + end + end + end) + end else - TriggerEvent("skinchanger:loadClothes", skin, jobSkin.skin_female) + ESX.ShowNotification(TranslateCap("no_vehicles_nearby")) end + end, function() + OpenAmmuActionsMenu() + end) + elseif data.current.value == "object_spawner" then + + ESX.OpenContext("right", elements4, function(menu4, element4) + local data2 = { current = element4 } + 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) + Wait(100) + SetEntityHeading(obj, GetEntityHeading(playerPed)) + PlaceObjectOnGroundProperly(obj) + end) + end, function() + OpenAmmuActionsMenu() end) end - ESX.CloseContext() - end, function() - CurrentAction = "cloakroom" - CurrentActionMsg = TranslateCap("cloakroom_prompt") - CurrentActionData = {} end) end -function OpenVehicleSpawnerMenu() - local elements = { - { unselectable = true, icon = "fas fa-car", title = TranslateCap("spawn_veh") }, - } +function OpenIdentityCardMenu(player) + ESX.TriggerServerCallback("bpt_ammujob:getOtherPlayerData", function(data) + local elements = { + { icon = "fas fa-user", title = TranslateCap("name", data.name) }, + { icon = "fas fa-user", title = TranslateCap("job", ("%s - %s"):format(data.job, data.grade)) }, + } - if Config.EnableSocietyOwnedVehicles then - ESX.TriggerServerCallback("bpt_society:getVehiclesInGarage", function(vehicles) - if #vehicles == 0 then - ESX.ShowNotification(TranslateCap("empty_garage")) - return - end + if Config.EnableESXIdentity then + elements[#elements + 1] = { icon = "fas fa-user", title = TranslateCap("sex", TranslateCap(data.sex)) } + elements[#elements + 1] = { icon = "fas fa-user", title = TranslateCap("sex", TranslateCap(data.sex)) } + elements[#elements + 1] = { icon = "fas fa-user", title = TranslateCap("height", data.height) } + end - for i = 1, #vehicles, 1 do - elements[#elements + 1] = { - icon = "fas fa-car", - title = GetDisplayNameFromVehicleModel(vehicles[i].model) .. " [" .. vehicles[i].plate .. "]", - value = vehicles[i], - } + if Config.EnableESXOptionalneeds and data.drunk then + elements[#elements + 1] = { title = TranslateCap("bac", data.drunk) } + end + + if data.licenses then + elements[#elements + 1] = { title = TranslateCap("license_label") } + + for i = 1, #data.licenses, 1 do + elements[#elements + 1] = { title = data.licenses[i].label } end + end - ESX.OpenContext("right", elements, function(_, element) - if not ESX.Game.IsSpawnPointClear(Config.Zones.VehicleSpawnPoint.Pos, 5.0) then - ESX.ShowNotification(TranslateCap("spawnpoint_blocked")) - return - end + ESX.OpenContext("right", elements, nil, function(menu) + OpenAmmuActionsMenu() + end) + end, GetPlayerServerId(player)) +end - if element.value == nil then - print("ERROR: Context menu clicked item value is nil!") - return - end +function OpenBodySearchMenu(player) + if Config.OxInventory then + ESX.CloseContext() + exports.ox_inventory:openInventory("player", GetPlayerServerId(player)) + return + end - local vehicleProps = element.value - ESX.TriggerServerCallback("bpt_ammujob:SpawnVehicle", function() - return - end, vehicleProps.model, vehicleProps) - TriggerServerEvent("bpt_society:removeVehicleFromGarage", "ammu", vehicleProps) - end, function() - CurrentAction = "vehicle_spawner" - CurrentActionMsg = TranslateCap("spawner_prompt") - CurrentActionData = {} - end) - end, "ammu") - else -- not society vehicles - if #Config.AuthorizedVehicles == 0 then - ESX.ShowNotification(TranslateCap("empty_garage")) - return + ESX.TriggerServerCallback("bpt_ammujob:getOtherPlayerData", function(data) + local elements = { + { unselectable = true, icon = "fas fa-user", title = TranslateCap("search") }, + } + + for i = 1, #data.accounts, 1 do + if data.accounts[i].name == "black_money" and data.accounts[i].money > 0 then + elements[#elements + 1] = { + icon = "fas fa-money", + title = TranslateCap("confiscate_dirty", ESX.Math.Round(data.accounts[i].money)), + value = "black_money", + itemType = "item_account", + amount = data.accounts[i].money, + } + break + end end - for i = 1, #Config.AuthorizedVehicles, 1 do + table.insert(elements, { label = TranslateCap("guns_label") }) + + for i = 1, #data.weapons, 1 do elements[#elements + 1] = { - icon = "fas fa-car", - title = Config.AuthorizedVehicles[i].label, - value = Config.AuthorizedVehicles[i].model, + icon = "fas fa-gun", + title = TranslateCap("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 - ESX.OpenContext("right", elements, function(_, element) - if not ESX.Game.IsSpawnPointClear(Config.Zones.VehicleSpawnPoint.Pos, 5.0) then - ESX.ShowNotification(TranslateCap("spawnpoint_blocked")) - return + elements[#elements + 1] = { title = TranslateCap("inventory_label") } + + for i = 1, #data.inventory, 1 do + if data.inventory[i].count > 0 then + elements[#elements + 1] = { + icon = "fas fa-box", + title = TranslateCap("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 - if element.value == nil then - print("ERROR: Context menu clicked item value is nil!") - return + ESX.OpenContext("right", elements, function(_, element) + data = { current = element } + if data.current.value then + TriggerServerEvent("bpt_ammujob:confiscatePlayerItem", GetPlayerServerId(player), data.current.itemType, data.current.value, data.current.amount) + OpenBodySearchMenu(player) end + end) + end, GetPlayerServerId(player)) +end - ESX.TriggerServerCallback("bpt_ammujob:SpawnVehicle", function() - ESX.ShowNotification(TranslateCap("vehicle_spawned"), "success") - end, element.value, { plate = "AMMU JOB" }) - ESX.CloseContext() - end, function() - CurrentAction = "vehicle_spawner" - CurrentActionMsg = TranslateCap("spawner_prompt") - CurrentActionData = {} +function OpenFineMenu(player) + if Config.EnableFinePresets then + local elements = { + { unselectable = true, icon = "fas fa-scroll", title = TranslateCap("fine") }, + { icon = "fas fa-scroll", title = TranslateCap("traffic_offense"), value = 0 }, + { icon = "fas fa-scroll", title = TranslateCap("minor_offense"), value = 1 }, + { icon = "fas fa-scroll", title = TranslateCap("average_offense"), value = 2 }, + { icon = "fas fa-scroll", title = TranslateCap("major_offense"), value = 3 }, + } + + ESX.OpenContext("right", elements, function(_, element) + local data = { current = element } + OpenFineCategoryMenu(player, data.current.value) end) + else + ESX.CloseContext() + ESX.CloseContext() + OpenFineTextInput(player) end end -function DeleteJobVehicle() - if Config.EnableSocietyOwnedVehicles then - local vehicleProps = ESX.Game.GetVehicleProperties(CurrentActionData.vehicle) - TriggerServerEvent("bpt_society:putVehicleInGarage", "ammu", vehicleProps) - ESX.Game.DeleteVehicle(CurrentActionData.vehicle) - else - if IsInAuthorizedVehicle() then - ESX.Game.DeleteVehicle(CurrentActionData.vehicle) +local fineList = {} +function OpenFineCategoryMenu(player, category) + if not fineList[category] then + local p = promise.new() - if Config.MaxInService ~= -1 then - TriggerServerEvent("esx_service:disableService", "ammu") - end - else - ESX.ShowNotification(TranslateCap("only_ammu")) - end + ESX.TriggerServerCallback("bpt_ammujob:getFineList", function(fines) + p:resolve(fines) + end, category) + + fineList[category] = Citizen.Await(p) end -end -function OpenAmmuActionsMenu() local elements = { - { unselectable = true, icon = "fas fa-ammu", title = TranslateCap("ammu") }, - { icon = "fas fa-box", title = TranslateCap("deposit_stock"), value = "put_stock" }, - { icon = "fas fa-box", title = TranslateCap("take_stock"), value = "get_stock" }, + { unselectable = true, icon = "fas fa-scroll", title = TranslateCap("fine") }, } - if Config.EnablePlayerManagement and ESX.PlayerData.job ~= nil and ESX.PlayerData.job.grade_name == "boss" then + for _, fine in ipairs(fineList[category]) do elements[#elements + 1] = { - icon = "fas fa-wallet", - title = TranslateCap("boss_actions"), - value = "boss_actions", + icon = "fas fa-scroll", + title = ('%s %s'):format(fine.label, TranslateCap("armory_item", ESX.Math.GroupDigits(fine.amount))), + value = fine.id, + amount = fine.amount, + fineLabel = fine.label, } end - ESX.OpenContext("right", elements, function(_, element) - if Config.OxInventory and (element.value == "put_stock" or element.value == "get_stock") then - exports.ox_inventory:openInventory("stash", "society_ammu") - return ESX.CloseContext() - elseif element.value == "put_stock" then - OpenPutStocksMenu() - elseif element.value == "get_stock" then - OpenGetStocksMenu() - elseif element.value == "boss_actions" then - TriggerEvent("bpt_society:openBossMenu", "ammu", function(_, menu) - menu.close() + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + if Config.EnablePlayerManagement then + TriggerServerEvent("bpt_billing:sendBill", GetPlayerServerId(player), "society_ammu", TranslateCap("fine_total", data.current.fineLabel), data.current.amount) + else + TriggerServerEvent("bpt_billing:sendBill", GetPlayerServerId(player), "", TranslateCap("fine_total", data.current.fineLabel), data.current.amount) + end + + ESX.SetTimeout(300, function() + OpenFineCategoryMenu(player, category) + end) + end) +end + +function OpenFineTextInput(player) + Citizen.CreateThread(function() + local amount = 0 + local reason = "" + AddTextEntry("FMMC_KEY_TIP1", TranslateCap("fine_enter_amount")) + Citizen.Wait(0) + DisplayOnscreenKeyboard(1, "FMMC_KEY_TIP1", "", "", "", "", "", 30) + while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do + Citizen.Wait(0) + end + if UpdateOnscreenKeyboard() ~= 2 then + amount = tonumber(GetOnscreenKeyboardResult()) + if amount == nil or amount <= 0 then + ESX.ShowNotification(TranslateCap("invalid_amount")) + return + end + end + AddTextEntry("FMMC_KEY_TIP1", TranslateCap("fine_enter_text")) + Citizen.Wait(0) + DisplayOnscreenKeyboard(1, "FMMC_KEY_TIP1", "", "", "", "", "", 120) + while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do + Citizen.Wait(0) + end + if UpdateOnscreenKeyboard() ~= 2 then + reason = GetOnscreenKeyboardResult() + end + Citizen.Wait(500) + TriggerServerEvent("bpt_billing:sendBill", GetPlayerServerId(player), "society_ammu", reason, amount) + OpenAmmuActionsMenu() + end) +end + +function LookupVehicle(elementF) + local elements = { + { unselectable = true, icon = "fas fa-car", title = elementF.title }, + { title = TranslateCap("search_plate"), input = true, inputType = "text", inputPlaceholder = "ABC 123" }, + { icon = "fas fa-check-double", title = TranslateCap("lookup_plate"), value = "lookup" }, + } + + ESX.OpenContext("right", elements, function(menu, element) + local data = { value = menu.eles[2].inputValue } + local length = string.len(data.value) + if not data.value or length < 2 or length > 8 then + ESX.ShowNotification(TranslateCap("search_database_error_invalid")) + else + ESX.TriggerServerCallback("bpt_ammujob:getVehicleInfos", function(retrivedInfo) + elements = { + { unselectable = true, icon = "fas fa-car", title = element.title }, + { unselectable = true, icon = "fas fa-car", title = TranslateCap("plate", retrivedInfo.plate) }, + } + + if not retrivedInfo.owner then + elements[#elements + 1] = { unselectable = true, icon = "fas fa-user", title = TranslateCap("owner_unknown") } + else + elements[#elements + 1] = { unselectable = true, icon = "fas fa-user", title = TranslateCap("owner", retrivedInfo.owner) } + end + + ESX.OpenContext("right", elements, nil, function() + OpenAmmuActionsMenu() + end) + end, data.value) + end + end) +end + +function ShowPlayerLicense(player) + local elements = { + { unselectable = true, icon = "fas fa-scroll", title = TranslateCap("license_revoke") }, + } + + ESX.TriggerServerCallback("bpt_ammujob: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 + elements[#elements + 1] = { + icon = "fas fa-scroll", + title = playerData.licenses[i].label, + type = playerData.licenses[i].type, + } + end + end + end + + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + ESX.ShowNotification(TranslateCap("licence_you_revoked", data.current.label, playerData.name)) + TriggerServerEvent("bpt_ammujob:message", GetPlayerServerId(player), TranslateCap("license_revoked", data.current.label)) + + TriggerServerEvent("esx_license:removeLicense", GetPlayerServerId(player), data.current.type) + + ESX.SetTimeout(300, function() + ShowPlayerLicense(player) end) + end) + end, GetPlayerServerId(player)) +end + +function OpenVehicleInfosMenu(vehicleData) + ESX.TriggerServerCallback("bpt_ammujob:getVehicleInfos", function(retrivedInfo) + local elements = { + { unselectable = true, icon = "fas fa-car", title = TranslateCap("vehicle_info") }, + { icon = "fas fa-car", title = TranslateCap("plate", retrivedInfo.plate) }, + } + + if not retrivedInfo.owner then + elements[#elements + 1] = { unselectable = true, icon = "fas fa-user", title = TranslateCap("owner_unknown") } + else + elements[#elements + 1] = { unselectable = true, icon = "fas fa-user", title = TranslateCap("owner", retrivedInfo.owner) } end - end, function() - CurrentAction = "ammu_actions_menu" - CurrentActionMsg = TranslateCap("press_to_open") - CurrentActionData = {} + + ESX.OpenContext("right", elements, nil, nil) + end, vehicleData.plate) +end + +function OpenGetWeaponMenu() + ESX.TriggerServerCallback("bpt_ammujob:getArmoryWeapons", function(weapons) + local elements = { + { unselectable = true, icon = "fas fa-gun", title = TranslateCap("get_weapon_menu") }, + } + + for i = 1, #weapons, 1 do + if weapons[i].count > 0 then + elements[#elements + 1] = { + icon = "fas fa-gun", + title = "x" .. weapons[i].count .. " " .. ESX.GetWeaponLabel(weapons[i].name), + value = weapons[i].name, + } + end + end + + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + ESX.TriggerServerCallback("bpt_ammujob:removeArmoryWeapon", function() + ESX.CloseContext() + OpenGetWeaponMenu() + end, data.current.value) + end) end) end -function OpenMobileAmmuActionsMenu() +function OpenPutWeaponMenu() local elements = { - { unselectable = true, icon = "fas fa-ammu", title = TranslateCap("ammu") }, - { icon = "fas fa-scroll", title = TranslateCap("billing"), value = "billing" }, + { unselectable = true, icon = "fas fa-gun", title = TranslateCap("put_weapon_menu") }, } + local playerPed = PlayerPedId() + local weaponList = ESX.GetWeaponList() + + for i = 1, #weaponList, 1 do + local weaponHash = joaat(weaponList[i].name) + + if HasPedGotWeapon(playerPed, weaponHash, false) and weaponList[i].name ~= "WEAPON_UNARMED" then + elements[#elements + 1] = { + icon = "fas fa-gun", + title = weaponList[i].label, + value = weaponList[i].name, + } + end + end + + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + ESX.TriggerServerCallback("bpt_ammujob:addArmoryWeapon", function() + ESX.CloseContext() + OpenPutWeaponMenu() + end, data.current.value, true) + end) +end + +function OpenGetStocksMenu() + ESX.TriggerServerCallback("bpt_ammujob:getStockItems", function(items) + local elements = { + { unselectable = true, icon = "fas fa-box", title = TranslateCap("ammu_stock") }, + } + + for i = 1, #items, 1 do + elements[#elements + 1] = { + icon = "fas fa-box", + title = "x" .. items[i].count .. " " .. items[i].label, + value = items[i].name, + } + end + + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + local itemName = data.current.value - ESX.OpenContext("right", elements, function(_, element) - if element.value == "billing" then local elements2 = { - { unselectable = true, icon = "fas fa-ammu", title = element.title }, + { unselectable = true, icon = "fas fa-box", title = element.title }, { - title = TranslateCap("amount"), + title = TranslateCap("quantity"), input = true, inputType = "number", inputMin = 1, - inputMax = 10000000, - inputPlaceholder = TranslateCap("bill_amount"), + inputMax = 150, + inputPlaceholder = TranslateCap("quantity_placeholder"), }, { icon = "fas fa-check-double", title = TranslateCap("confirm"), value = "confirm" }, } - ESX.OpenContext("right", elements2, function(menu2) - local amount = tonumber(menu2.eles[2].inputValue) - if amount == nil then - ESX.ShowNotification(TranslateCap("amount_invalid")) + ESX.OpenContext("right", elements2, function(menu2, element2) + local data2 = { value = menu2.eles[2].inputValue } + local count = tonumber(data2.value) + + if not count then + ESX.ShowNotification(TranslateCap("quantity_invalid")) else ESX.CloseContext() - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - if closestPlayer == -1 or closestDistance > 3.0 then - ESX.ShowNotification(TranslateCap("no_players_near")) - else - TriggerServerEvent("bpt_billing:sendBill", GetPlayerServerId(closestPlayer), "society_ammu", "Ammu", amount) - ESX.ShowNotification(TranslateCap("billing_sent")) - end + TriggerServerEvent("bpt_ammujob:getStockItem", itemName, count) + + Wait(300) + OpenGetStocksMenu() end end) + end) + end) +end + +function OpenPutStocksMenu() + ESX.TriggerServerCallback("bpt_ammujob:getPlayerInventory", function(inventory) + local elements = { + { unselectable = true, icon = "fas fa-box", title = TranslateCap("inventory") }, + } + + for i = 1, #inventory.items, 1 do + local item = inventory.items[i] + + if item.count > 0 then + elements[#elements + 1] = { + icon = "fas fa-box", + title = item.label .. " x" .. item.count, + type = "item_standard", + value = item.name, + } + end end + + ESX.OpenContext("right", elements, function(menu, element) + local data = { current = element } + local itemName = data.current.value + + local elements2 = { + { unselectable = true, icon = "fas fa-box", title = element.title }, + { + title = TranslateCap("quantity"), + input = true, + inputType = "number", + inputMin = 1, + inputMax = 150, + inputPlaceholder = TranslateCap("quantity_placeholder"), + }, + { icon = "fas fa-check-double", title = TranslateCap("confirm"), value = "confirm" }, + } + + ESX.OpenContext("right", elements2, function(menu2, element2) + local data2 = { value = menu2.eles[2].inputValue } + local count = tonumber(data2.value) + + if not count then + ESX.ShowNotification(TranslateCap("quantity_invalid")) + else + ESX.CloseContext() + TriggerServerEvent("bpt_ammujob:putStockItems", itemName, count) + + Wait(300) + OpenPutStocksMenu() + end + end) + end) end) end -function IsInAuthorizedVehicle() +AddEventHandler("bpt_ammujob:hasEnteredMarker", function(station, part, partNum) + if part == "Armory" then + CurrentAction = "menu_armory" + CurrentActionMsg = TranslateCap("open_armory") + CurrentActionData = { station = station } + elseif part == "Vehicles" then + CurrentAction = "menu_vehicle_spawner" + CurrentActionMsg = TranslateCap("garage_prompt") + CurrentActionData = { station = station, part = part, partNum = partNum } + elseif part == "BossActions" then + CurrentAction = "menu_boss_actions" + CurrentActionMsg = TranslateCap("open_bossmenu") + CurrentActionData = {} + end +end) + +AddEventHandler("bpt_ammujob:hasExitedMarker", function(station, part, partNum) + if not IsInShopMenu then + ESX.CloseContext() + end + + CurrentAction = nil +end) + +AddEventHandler("bpt_ammujob:hasEnteredEntityZone", function(entity) local playerPed = PlayerPedId() - local vehModel = GetEntityModel(GetVehiclePedIsIn(playerPed, false)) - for i = 1, #Config.AuthorizedVehicles, 1 do - if vehModel == joaat(Config.AuthorizedVehicles[i].model) then - return true + if ESX.PlayerData.job and ESX.PlayerData.job.name == "ammu" and IsPedOnFoot(playerPed) then + CurrentAction = "remove_entity" + CurrentActionMsg = TranslateCap("remove_prop") + CurrentActionData = { entity = entity } + end + + if GetEntityModel(entity) == `p_ld_stinger_s` then + playerPed = PlayerPedId() + local _ = 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) - return false -end +AddEventHandler("bpt_ammujob:hasExitedEntityZone", function(entity) + if CurrentAction == "remove_entity" then + CurrentAction = nil + end +end) -AddEventHandler("bpt_ammujob:hasEnteredMarker", function(zone) - if zone == "VehicleSpawner" then - CurrentAction = "vehicle_spawner" - CurrentActionMsg = TranslateCap("spawner_prompt") - CurrentActionData = {} - elseif zone == "VehicleDeleter" then +RegisterNetEvent("bpt_ammujob:handcuff") +AddEventHandler("bpt_ammujob:handcuff", function() + isHandcuffed = not isHandcuffed + local playerPed = PlayerPedId() + + if isHandcuffed then + RequestAnimDict("mp_arresting") + while not HasAnimDictLoaded("mp_arresting") do + Wait(100) + end + + TaskPlayAnim(playerPed, "mp_arresting", "idle", 8.0, -8, -1, 49, 0, 0, 0, 0) + RemoveAnimDict("mp_arresting") + + SetEnableHandcuffs(playerPed, true) + DisablePlayerFiring(playerPed, true) + SetCurrentPedWeapon(playerPed, `WEAPON_UNARMED`, true) -- unarm player + SetPedCanPlayGestureAnims(playerPed, false) + FreezeEntityPosition(playerPed, true) + DisplayRadar(false) + + if Config.EnableHandcuffTimer then + if handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + + StartHandcuffTimer() + end + else + if 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("bpt_ammujob:unrestrain") +AddEventHandler("bpt_ammujob:unrestrain", function() + if isHandcuffed then local playerPed = PlayerPedId() - local vehicle = GetVehiclePedIsIn(playerPed, false) + isHandcuffed = false - if IsPedInAnyVehicle(playerPed, false) and GetPedInVehicleSeat(vehicle, -1) == playerPed then - CurrentAction = "delete_vehicle" - CurrentActionMsg = TranslateCap("store_veh") - CurrentActionData = { - vehicle = vehicle, - } + ClearPedSecondaryTask(playerPed) + SetEnableHandcuffs(playerPed, false) + DisablePlayerFiring(playerPed, false) + SetPedCanPlayGestureAnims(playerPed, true) + FreezeEntityPosition(playerPed, false) + DisplayRadar(true) + + -- end timer + if Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) end - elseif zone == "AmmuActions" then - CurrentAction = "ammu_actions_menu" - CurrentActionMsg = TranslateCap("press_to_open") - CurrentActionData = {} - elseif zone == "Cloakroom" then - CurrentAction = "cloakroom" - CurrentActionMsg = TranslateCap("cloakroom_prompt") - CurrentActionData = {} end end) -AddEventHandler("bpt_ammujob:hasExitedMarker", function() - ESX.CloseContext() - CurrentAction = nil +RegisterNetEvent("bpt_ammujob:drag") +AddEventHandler("bpt_ammujob:drag", function(copId) + if isHandcuffed then + dragStatus.isDragged = not dragStatus.isDragged + dragStatus.CopId = copId + end +end) + +CreateThread(function() + local wasDragged + + while true do + local Sleep = 1500 + + if isHandcuffed and dragStatus.isDragged then + Sleep = 50 + local targetPed = GetPlayerPed(GetPlayerFromServerId(dragStatus.CopId)) + + if DoesEntityExist(targetPed) and IsPedOnFoot(targetPed) and not IsPedDeadOrDying(targetPed, true) then + if not wasDragged then + AttachEntityToEntity(ESX.PlayerData.ped, targetPed, 11816, 0.54, 0.54, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) + wasDragged = true + else + Wait(1000) + end + else + wasDragged = false + dragStatus.isDragged = false + DetachEntity(ESX.PlayerData.ped, true, false) + end + elseif wasDragged then + wasDragged = false + DetachEntity(ESX.PlayerData.ped, true, false) + end + Wait(Sleep) + end +end) + +RegisterNetEvent("bpt_ammujob:putInVehicle") +AddEventHandler("bpt_ammujob:putInVehicle", function() + if isHandcuffed then + local playerPed = PlayerPedId() + local vehicle, distance = ESX.Game.GetClosestVehicle() + + if vehicle and distance < 5 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) + +RegisterNetEvent("bpt_ammujob:OutVehicle") +AddEventHandler("bpt_ammujob:OutVehicle", function() + local GetVehiclePedIsIn = GetVehiclePedIsIn + local IsPedSittingInAnyVehicle = IsPedSittingInAnyVehicle + local TaskLeaveVehicle = TaskLeaveVehicle + if IsPedSittingInAnyVehicle(ESX.PlayerData.ped) then + local vehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false) + TaskLeaveVehicle(ESX.PlayerData.ped, vehicle, 64) + end +end) + +-- Handcuff +CreateThread(function() + local DisableControlAction = DisableControlAction + local IsEntityPlayingAnim = IsEntityPlayingAnim + while true do + local Sleep = 1000 + + if isHandcuffed then + Sleep = 0 + 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(ESX.PlayerData.ped, "mp_arresting", "idle", 3) ~= 1 then + ESX.Streaming.RequestAnimDict("mp_arresting", function() + TaskPlayAnim(ESX.PlayerData.ped, "mp_arresting", "idle", 8.0, -8, -1, 49, 0.0, false, false, false) + RemoveAnimDict("mp_arresting") + end) + end + end + Wait(Sleep) + end end) --- Create Blips +-- Create blips CreateThread(function() - local blip = AddBlipForCoord(Config.Zones.AmmuActions.Pos.x, Config.Zones.AmmuActions.Pos.y, Config.Zones.AmmuActions.Pos.z) + for _, v in pairs(Config.Ammu) do + local blip = AddBlipForCoord(v.Blip.Coords) - SetBlipSprite(blip, 156) - SetBlipDisplay(blip, 4) - SetBlipScale(blip, 1.0) - SetBlipColour(blip, 5) - SetBlipAsShortRange(blip, true) + SetBlipSprite(blip, v.Blip.Sprite) + SetBlipDisplay(blip, v.Blip.Display) + SetBlipScale(blip, v.Blip.Scale) + SetBlipColour(blip, v.Blip.Colour) + SetBlipAsShortRange(blip, true) - BeginTextCommandSetBlipName("STRING") - AddTextComponentSubstringPlayerName(TranslateCap("blip_ammu")) - EndTextCommandSetBlipName(blip) + BeginTextCommandSetBlipName("STRING") + AddTextComponentSubstringPlayerName(TranslateCap("map_blip")) + EndTextCommandSetBlipName(blip) + end end) --- Enter / Exit marker events, and draw markers +-- Draw markers and more CreateThread(function() while true do - local sleep = 1500 + local Sleep = 1500 if ESX.PlayerData.job and ESX.PlayerData.job.name == "ammu" then - local coords = GetEntityCoords(PlayerPedId()) - local isInMarker, currentZone = false - local inVeh = IsPedInAnyVehicle(PlayerPedId(), false) - - for k, v in pairs(Config.Zones) do - local zonePos = vector3(v.Pos.x, v.Pos.y, v.Pos.z) - local distance = #(coords - zonePos) - - if v.Type ~= -1 and distance < Config.DrawDistance then - sleep = 0 - if k == "VehicleDeleter" then - if inVeh then - DrawMarker(v.Type, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Size.x, v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, false, 2, v.Rotate, nil, nil, false) + Sleep = 500 + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + local isInMarker, hasExited = false, false + local currentStation, currentPart, currentPartNum + + for k, v in pairs(Config.Ammu) do + + for i = 1, #v.Armories, 1 do + local distance = #(playerCoords - v.Armories[i]) + + if distance < Config.DrawDistance then + DrawMarker(Config.MarkerType.Armories, v.Armories[i], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false) + Sleep = 0 + + if distance < Config.MarkerSize.x then + isInMarker, currentStation, currentPart, currentPartNum = true, k, "Armory", i + end + end + end + + for i = 1, #v.Vehicles, 1 do + local distance = #(playerCoords - v.Vehicles[i].Spawner) + + if distance < Config.DrawDistance then + DrawMarker(Config.MarkerType.Vehicles, v.Vehicles[i].Spawner, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false) + Sleep = 0 + + if distance < Config.MarkerSize.x then + isInMarker, currentStation, currentPart, currentPartNum = true, k, "Vehicles", i end - else - DrawMarker(v.Type, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Size.x, v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, false, 2, v.Rotate, nil, nil, false) end end - if distance < v.Size.x then - isInMarker, currentZone = true, k + if Config.EnablePlayerManagement and ESX.PlayerData.job.grade_name == "boss" then + for i = 1, #v.BossActions, 1 do + local distance = #(playerCoords - v.BossActions[i]) + + if distance < Config.DrawDistance then + DrawMarker(Config.MarkerType.BossActions, v.BossActions[i], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, true, false, false, false) + Sleep = 0 + + if distance < Config.MarkerSize.x then + isInMarker, currentStation, currentPart, currentPartNum = true, k, "BossActions", i + end + end + end end end - if (isInMarker and not HasAlreadyEnteredMarker) or (isInMarker and LastZone ~= currentZone) then - HasAlreadyEnteredMarker, LastZone = true, currentZone - TriggerEvent("bpt_ammujob:hasEnteredMarker", currentZone) + if isInMarker and not HasAlreadyEnteredMarker or (isInMarker and (LastStation ~= currentStation or LastPart ~= currentPart or LastPartNum ~= currentPartNum)) then + if (LastStation and LastPart and LastPartNum) and (LastStation ~= currentStation or LastPart ~= currentPart or LastPartNum ~= currentPartNum) then + TriggerEvent("bpt_ammujob:hasExitedMarker", LastStation, LastPart, LastPartNum) + hasExited = true + end + + HasAlreadyEnteredMarker = true + LastStation = currentStation + LastPart = currentPart + LastPartNum = currentPartNum + + TriggerEvent("bpt_ammujob:hasEnteredMarker", currentStation, currentPart, currentPartNum) end - if not isInMarker and HasAlreadyEnteredMarker then + if not hasExited and not isInMarker and HasAlreadyEnteredMarker then HasAlreadyEnteredMarker = false - TriggerEvent("bpt_ammujob:hasExitedMarker", LastZone) + TriggerEvent("bpt_ammujob:hasExitedMarker", LastStation, LastPart, LastPartNum) end end - Wait(sleep) + Wait(Sleep) end end) --- Key Controls +-- Enter / Exit entity zone events 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 - local sleep = 1500 - if CurrentAction and not ESX.PlayerData.dead then - sleep = 0 - ESX.ShowHelpNotification(CurrentActionMsg) + local Sleep = 1500 - if IsControlJustReleased(0, 38) and ESX.PlayerData.job and ESX.PlayerData.job.name == "ammu" then - if CurrentAction == "ammu_actions_menu" then - OpenAmmuActionsMenu() - elseif CurrentAction == "cloakroom" then - OpenCloakroom() - elseif CurrentAction == "vehicle_spawner" then - OpenVehicleSpawnerMenu() - elseif CurrentAction == "delete_vehicle" then - DeleteJobVehicle() + local GetEntityCoords = GetEntityCoords + local GetClosestObjectOfType = GetClosestObjectOfType + local DoesEntityExist = DoesEntityExist + local playerCoords = GetEntityCoords(ESX.PlayerData.ped) + + local closestDistance = -1 + local closestEntity = nil + + for i = 1, #trackedEntities, 1 do + local object = GetClosestObjectOfType(playerCoords, 3.0, trackedEntities[i], false, false, false) + + if DoesEntityExist(object) then + Sleep = 500 + local objCoords = GetEntityCoords(object) + local distance = #(playerCoords - objCoords) + + if closestDistance == -1 or closestDistance > distance then + closestDistance = distance + closestEntity = object end + end + end - CurrentAction = nil + if closestDistance ~= -1 and closestDistance <= 3.0 then + if LastEntity ~= closestEntity then + TriggerEvent("bpt_ammujob:hasEnteredEntityZone", closestEntity) + LastEntity = closestEntity + end + else + if LastEntity then + TriggerEvent("bpt_ammujob:hasExitedEntityZone", LastEntity) + LastEntity = nil end end - Wait(sleep) + Wait(Sleep) end end) -RegisterCommand("ammumenu", function() - if not ESX.PlayerData.dead and Config.EnablePlayerManagement and ESX.PlayerData.job and ESX.PlayerData.job.name == "ammu" then - OpenMobileAmmuActionsMenu() +ESX.RegisterInput("ammu:interact", "(BPT AmmuJob) " .. TranslateCap("interaction"), "keyboard", "E", function() + if not CurrentAction then + return + end + + if not ESX.PlayerData.job or (ESX.PlayerData.job and not ESX.PlayerData.job.name == "ammu") then + return end -end, false) + if CurrentAction == "menu_armory" then + if not Config.EnableESXService then + OpenArmoryMenu(CurrentActionData.station) + elseif playerInService then + OpenArmoryMenu(CurrentActionData.station) + else + ESX.ShowNotification(TranslateCap("service_not")) + end + elseif CurrentAction == "menu_vehicle_spawner" then + if not Config.EnableESXService then + OpenVehicleSpawnerMenu("car", CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum) + elseif playerInService then + OpenVehicleSpawnerMenu("car", CurrentActionData.station, CurrentActionData.part, CurrentActionData.partNum) + else + ESX.ShowNotification(TranslateCap("service_not")) + end + elseif CurrentAction == "delete_vehicle" then + ESX.Game.DeleteVehicle(CurrentActionData.vehicle) + elseif CurrentAction == "menu_boss_actions" then + ESX.CloseContext() + TriggerEvent("bpt_society:openBossMenu", "ammu", function(data, menu) + ESX.CloseContext() -RegisterKeyMapping("ammumenu", "Open Ammu Menu", "keyboard", "f6") + CurrentAction = "menu_boss_actions" + CurrentActionMsg = TranslateCap("open_bossmenu") + CurrentActionData = {} + end) + elseif CurrentAction == "remove_entity" then + DeleteEntity(CurrentActionData.entity) + end + + CurrentAction = nil +end) + +ESX.RegisterInput("ammu:quickactions", "(BPT AmmuJob) " .. TranslateCap("quick_actions"), "keyboard", "F6", function() + if not ESX.PlayerData.job or (ESX.PlayerData.job.name ~= "ammu") or isDead then + return + end + + if not Config.EnableESXService then + OpenAmmuActionsMenu() + elseif playerInService then + OpenAmmuActionsMenu() + else + ESX.ShowNotification(TranslateCap("service_not")) + end +end) + +CreateThread(function() + while true do + local Sleep = 1000 + + if CurrentAction then + Sleep = 0 + ESX.ShowHelpNotification(CurrentActionMsg) + end + Wait(Sleep) + end +end) + +-- Create blip for colleagues +function CreateBlip(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 + +AddEventHandler("esx:onPlayerSpawn", function(spawn) + isDead = false + TriggerEvent("bpt_ammujob:unrestrain") + + if not hasAlreadyJoined then + TriggerServerEvent("bpt_ammujob:spawned") + end + hasAlreadyJoined = true +end) + +AddEventHandler("esx:onPlayerDeath", function(data) + isDead = true +end) + +AddEventHandler("onResourceStop", function(resource) + if resource == GetCurrentResourceName() then + TriggerEvent("bpt_ammujob:unrestrain") + + if Config.EnableESXService then + TriggerServerEvent("esx_service:disableService", "ammu") + end + + if Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + end +end) + +-- handcuff timer, unrestrain the player after an certain amount of time +function StartHandcuffTimer() + if Config.EnableHandcuffTimer and handcuffTimer.active then + ESX.ClearTimeout(handcuffTimer.task) + end + + handcuffTimer.active = true + + handcuffTimer.task = ESX.SetTimeout(Config.HandcuffTimer, function() + ESX.ShowNotification(TranslateCap("unrestrained_timer")) + TriggerEvent("bpt_ammujob:unrestrain") + handcuffTimer.active = false + end) +end + +-- TODO +-- - return to garage if owned +-- - message owner that his vehicle has been impounded +function ImpoundVehicle(vehicle) + --local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(GetEntityModel(vehicle))) + ESX.Game.DeleteVehicle(vehicle) + ESX.ShowNotification(TranslateCap("impound_successful")) + currentTask.busy = false +end diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/client/vehicle.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/client/vehicle.lua new file mode 100644 index 000000000..646a2cea2 --- /dev/null +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/client/vehicle.lua @@ -0,0 +1,320 @@ +---@diagnostic disable: undefined-global + +local spawnedVehicles = {} + +function OpenVehicleSpawnerMenu(type, station, part, partNum) + local playerCoords = GetEntityCoords(PlayerPedId()) + local elements = { + { unselectable = true, icon = "fas fa-car", title = TranslateCap("garage_title") }, + { icon = "fas fa-car", title = TranslateCap("garage_storeditem"), action = "garage" }, + { icon = "fas fa-car", title = TranslateCap("garage_storeitem"), action = "store_garage" }, + { icon = "fas fa-car", title = TranslateCap("garage_buyitem"), action = "buy_vehicle" }, + } + + ESX.OpenContext("right", elements, function(menu, element) + if element.action == "buy_vehicle" then + local shopElements = {} + local shopCoords = Config.Ammu[station][part][partNum].InsideShop + local authorizedVehicles = Config.AuthorizedVehicles[type][ESX.PlayerData.job.grade_name] + + if authorizedVehicles then + if #authorizedVehicles > 0 then + for _, vehicle in ipairs(authorizedVehicles) do + if IsModelInCdimage(vehicle.model) then + local vehicleLabel = GetLabelText(GetDisplayNameFromVehicleModel(vehicle.model)) + + shopElements[#shopElements + 1] = { + icon = "fas fa-car", + title = ('%s - %s'):format(vehicleLabel, TranslateCap("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 + OpenShopMenu(shopElements, playerCoords, shopCoords) + else + ESX.ShowNotification(TranslateCap("garage_notauthorized")) + end + else + ESX.ShowNotification(TranslateCap("garage_notauthorized")) + end + else + ESX.ShowNotification(TranslateCap("garage_notauthorized")) + end + elseif element.action == "garage" then + local garage = { + { unselectable = true, icon = "fas fa-car", title = "Garage" }, + } + + ESX.TriggerServerCallback("esx_vehicleshop:retrieveJobVehicles", function(jobVehicles) + if #jobVehicles > 0 then + local allVehicleProps = {} + + for _, 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 == 1 or v.stored == true then + label = label .. ('%s'):format(TranslateCap("garage_stored")) + elseif v.stored == 0 or v.stored == false then + label = label .. ('%s'):format(TranslateCap("garage_notstored")) + end + + garage[#garage + 1] = { + icon = "fas fa-car", + title = label, + stored = v.stored, + model = props.model, + plate = props.plate, + } + + allVehicleProps[props.plate] = props + end + end + + if #garage > 0 then + ESX.OpenContext("right", garage, function(menuG, elementG) + if elementG.stored == 1 or elementG.stored == true then + local foundSpawn, spawnPoint = GetAvailableVehicleSpawnPoint(station, part, partNum) + + if foundSpawn then + ESX.CloseContext() + + ESX.Game.SpawnVehicle(elementG.model, spawnPoint.coords, spawnPoint.heading, function(vehicle) + local vehicleProps = allVehicleProps[elementG.plate] + ESX.Game.SetVehicleProperties(vehicle, vehicleProps) + + TriggerServerEvent("esx_vehicleshop:setJobVehicleState", elementG.plate, false) + ESX.ShowNotification(TranslateCap("garage_released")) + end) + end + else + ESX.ShowNotification(TranslateCap("garage_notavailable")) + end + end) + else + ESX.ShowNotification(TranslateCap("garage_empty")) + end + else + ESX.ShowNotification(TranslateCap("garage_empty")) + end + end, type) + elseif element.action == "store_garage" then + StoreNearbyVehicle(playerCoords) + end + end) +end + +function StoreNearbyVehicle(playerCoords) + local vehicles, plates, index = ESX.Game.GetVehiclesInArea(playerCoords, 30.0), {}, {} + + if next(vehicles) then + for i = 1, #vehicles do + local vehicle = vehicles[i] + + -- Make sure the vehicle we're saving is empty, or else it won't be deleted + if GetVehicleNumberOfPassengers(vehicle) == 0 and IsVehicleSeatFree(vehicle, -1) then + local plate = ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)) + plates[#plates + 1] = plate + index[plate] = vehicle + end + end + else + ESX.ShowNotification(TranslateCap("garage_store_nearby")) + return + end + + ESX.TriggerServerCallback("bpt_ammujob:storeNearbyVehicle", function(plate) + if plate then + local vehicleId = index[plate] + local attempts = 0 + ESX.Game.DeleteVehicle(vehicleId) + local isBusy = true + + CreateThread(function() + BeginTextCommandBusyspinnerOn("STRING") + AddTextComponentSubstringPlayerName(TranslateCap("garage_storing")) + EndTextCommandBusyspinnerOn(4) + + while isBusy do + Wait(100) + end + + BusyspinnerOff() + end) + + -- Workaround for vehicle not deleting when other players are near it. + while DoesEntityExist(vehicleId) do + 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 i = 1, #vehicles do + local vehicle = vehicles[i] + if ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)) == plate then + ESX.Game.DeleteVehicle(vehicle) + break + end + end + end + end + + isBusy = false + ESX.ShowNotification(TranslateCap("garage_has_stored")) + else + ESX.ShowNotification(TranslateCap("garage_has_notstored")) + end + end, plates) +end + +function GetAvailableVehicleSpawnPoint(station, part, partNum) + local spawnPoints = Config.Ammu[station][part][partNum].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(TranslateCap("vehicle_blocked")) + return false + end +end + +function OpenShopMenu(elements, restoreCoords, shopCoords) + local playerPed = PlayerPedId() + IsInShopMenu = true + ESX.OpenContext("right", elements, function(menu, element) + local elements2 = { + { unselectable = true, icon = "fas fa-car", title = element.title }, + { icon = "fas fa-eye", title = TranslateCap("view"), value = "view" }, + } + + ESX.OpenContext("right", elements2, function(menu2, element2) + if element2.value == "view" then + DeleteSpawnedVehicles() + WaitForVehicleToLoad(element.model) + + ESX.Game.SpawnLocalVehicle(element.model, shopCoords, 0.0, function(vehicle) + table.insert(spawnedVehicles, vehicle) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + FreezeEntityPosition(vehicle, true) + SetModelAsNoLongerNeeded(element.model) + + if element.props then + ESX.Game.SetVehicleProperties(vehicle, element.props) + end + end) + + local elements3 = { + { unselectable = true, icon = "fas fa-car", title = element.title }, + { icon = "fas fa-check-double", title = TranslateCap("buy_car"), value = "buy" }, + { icon = "fas fa-eye", title = TranslateCap("stop_view"), value = "stop" }, + } + + ESX.OpenContext("right", elements3, function(menu3, element3) + if element3.value == "stop" then + IsInShopMenu = false + ESX.CloseContext() + + DeleteSpawnedVehicles() + FreezeEntityPosition(playerPed, false) + SetEntityVisible(PlayerPedId(), true, true) + + ESX.Game.Teleport(playerPed, restoreCoords) + elseif element3.value == "buy" then + local newPlate = exports["esx_vehicleshop"]:GeneratePlate() + local vehicle = GetVehiclePedIsIn(playerPed, false) + local props = ESX.Game.GetVehicleProperties(vehicle) + props.plate = newPlate + + ESX.TriggerServerCallback("bpt_ammujob:buyJobVehicle", function(bought) + if bought then + ESX.ShowNotification(TranslateCap("vehicleshop_bought", element.name, ESX.Math.GroupDigits(element.price))) + + IsInShopMenu = false + ESX.CloseContext() + DeleteSpawnedVehicles() + FreezeEntityPosition(playerPed, false) + SetEntityVisible(PlayerPedId(), true, true) + + ESX.Game.Teleport(playerPed, restoreCoords) + else + ESX.ShowNotification(TranslateCap("vehicleshop_money")) + ESX.CloseContext() + end + end, props, element.type) + end + end, function() + IsInShopMenu = false + ESX.CloseContext() + + DeleteSpawnedVehicles() + FreezeEntityPosition(playerPed, false) + SetEntityVisible(PlayerPedId(), true, true) + + ESX.Game.Teleport(playerPed, restoreCoords) + end) + end + end) + end) +end + +CreateThread(function() + while true do + Wait(0) + + if IsInShopMenu then + DisableControlAction(0, 75, true) -- Disable exit vehicle + DisableControlAction(27, 75, true) -- Disable exit vehicle + else + Wait(500) + end + end +end) + +function DeleteSpawnedVehicles() + while #spawnedVehicles > 0 do + local vehicle = spawnedVehicles[1] + ESX.Game.DeleteVehicle(vehicle) + table.remove(spawnedVehicles, 1) + end +end + +function WaitForVehicleToLoad(modelHash) + modelHash = (type(modelHash) == "number" and modelHash or joaat(modelHash)) + + if not HasModelLoaded(modelHash) then + RequestModel(modelHash) + + BeginTextCommandBusyspinnerOn("STRING") + AddTextComponentSubstringPlayerName(TranslateCap("vehicleshop_awaiting_model")) + EndTextCommandBusyspinnerOn(4) + + while not HasModelLoaded(modelHash) do + Wait(0) + DisableAllControlActions(0) + end + + BusyspinnerOff() + end +end diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/config.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/config.lua index 8975d374e..286cff102 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/config.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/config.lua @@ -1,54 +1,85 @@ +---@diagnostic disable: undefined-global Config = {} + Config.DrawDistance = 10.0 -- How close do you need to be for the markers to be drawn (in GTA units). -Config.MaxInService = -1 -- How much people can be in service at once? -Config.EnablePlayerManagement = true -- Enable society managing. -Config.EnableSocietyOwnedVehicles = false -Config.Locale = "it" +Config.MarkerType = { Armories = 21, BossActions = 22, Vehicles = 36 } +Config.MarkerSize = { x = 1.5, y = 1.5, z = 0.5 } +Config.MarkerColor = { r = 50, g = 50, b = 204 } +Config.EnablePlayerManagement = true -- Enable if you want society managing. +Config.EnableArmoryManagement = false +Config.EnableESXIdentity = true -- Enable if you're using esx_identity. +Config.EnableESXOptionalneeds = false -- Enable if you're using esx_optionalneeds +Config.EnableLicenses = true -- 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 minutes. +Config.EnableESXService = false -- Enable esx service? +Config.MaxInService = -1 -- How many people can be in service at once? Set as -1 to have no limit +Config.EnableFinePresets = false -- Set to false to use a custom input fields for fines +Config.Locale = GetConvar("esx:locale", "it") Config.OxInventory = ESX.GetConfig().OxInventory -Config.AuthorizedVehicles = { - { model = "rumpo", label = "Rumpo" }, -} +Config.Ammu = { -Config.Zones = { + AMMU = { - VehicleSpawner = { - Pos = { x = 821.340637, y = -2146.417480, z = 28.706909 }, - Size = { x = 1.0, y = 1.0, z = 1.0 }, - Color = { r = 145, g = 30, b = 30 }, - Type = 36, - Rotate = true, - }, + Blip = { + Coords = vector3(425.1, -979.5, 30.7), + Sprite = 60, + Display = 4, + Scale = 1.2, + Colour = 29, + }, - VehicleSpawnPoint = { - Pos = { x = 822.540649, y = -2134.575928, z = 29.279907 }, - Size = { x = 1.5, y = 1.5, z = 1.0 }, - Type = -1, - Rotate = false, - Heading = 225.0, - }, + Armories = { + vector3(487.239563, -996.949463, 30.678345), + }, - VehicleDeleter = { - Pos = { x = 822.540649, y = -2134.575928, z = 28.279907 }, - Size = { x = 3.0, y = 3.0, z = 0.25 }, - Color = { r = 255, g = 0, b = 0 }, - Type = 1, - Rotate = false, - }, + Vehicles = { + { + Spawner = vector3(454.6, -1017.4, 28.4), + InsideShop = vector3(444.553833, -1019.498901, 28.605835), + 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 }, + }, + }, + }, - AmmuActions = { - Pos = { x = 812.479126, y = -2159.182373, z = 29.616821 }, - Size = { x = 0.5, y = 0.5, z = 0.5 }, - Color = { r = 204, g = 204, b = 0 }, - Type = 20, - Rotate = true, + BossActions = { + vector3(824.742859, -2150.386719, 29.616821), + }, }, +} + +Config.AuthorizedVehicles = { + car = { + apprentice = {}, + + gunsmith = { + { model = "police3", price = 20000 }, + }, + + armorychief = { + { model = "policet", price = 18500 }, + }, + + deputydirector = { + { model = "riot", price = 70000 }, + }, - Cloakroom = { - Pos = { x = 810.065918, y = -2162.439453, z = 29.616821 }, - Size = { x = 0.5, y = 0.5, z = 0.5 }, - Color = { r = 204, g = 204, b = 0 }, - Type = 21, - Rotate = true, + boss = { + { model = "riot", price = 70000 }, + }, }, } diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/fxmanifest.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/fxmanifest.lua index 1b2df0471..d568bbd57 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/fxmanifest.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/fxmanifest.lua @@ -1,25 +1,24 @@ fx_version("adamant") + game("gta5") -description("bpt_ammunation job") -author("bitpredator") +description("bpt_ammunation job RP server") lua54("yes") -version("1.0.2") +version("1.0.3") shared_script("@es_extended/imports.lua") -client_scripts({ - "@es_extended/locale.lua", - "locales/*.lua", - "config.lua", - "client/*.lua", -}) - server_scripts({ - "@es_extended/locale.lua", - "locales/*.lua", - "config.lua", - "server/*.lua", + "@oxmysql/lib/MySQL.lua", + "@es_extended/locale.lua", + "locales/*.lua", + "config.lua", + "server/*.lua", }) -dependency("es_extended") +client_scripts({ + "@es_extended/locale.lua", + "locales/*.lua", + "config.lua", + "client/*.lua", +}) diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/locales/en.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/locales/en.lua index 748409dcf..0653a8c1f 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/locales/en.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/locales/en.lua @@ -1,34 +1,150 @@ Locales["en"] = { - -- cloakroom - ["cloakroom_menu"] = "cloakroom", - ["cloakroom_prompt"] = "press [E] to access the cloakroom.", - ["wear_citizen"] = "civilian clothing", - ["wear_work"] = "work clothes", - -- Inventory - ["deposit_stock"] = "Deposit stock", - ["take_stock"] = "Take stock", - ["have_deposited"] = "Have deposited", - ["quantity_invalid"] = "Quantity invelid", - -- garage - ["spawner_prompt"] = "press [E] to access the garage.", - ["vehicle_spawned"] = "vehicle spawned successfully!", - ["store_veh"] = "press [E] to deposit the vehicle", - ["spawn_veh"] = "spawn vehicle", - ["spawnpoint_blocked"] = "vehicle blocks the spawnpoint!", - ["only_ammu"] = "you can only deposit company vehicles.", - ["empty_garage"] = "no vehicles in the garage!", - ["taking_service"] = "Take service: Gunsmith", - ["full_service"] = "complete service: ", - ["amount_invalid"] = "invalid amount", - ["press_to_open"] = "press [E] to access the menu", - ["billing"] = "billing", - ["billing_sent"] = "the invoice has been posted!", - ["invoice_amount"] = "invoice amount", - ["no_players_near"] = "no players nearby", - ["boss_actions"] = "Boss actions", - ["blip_ammu"] = "Armory.", - ["ammu"] = "ammu", - -- billing - ["bill_amount"] = "Amount to bill..", + -- 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 [E] to access the Armory.", + ["armory_owned"] = "owned", + ["armory_free"] = "free", + ["armory_item"] = "$%s", + ["armory_weapontitle"] = "armory - Buy weapon", + ["armory_componenttitle"] = "armory - Weapon attatchments", + ["armory_bought"] = "you bought an %s for $%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", ["confirm"] = "Confirm", + -- Vehicles + ["vehicle_menu"] = "vehicle", + ["vehicle_blocked"] = "all available spawn points are currently blocked!", + ["garage_prompt"] = "press [E] to access the Vehicle Actions.", + ["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 don't 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.", + ["shop_item"] = "$%s", + ["vehicleshop_title"] = "vehicle Shop", + ["vehicleshop_confirm"] = "do you want to buy this vehicle?", + ["vehicleshop_bought"] = "you have bought %s for ~r~$%s", + ["vehicleshop_money"] = "you cannot afford that vehicle", + ["vehicleshop_awaiting_model"] = "the vehicle is currently DOWNLOADING & LOADING please wait", + ["confirm_no"] = "no", + ["confirm_yes"] = "yes", + ["view"] = "View", + ["buy_car"] = "Buy", + ["stop_view"] = "Stop Viewing", + -- 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 %s has entered service!", + ["service_out"] = "you have left service.", + ["service_out_announce"] = "operator %s has left their service.", + -- Action Menu + ["menu_title"] = "Ammu", + ["citizen_interaction"] = "citizen Interaction", + ["vehicle_interaction"] = "vehicle Interaction", + ["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", + ["license_check"] = "manage license", + ["license_revoke"] = "revoke license", + ["license_revoked"] = "your %s has been revoked!", + ["licence_you_revoked"] = "you revoked a %s which belonged to %s", + ["no_players_nearby"] = "there is no player(s) nearby!", + ["being_searched"] = "you are being searched by the Ammu", + -- Vehicle interaction + ["vehicle_info"] = "vehicle Info", + ["pick_lock"] = "lockpick Vehicle", + ["vehicle_unlocked"] = "vehicle Unlocked", + ["no_vehicles_nearby"] = "there is no vehicles nearby", + ["impound"] = "impound vehicle", + ["impound_prompt"] = "press [E] to cancel the impound", + ["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 a valid registration number", + ["search_plate"] = "Enter Plate", + ["lookup_plate"] = "Lookup Plate", + -- 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 %sx %s from %s", + ["got_confiscated"] = "%sx %s were confiscated by %s", + ["you_confiscated_account"] = "you confiscated $%s (%s) from %s", + ["got_confiscated_account"] = "$%s (%s) was confiscated by %s", + ["you_confiscated_weapon"] = "you confiscated %s from %s with ~o~%s bullets", + ["got_confiscated_weapon"] = "your %s with ~o~%s bullets was confiscated by %s", + ["traffic_offense"] = "traffic Offense", + ["minor_offense"] = "minor Offense", + ["average_offense"] = "average Offense", + ["major_offense"] = "major Offense", + ["fine_total"] = "fine: %s", + ["fine_enter_amount"] = "Enter the amount of the fine", + ["fine_enter_text"] = "Enter the reason for the fine", + ["invalid_amount"] = "Error: Amount was not a number or invalid", + -- Vehicle Info Menu + ["plate"] = "plate: %s", + ["owner_unknown"] = "owner: Unknown", + ["owner"] = "owner: %s", + -- Boss Menu + ["open_bossmenu"] = "press [E] to open the menu", + ["quantity_invalid"] = "invalid quantity", + ["have_withdrawn"] = "you have withdrawn %sx %s", + ["have_deposited"] = "you have deposited %sx %s", + ["quantity"] = "quantity", + ["quantity_placeholder"] = "Amount to withdraw..", + ["inventory"] = "inventory", + ["ammu_stock"] = "Ammu Stock", + -- Misc + ["remove_prop"] = "press [E] to delete the object", + ["map_blip"] = "Ammu Station", + ["unrestrained_timer"] = "you feel your handcuffs slowly losing grip and fading away.", + -- Notifications + ["alert_ammu"] = "Ammu alert", + ["phone_ammu"] = "Ammu", + -- Keybind + ["interaction"] = "Interact", + ["quick_actions"] = "Quick Actions", + -- Other + ["society_ammu"] = "Ammu", + ["received_firearms_license"] = "You have received your firearms license", + ["released_gun_licence"] = "you have issued your gun licence", } diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/locales/it.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/locales/it.lua index 4fe3d8de4..5450ebe03 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/locales/it.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/locales/it.lua @@ -1,35 +1,148 @@ Locales["it"] = { - -- cloakroom - ["cloakroom_menu"] = "guardaroba", - ["cloakroom_prompt"] = "premi [E] per accedere al guardaroba.", - ["wear_citizen"] = "abbigliamento civile", - ["wear_work"] = "abiti da lavoro", - -- Inventory - ["deposit_stock"] = "Depositare", - ["take_stock"] = "Prendi", - ["have_deposited"] = "Hai depositato", - ["quantity_invalid"] = "Qunatità non valida", - -- garage - ["spawner_prompt"] = "premi [E] per accedere al garage.", - ["vehicle_spawned"] = "veicolo generato con successo!", - ["store_veh"] = "premi [E] per depositare il veicolo", - ["spawn_veh"] = "genera veicolo", - ["spawnpoint_blocked"] = "un veicolo blocca lo spawnpoint!", - ["only_ammu"] = "puoi depositare solo veicoli aziendali.", - ["empty_garage"] = "nessun veicolo nel garage!", - ["taking_service"] = "prendi servizio: Armaiolo", - ["full_service"] = "servizio completo: ", - ["amount_invalid"] = "importo non valido", - ["press_to_open"] = "premi [E] per accedere al menu", - ["billing"] = "fattura", - ["billing_sent"] = "la fattura è stata registrata!", - ["invoice_amount"] = "importo fattura", - ["no_players_near"] = "nessun giocatore nelle vicinanze", - ["boss_actions"] = "Azioni del capo", - ["blip_ammu"] = "Armeria.", - ["ammu"] = "ammu", - -- billing - ["bill_amount"] = "importo della fattura", + -- Armeria + ["remove_object"] = "Prendi oggetto", + ["deposit_object"] = "Deposita oggetto", + ["get_weapon"] = "Prendi arma dall'armeria", + ["put_weapon"] = "Deposita arma nell'armeria", + ["buy_weapons"] = "Acquista armi", + ["armory"] = "armeria", + ["open_armory"] = "Premi [E] per accedere all'Armeria.", + ["armory_owned"] = "posseduto", + ["armory_free"] = "gratuito", + ["armory_item"] = "$%s", + ["armory_weapontitle"] = "armeria - Acquista arma", + ["armory_componenttitle"] = "armeria - Accessori arma", + ["armory_bought"] = "Hai comprato un %s per $%s", + ["armory_money"] = "Non puoi permetterti quell'arma", + ["armory_hascomponent"] = "Hai già quel accessorio equipaggiato!", + ["get_weapon_menu"] = "armeria - Prendi arma", + ["put_weapon_menu"] = "armeria - Deposita arma", ["confirm"] = "Conferma", - ["amount"] = "importo", + -- Veicoli + ["vehicle_menu"] = "veicolo", + ["vehicle_blocked"] = "tutti i punti di spawn disponibili sono attualmente bloccati!", + ["garage_prompt"] = "Premi [E] per accedere alle Azioni sul Veicolo.", + ["garage_title"] = "Azioni sul Veicolo", + ["garage_stored"] = "nella rimessa", + ["garage_notstored"] = "non in rimessa", + ["garage_storing"] = "Stiamo cercando di rimuovere il veicolo, assicurati che nessun giocatore sia intorno ad esso.", + ["garage_has_stored"] = "il veicolo è stato riposto in rimessa", + ["garage_has_notstored"] = "nessun veicolo di proprietà è stato trovato nelle vicinanze", + ["garage_notavailable"] = "il tuo veicolo non è riposto in rimessa.", + ["garage_blocked"] = "non ci sono punti di spawn disponibili!", + ["garage_empty"] = "non hai veicoli in rimessa.", + ["garage_released"] = "il tuo veicolo è stato rilasciato dalla rimessa.", + ["garage_store_nearby"] = "non ci sono veicoli nelle vicinanze.", + ["garage_storeditem"] = "apri rimessa", + ["garage_storeitem"] = "riponi veicolo in rimessa", + ["garage_buyitem"] = "concessionario veicoli", + ["garage_notauthorized"] = "non sei autorizzato ad acquistare questo tipo di veicoli.", + ["shop_item"] = "$%s", + ["vehicleshop_title"] = "concessionario veicoli", + ["vehicleshop_confirm"] = "vuoi comprare questo veicolo?", + ["vehicleshop_bought"] = "hai comprato %s per ~r~$%s", + ["vehicleshop_money"] = "non puoi permetterti quel veicolo", + ["vehicleshop_awaiting_model"] = "il veicolo è attualmente in DOWNLOAD & LOADING, per favore attendi", + ["confirm_no"] = "no", + ["confirm_yes"] = "si", + ["view"] = "Visualizza", + ["buy_car"] = "Compra", + ["stop_view"] = "Interrompi la visualizzazione", + -- Servizio + ["service_max"] = "non puoi entrare in servizio, numero massimo di agenti in servizio: %s/%s", + ["service_not"] = "non sei in servizio! Devi cambiarti prima.", + ["service_anonunce"] = "informazioni servizio", + ["service_in"] = "sei entrato in servizio, benvenuto!", + ["service_in_announce"] = "l'operatore %s è entrato in servizio!", + ["service_out"] = "hai lasciato il servizio.", + ["service_out_announce"] = "l'operatore %s ha lasciato il servizio.", + -- Menu Azioni + ["menu_title"] = "Armeria", + ["citizen_interaction"] = "Interazione con cittadino", + ["vehicle_interaction"] = "Interazione con veicolo", + ["id_card"] = "Carta d'identità", + ["search"] = "perquisisci", + ["handcuff"] = "ammanetta / smanetta", + ["drag"] = "scorta", + ["put_in_vehicle"] = "metti in veicolo", + ["out_the_vehicle"] = "trascina fuori dal veicolo", + ["fine"] = "multa", + ["license_check"] = "gestisci licenze", + ["license_revoke"] = "revoca licenza", + ["license_revoked"] = "la tua %s è stata revocata!", + ["licence_you_revoked"] = "hai revocato una %s che apparteneva a %s", + ["no_players_nearby"] = "non ci sono giocatori nelle vicinanze!", + ["being_searched"] = "perquisizione in corso", + ["fine_enter_amount"] = "Inserisci l'importo della sanzione", + ["fine_enter_text"] = "Inserisci il motivo della multa", + ["invalid_amount"] = "Errore: l'importo non era un numero o non era valido", + -- Interazione veicolo + ["vehicle_info"] = "informazioni sul veicolo", + ["pick_lock"] = "forza la serratura del veicolo", + ["vehicle_unlocked"] = "veicolo sbloccato", + ["no_vehicles_nearby"] = "non ci sono veicoli nelle vicinanze", + ["impound"] = "recupera veicolo", + ["impound_prompt"] = "Premi [E] per annullare il recupero", + ["impound_canceled"] = "hai annullato il recupero", + ["impound_canceled_moved"] = "il recupero è stato annullato perché il veicolo si è mosso", + ["impound_successful"] = "hai confiscato il veicolo", + ["search_database"] = "informazioni sul veicolo", + ["search_database_title"] = "informazioni sul veicolo - cerca con numero di targa", + ["search_database_error_invalid"] = "quello non è un numero di targa valido", + ["search_plate"] = "Inserisci targa", + ["lookup_plate"] = "Cerca targa", + -- Menu Carta d'identità + ["name"] = "nome: %s", + ["job"] = "lavoro: %s", + ["sex"] = "sesso: %s", + ["dob"] = "DOB: %s", + ["height"] = "altezza: %s", + ["bac"] = "BAC: %s", + ["unknown"] = "sconosciuto", + ["male"] = "maschio", + ["female"] = "femmina", + -- Menu Perquisizione corpo + ["guns_label"] = "--- Armi ---", + ["inventory_label"] = "--- Inventario ---", + ["license_label"] = " --- Licenze ---", + ["confiscate"] = "confisca %s", + ["confiscate_weapon"] = "confisca %s con %s proiettili", + ["confiscate_inv"] = "confisca %sx %s", + ["confiscate_dirty"] = 'confisca denaro sporco: $%s', + ["you_confiscated"] = "hai confiscato %sx %s da %s", + ["got_confiscated"] = "%sx %s sono stati confiscati da %s", + ["you_confiscated_account"] = "hai confiscato $%s (%s) da %s", + ["got_confiscated_account"] = "$%s (%s) sono stati confiscati da %s", + ["you_confiscated_weapon"] = "hai confiscato %s da %s con ~o~%s proiettili", + ["got_confiscated_weapon"] = "la tua %s con ~o~%s proiettili è stata confiscata da %s", + ["traffic_offense"] = "infrazione del traffico", + ["minor_offense"] = "infrazione minore", + ["average_offense"] = "infrazione media", + ["major_offense"] = "infrazione grave", + ["fine_total"] = "multa: %s", + -- Menu Informazioni Veicolo + ["plate"] = "targa: %s", + ["owner_unknown"] = "proprietario: sconosciuto", + ["owner"] = "proprietario: %s", + -- Menu Boss + ["open_bossmenu"] = "premi [E] per aprire il menu", + ["quantity_invalid"] = "quantità non valida", + ["have_withdrawn"] = "hai prelevato %sx %s", + ["have_deposited"] = "hai depositato %sx %s", + ["quantity"] = "quantità", + ["quantity_placeholder"] = "Importo da prelevare..", + ["inventory"] = "inventario", + ["ammu_stock"] = "Deposito armeria", + -- Varie + ["remove_prop"] = "premi [E] per eliminare l'oggetto", + ["map_blip"] = "Armeria", + ["unrestrained_timer"] = "senti le manette che si allentano lentamente e svaniscono.", + -- Pulsante + ["interaction"] = "Interagisci", + ["quick_actions"] = "Azioni rapide", + -- Altro + ["society_ammu"] = "Armeria", + ["weapon"] = "Porto D'armi", + ["received_firearms_license"] = "Hai ricevuto il porto d'armi", + ["released_gun_licence"] = "Hai rilasciato il porto d'armi", } diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/localization/bpt_ammujob_it.sql b/server-data/resources/[bpt_addons]/bpt_ammujob/localization/bpt_ammujob_it.sql index dd7fa6599..e312eadc2 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/localization/bpt_ammujob_it.sql +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/localization/bpt_ammujob_it.sql @@ -20,4 +20,4 @@ INSERT INTO `job_grades` (job_name, grade, name, label, salary, skin_male, skin_ ('ammu',2,'armorychief','Capo Armeria',60,'{}','{}'), ('ammu',3,'deputydirector','Vice direttore',85,'{}','{}'), ('ammu',4,'boss','Direttore',100,'{}','{}') -; +; \ No newline at end of file diff --git a/server-data/resources/[bpt_addons]/bpt_ammujob/server/main.lua b/server-data/resources/[bpt_addons]/bpt_ammujob/server/main.lua index caaced1b5..d354694d1 100644 --- a/server-data/resources/[bpt_addons]/bpt_ammujob/server/main.lua +++ b/server-data/resources/[bpt_addons]/bpt_ammujob/server/main.lua @@ -1,82 +1,404 @@ -local netId +---@diagnostic disable: undefined-global -TriggerEvent("bpt_society:registerSociety", "ammu", "Ammu", "society_ammu", "society_ammu", "society_ammu", { +if Config.EnableESXService then + if Config.MaxInService ~= -1 then + TriggerEvent("esx_service:activateService", "ammu", Config.MaxInService) + end +end + +TriggerEvent("bpt_society:registerSociety", "ammu", TranslateCap("society_ammu"), "society_ammu", "society_ammu", "society_ammu", { type = "public", }) -if Config.MaxInService ~= -1 then - TriggerEvent("esx_service:activateService", "ammu", Config.MaxInService) -end - -ESX.RegisterServerCallback("bpt_ammujob:SpawnVehicle", function(source, cb, model, props) - local xPlayer = ESX.GetPlayerFromId(source) +RegisterNetEvent("bpt_ammujob:confiscatePlayerItem") +AddEventHandler("bpt_ammujob:confiscatePlayerItem", function(target, itemType, itemName, amount) + local source = source + local sourceXPlayer = ESX.GetPlayerFromId(source) + local targetXPlayer = ESX.GetPlayerFromId(target) - if xPlayer.job.name ~= "ammu" then - print(("[^3WARNING^7] Player ^5%s^7 attempted to Exploit Vehicle Spawing!!"):format(source)) + if sourceXPlayer.job.name ~= "ammu" then + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Exploit The Confuscation System!"):format(sourceXPlayer.source)) return end - local SpawnPoint = vector3(Config.Zones.VehicleSpawnPoint.Pos.x, Config.Zones.VehicleSpawnPoint.Pos.y, Config.Zones.VehicleSpawnPoint.Pos.z) - ESX.OneSync.SpawnVehicle(joaat(model), SpawnPoint, Config.Zones.VehicleSpawnPoint.Heading, props, function() - local vehicle = NetworkGetEntityFromNetworkId(netId) - while GetVehicleNumberPlateText(vehicle) ~= props.plate do - Wait(0) + + 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(TranslateCap("you_confiscated", amount, sourceItem.label, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("got_confiscated", amount, sourceItem.label, sourceXPlayer.name)) + else + sourceXPlayer.showNotification(TranslateCap("quantity_invalid")) + end + else + sourceXPlayer.showNotification(TranslateCap("quantity_invalid")) end - TaskWarpPedIntoVehicle(GetPlayerPed(source), vehicle, -1) - end) - cb() + elseif itemType == "item_account" then + local targetAccount = targetXPlayer.getAccount(itemName) + + -- does the target player have enough money? + if targetAccount.money >= amount then + targetXPlayer.removeAccountMoney(itemName, amount, "Confiscated") + sourceXPlayer.addAccountMoney(itemName, amount, "Confiscated") + + sourceXPlayer.showNotification(TranslateCap("you_confiscated_account", amount, itemName, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("got_confiscated_account", amount, itemName, sourceXPlayer.name)) + else + sourceXPlayer.showNotification(TranslateCap("quantity_invalid")) + end + elseif itemType == "item_weapon" then + if amount == nil then + amount = 0 + end + + -- does the target player have weapon? + if targetXPlayer.hasWeapon(itemName) then + targetXPlayer.removeWeapon(itemName) + sourceXPlayer.addWeapon(itemName, amount) + + sourceXPlayer.showNotification(TranslateCap("you_confiscated_weapon", ESX.GetWeaponLabel(itemName), targetXPlayer.name, amount)) + targetXPlayer.showNotification(TranslateCap("got_confiscated_weapon", ESX.GetWeaponLabel(itemName), amount, sourceXPlayer.name)) + else + sourceXPlayer.showNotification(TranslateCap("quantity_invalid")) + end + end +end) + +RegisterNetEvent("bpt_ammujob:handcuff") +AddEventHandler("bpt_ammujob:handcuff", function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == "ammu" then + TriggerClientEvent("bpt_ammujob:handcuff", target) + else + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Exploit Handcuffs!"):format(xPlayer.source)) + end +end) + +RegisterNetEvent("bpt_ammujob:drag") +AddEventHandler("bpt_ammujob:drag", function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == "ammu" then + TriggerClientEvent("bpt_ammujob:drag", target, source) + else + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Exploit Dragging!"):format(xPlayer.source)) + end +end) + +RegisterNetEvent("bpt_ammujob:putInVehicle") +AddEventHandler("bpt_ammujob:putInVehicle", function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == "ammu" then + TriggerClientEvent("bpt_ammujob:putInVehicle", target) + else + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Exploit Garage!"):format(xPlayer.source)) + end +end) + +RegisterNetEvent("bpt_ammujob:OutVehicle") +AddEventHandler("bpt_ammujob:OutVehicle", function(target) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == "ammu" then + TriggerClientEvent("bpt_ammujob:OutVehicle", target) + else + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Exploit Dragging Out Of Vehicle!"):format(xPlayer.source)) + end end) RegisterNetEvent("bpt_ammujob:getStockItem") AddEventHandler("bpt_ammujob:getStockItem", function(itemName, count) + local source = source local xPlayer = ESX.GetPlayerFromId(source) - if xPlayer.job.name == "ammu" then - TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", function(inventory) - local item = inventory.getItem(itemName) - - -- is there enough in the society? - if count > 0 and item.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(TranslateCap("have_withdrawn", count, item.label)) - else - xPlayer.showNotification(TranslateCap("player_cannot_hold")) - end + TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", 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(TranslateCap("have_withdrawn", count, inventoryItem.name)) else xPlayer.showNotification(TranslateCap("quantity_invalid")) end + else + xPlayer.showNotification(TranslateCap("quantity_invalid")) + end + end) +end) + +RegisterNetEvent("bpt_ammujob:putStockItems") +AddEventHandler("bpt_ammujob:putStockItems", function(itemName, count) + local xPlayer = ESX.GetPlayerFromId(source) + local sourceItem = xPlayer.getInventoryItem(itemName) + + TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", 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(TranslateCap("have_deposited", count, inventoryItem.name)) + else + xPlayer.showNotification(TranslateCap("quantity_invalid")) + end + end) +end) + +ESX.RegisterServerCallback("bpt_ammujob:getOtherPlayerData", function(source, cb, target, notify) + local xPlayer = ESX.GetPlayerFromId(target) + + if notify then + xPlayer.showNotification(TranslateCap("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 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("bpt_status:getStatus", target, "drunk", function(status) + if status then + data.drunk = ESX.Math.Round(status.percent) + end + end) + + if Config.EnableLicenses then + TriggerEvent("esx_license:getLicenses", target, function(licenses) + data.licenses = licenses + cb(data) + end) + else + cb(data) + end + end +end) + +local fineList = {} +ESX.RegisterServerCallback("bpt_ammujob:getFineList", function(source, cb, category) + if not fineList[category] then + MySQL.query("SELECT * FROM fine_types WHERE category = ?", { category }, function(fines) + fineList[category] = fines + + cb(fines) end) else - print(("[^3WARNING^7] Player ^5%s^7 attempted ^5bpt_ammujob:getStockItem^7 (cheating)"):format(source)) + cb(fineList[category]) end end) -ESX.RegisterServerCallback("bpt_ammujob:getStockItems", function(_, cb) - TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", function(inventory) - cb(inventory.items) +ESX.RegisterServerCallback("bpt_ammujob:getVehicleInfos", function(source, cb, plate) + local retrivedInfo = { + plate = plate, + } + if Config.EnableESXIdentity then + MySQL.single("SELECT users.firstname, users.lastname FROM owned_vehicles JOIN users ON owned_vehicles.owner = users.identifier WHERE plate = ?", { plate }, function(result) + if result then + retrivedInfo.owner = ("%s %s"):format(result.firstname, result.lastname) + end + cb(retrivedInfo) + end) + else + MySQL.scalar("SELECT owner FROM owned_vehicles WHERE plate = ?", { plate }, function(owner) + if owner then + local xPlayer = ESX.GetPlayerFromIdentifier(owner) + if xPlayer then + retrivedInfo.owner = xPlayer.getName() + end + end + cb(retrivedInfo) + end) + end +end) + +ESX.RegisterServerCallback("bpt_ammujob:getArmoryWeapons", function(source, cb) + TriggerEvent("bpt_datastore:getSharedDataStore", "society_ammu", function(store) + local weapons = store.get("weapons") + + if weapons == nil then + weapons = {} + end + + cb(weapons) end) end) -RegisterNetEvent("bpt_ammujob:putStockItems") -AddEventHandler("bpt_ammujob:putStockItems", function(itemName, count) +ESX.RegisterServerCallback("bpt_ammujob:addArmoryWeapon", function(source, cb, weaponName, removeWeapon) local xPlayer = ESX.GetPlayerFromId(source) - local sourceItem = xPlayer.getInventoryItem(itemName) - if xPlayer.job.name == "ammu" then - TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", function(inventory) - local item = inventory.getItem(itemName) + if removeWeapon then + xPlayer.removeWeapon(weaponName) + end + + TriggerEvent("bpt_datastore:getSharedDataStore", "society_ammu", 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("bpt_ammujob:removeArmoryWeapon", function(source, cb, weaponName) + local xPlayer = ESX.GetPlayerFromId(source) + xPlayer.addWeapon(weaponName, 500) + + TriggerEvent("bpt_datastore:getSharedDataStore", "society_ammu", 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("bpt_ammujob:buyJobVehicle", function(source, cb, vehicleProps, type) + local xPlayer = ESX.GetPlayerFromId(source) + local price = GetPriceFromHash(vehicleProps.model, xPlayer.job.grade_name, type) + + -- vehicle model not found + if price == 0 then + print(("[^3WARNING^7] Player ^5%s^7 Attempted To Buy Invalid Vehicle - ^5%s^7!"):format(source, vehicleProps.model)) + cb(false) + else + if xPlayer.getMoney() >= price then + xPlayer.removeMoney(price, "Job Vehicle Bought") + + MySQL.insert("INSERT INTO owned_vehicles (owner, vehicle, plate, type, job, `stored`) VALUES (?, ?, ?, ?, ?, ?)", { xPlayer.identifier, json.encode(vehicleProps), vehicleProps.plate, type, xPlayer.job.name, true }, function(rowsChanged) + cb(true) + end) + else + cb(false) + end + end +end) - if sourceItem.count >= count and count > 0 then - xPlayer.removeInventoryItem(itemName, count) - inventory.addItem(itemName, count) - xPlayer.showNotification(TranslateCap("have_deposited", count, item.label)) +ESX.RegisterServerCallback("bpt_ammujob:storeNearbyVehicle", function(source, cb, plates) + local xPlayer = ESX.GetPlayerFromId(source) + + local plate = MySQL.scalar.await("SELECT plate FROM owned_vehicles WHERE owner = ? AND plate IN (?) AND job = ?", { xPlayer.identifier, plates, xPlayer.job.name }) + + if plate then + MySQL.update("UPDATE owned_vehicles SET `stored` = true WHERE owner = ? AND plate = ? AND job = ?", { xPlayer.identifier, plate, xPlayer.job.name }, function(rowsChanged) + if rowsChanged == 0 then + cb(false) else - xPlayer.showNotification(TranslateCap("quantity_invalid")) + cb(plate) end end) else - print(("[^3WARNING^7] Player ^5%s^7 attempted ^5bpt_ammujob:putStockItems^7 (cheating)"):format(source)) + cb(false) + end +end) + +function GetPriceFromHash(vehicleHash, jobGrade, type) + local vehicles = Config.AuthorizedVehicles[type][jobGrade] + + for i = 1, #vehicles do + local vehicle = vehicles[i] + if GetHashKey(vehicle.model) == vehicleHash then + return vehicle.price + end + end + + return 0 +end + +ESX.RegisterServerCallback("bpt_ammujob:getStockItems", function(source, cb) + TriggerEvent("bpt_addoninventory:getSharedInventory", "society_ammu", function(inventory) + cb(inventory.items) + end) +end) + +ESX.RegisterServerCallback("bpt_ammujob:getPlayerInventory", function(source, cb) + local xPlayer = ESX.GetPlayerFromId(source) + local items = xPlayer.inventory + + cb({ items = items }) +end) + +RegisterNetEvent("bpt_ammujob:spawned") +AddEventHandler("bpt_ammujob:spawned", function() + local playerId = source + local xPlayer = ESX.GetPlayerFromId(playerId) + + if xPlayer and xPlayer.job.name == "ammu" then + Wait(5000) + TriggerClientEvent("bpt_ammujob:updateBlip", -1) + end +end) + +RegisterNetEvent("bpt_ammujob:forceBlip") +AddEventHandler("bpt_ammujob:forceBlip", function() + for _, xPlayer in pairs(ESX.GetExtendedPlayers("job", "ammu")) do + TriggerClientEvent("bpt_ammujob:updateBlip", xPlayer.source) + end +end) + +AddEventHandler("onResourceStart", function(resource) + if resource == GetCurrentResourceName() then + Wait(5000) + for _, xPlayer in pairs(ESX.GetExtendedPlayers("job", "ammu")) do + TriggerClientEvent("bpt_ammujob:updateBlip", xPlayer.source) + end end end)