Skip to content

Commit

Permalink
refactor: armory work reconstruction
Browse files Browse the repository at this point in the history
  • Loading branch information
bitpredator committed Dec 17, 2024
1 parent 84cad1e commit 1f9d239
Show file tree
Hide file tree
Showing 9 changed files with 2,120 additions and 423 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,'{}','{}')
;
;
1,304 changes: 1,050 additions & 254 deletions server-data/resources/[bpt_addons]/bpt_ammujob/client/main.lua

Large diffs are not rendered by default.

320 changes: 320 additions & 0 deletions server-data/resources/[bpt_addons]/bpt_ammujob/client/vehicle.lua
Original file line number Diff line number Diff line change
@@ -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 - <span style="color:green;">%s</span>'):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 - <span style="color:darkgoldenrod;">%s</span>: '):format(vehicleName, props.plate)

if v.stored == 1 or v.stored == true then
label = label .. ('<span style="color:green;">%s</span>'):format(TranslateCap("garage_stored"))
elseif v.stored == 0 or v.stored == false then
label = label .. ('<span style="color:darkred;">%s</span>'):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
Loading

0 comments on commit 1f9d239

Please sign in to comment.