mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-08-30 17:58:54 +00:00
924 lines
28 KiB
Lua
924 lines
28 KiB
Lua
local CurrentAction, CurrentActionMsg, CurrentActionData = nil, '', {}
|
|
local HasAlreadyEnteredMarker, LastHospital, LastPart, LastPartNum
|
|
local IsBusy = false
|
|
local spawnedVehicles, isInShopMenu = {}, false
|
|
|
|
function OpenAmbulanceActionsMenu()
|
|
local elements = {
|
|
{label = _U('cloakroom'), value = 'cloakroom'}
|
|
}
|
|
|
|
if Config.EnablePlayerManagement and ESX.PlayerData.job.grade_name == 'boss' then
|
|
table.insert(elements, {label = _U('boss_actions'), value = 'boss_actions'})
|
|
end
|
|
|
|
ESX.UI.Menu.CloseAll()
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'ambulance_actions',
|
|
{
|
|
title = _U('ambulance'),
|
|
align = 'top-left',
|
|
elements = elements
|
|
}, function(data, menu)
|
|
if data.current.value == 'cloakroom' then
|
|
OpenCloakroomMenu()
|
|
elseif data.current.value == 'boss_actions' then
|
|
TriggerEvent('esx_society:openBossMenu', 'ambulance', function(data, menu)
|
|
menu.close()
|
|
end, {wash = false})
|
|
end
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
end
|
|
|
|
function OpenMobileAmbulanceActionsMenu()
|
|
|
|
ESX.UI.Menu.CloseAll()
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'mobile_ambulance_actions',
|
|
{
|
|
title = _U('ambulance'),
|
|
align = 'top-left',
|
|
elements = {
|
|
{label = _U('ems_menu'), value = 'citizen_interaction'}
|
|
}
|
|
}, function(data, menu)
|
|
if data.current.value == 'citizen_interaction' then
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'citizen_interaction',
|
|
{
|
|
title = _U('ems_menu_title'),
|
|
align = 'top-left',
|
|
elements = {
|
|
{label = _U('ems_menu_revive'), value = 'revive'},
|
|
{label = _U('ems_menu_small'), value = 'small'},
|
|
{label = _U('ems_menu_big'), value = 'big'},
|
|
{label = _U('ems_menu_putincar'), value = 'put_in_vehicle'}
|
|
}
|
|
}, function(data, menu)
|
|
if IsBusy then return end
|
|
|
|
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer()
|
|
|
|
if closestPlayer == -1 or closestDistance > 1.0 then
|
|
ESX.ShowNotification(_U('no_players'))
|
|
else
|
|
|
|
if data.current.value == 'revive' then
|
|
|
|
IsBusy = true
|
|
|
|
ESX.TriggerServerCallback('esx_ambulancejob:getItemAmount', function(quantity)
|
|
if quantity > 0 then
|
|
local closestPlayerPed = GetPlayerPed(closestPlayer)
|
|
|
|
if IsPedDeadOrDying(closestPlayerPed, 1) then
|
|
local playerPed = PlayerPedId()
|
|
|
|
ESX.ShowNotification(_U('revive_inprogress'))
|
|
|
|
local lib, anim = 'mini@cpr@char_a@cpr_str', 'cpr_pumpchest'
|
|
|
|
for i=1, 15, 1 do
|
|
Citizen.Wait(900)
|
|
|
|
ESX.Streaming.RequestAnimDict(lib, function()
|
|
TaskPlayAnim(PlayerPedId(), lib, anim, 8.0, -8.0, -1, 0, 0, false, false, false)
|
|
end)
|
|
end
|
|
|
|
TriggerServerEvent('esx_ambulancejob:removeItem', 'medikit')
|
|
TriggerServerEvent('esx_ambulancejob:revive', GetPlayerServerId(closestPlayer))
|
|
|
|
-- Show revive award?
|
|
if Config.ReviveReward > 0 then
|
|
ESX.ShowNotification(_U('revive_complete_award', GetPlayerName(closestPlayer), Config.ReviveReward))
|
|
else
|
|
ESX.ShowNotification(_U('revive_complete', GetPlayerName(closestPlayer)))
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('player_not_unconscious'))
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('not_enough_medikit'))
|
|
end
|
|
|
|
IsBusy = false
|
|
|
|
end, 'medikit')
|
|
|
|
elseif data.current.value == 'small' then
|
|
|
|
ESX.TriggerServerCallback('esx_ambulancejob:getItemAmount', function(quantity)
|
|
if quantity > 0 then
|
|
local closestPlayerPed = GetPlayerPed(closestPlayer)
|
|
local health = GetEntityHealth(closestPlayerPed)
|
|
|
|
if health > 0 then
|
|
local playerPed = PlayerPedId()
|
|
|
|
IsBusy = true
|
|
ESX.ShowNotification(_U('heal_inprogress'))
|
|
TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true)
|
|
Citizen.Wait(10000)
|
|
ClearPedTasks(playerPed)
|
|
|
|
TriggerServerEvent('esx_ambulancejob:removeItem', 'bandage')
|
|
TriggerServerEvent('esx_ambulancejob:heal', GetPlayerServerId(closestPlayer), 'small')
|
|
ESX.ShowNotification(_U('heal_complete', GetPlayerName(closestPlayer)))
|
|
IsBusy = false
|
|
else
|
|
ESX.ShowNotification(_U('player_not_conscious'))
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('not_enough_bandage'))
|
|
end
|
|
end, 'bandage')
|
|
|
|
elseif data.current.value == 'big' then
|
|
|
|
ESX.TriggerServerCallback('esx_ambulancejob:getItemAmount', function(quantity)
|
|
if quantity > 0 then
|
|
local closestPlayerPed = GetPlayerPed(closestPlayer)
|
|
local health = GetEntityHealth(closestPlayerPed)
|
|
|
|
if health > 0 then
|
|
local playerPed = PlayerPedId()
|
|
|
|
IsBusy = true
|
|
ESX.ShowNotification(_U('heal_inprogress'))
|
|
TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true)
|
|
Citizen.Wait(10000)
|
|
ClearPedTasks(playerPed)
|
|
|
|
TriggerServerEvent('esx_ambulancejob:removeItem', 'medikit')
|
|
TriggerServerEvent('esx_ambulancejob:heal', GetPlayerServerId(closestPlayer), 'big')
|
|
ESX.ShowNotification(_U('heal_complete', GetPlayerName(closestPlayer)))
|
|
IsBusy = false
|
|
else
|
|
ESX.ShowNotification(_U('player_not_conscious'))
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('not_enough_medikit'))
|
|
end
|
|
end, 'medikit')
|
|
|
|
elseif data.current.value == 'put_in_vehicle' then
|
|
TriggerServerEvent('esx_ambulancejob:putInVehicle', GetPlayerServerId(closestPlayer))
|
|
end
|
|
end
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
end
|
|
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
end
|
|
|
|
function FastTravel(coords, heading)
|
|
local playerPed = PlayerPedId()
|
|
|
|
DoScreenFadeOut(800)
|
|
|
|
while not IsScreenFadedOut() do
|
|
Citizen.Wait(500)
|
|
end
|
|
|
|
ESX.Game.Teleport(playerPed, coords, function()
|
|
DoScreenFadeIn(800)
|
|
|
|
if heading then
|
|
SetEntityHeading(playerPed, heading)
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Draw markers & Marker logic
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
Citizen.Wait(0)
|
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
|
local letSleep, isInMarker, hasExited = true, false, false
|
|
local currentHospital, currentPart, currentPartNum
|
|
|
|
for hospitalNum,hospital in pairs(Config.Hospitals) do
|
|
|
|
-- Ambulance Actions
|
|
for k,v in ipairs(hospital.AmbulanceActions) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(Config.Marker.type, v, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Config.Marker.x, Config.Marker.y, Config.Marker.z, Config.Marker.r, Config.Marker.g, Config.Marker.b, Config.Marker.a, false, false, 2, Config.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
if distance < Config.Marker.x then
|
|
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'AmbulanceActions', k
|
|
end
|
|
end
|
|
|
|
-- Pharmacies
|
|
for k,v in ipairs(hospital.Pharmacies) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(Config.Marker.type, v, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Config.Marker.x, Config.Marker.y, Config.Marker.z, Config.Marker.r, Config.Marker.g, Config.Marker.b, Config.Marker.a, false, false, 2, Config.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
if distance < Config.Marker.x then
|
|
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Pharmacy', k
|
|
end
|
|
end
|
|
|
|
-- Vehicle Spawners
|
|
for k,v in ipairs(hospital.Vehicles) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v.Spawner, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(v.Marker.type, v.Spawner, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Marker.x, v.Marker.y, v.Marker.z, v.Marker.r, v.Marker.g, v.Marker.b, v.Marker.a, false, false, 2, v.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
if distance < v.Marker.x then
|
|
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Vehicles', k
|
|
end
|
|
end
|
|
|
|
-- Helicopter Spawners
|
|
for k,v in ipairs(hospital.Helicopters) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v.Spawner, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(v.Marker.type, v.Spawner, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Marker.x, v.Marker.y, v.Marker.z, v.Marker.r, v.Marker.g, v.Marker.b, v.Marker.a, false, false, 2, v.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
if distance < v.Marker.x then
|
|
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Helicopters', k
|
|
end
|
|
end
|
|
|
|
-- Fast Travels
|
|
for k,v in ipairs(hospital.FastTravels) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v.From, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(v.Marker.type, v.From, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Marker.x, v.Marker.y, v.Marker.z, v.Marker.r, v.Marker.g, v.Marker.b, v.Marker.a, false, false, 2, v.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
|
|
if distance < v.Marker.x then
|
|
FastTravel(v.To.coords, v.To.heading)
|
|
end
|
|
end
|
|
|
|
-- Fast Travels (Prompt)
|
|
for k,v in ipairs(hospital.FastTravelsPrompt) do
|
|
local distance = GetDistanceBetweenCoords(playerCoords, v.From, true)
|
|
|
|
if distance < Config.DrawDistance then
|
|
DrawMarker(v.Marker.type, v.From, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, v.Marker.x, v.Marker.y, v.Marker.z, v.Marker.r, v.Marker.g, v.Marker.b, v.Marker.a, false, false, 2, v.Marker.rotate, nil, nil, false)
|
|
letSleep = false
|
|
end
|
|
|
|
if distance < v.Marker.x then
|
|
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'FastTravelsPrompt', k
|
|
end
|
|
end
|
|
|
|
-- Logic for exiting & entering markers
|
|
if isInMarker and not HasAlreadyEnteredMarker or (isInMarker and (LastHospital ~= currentHospital or LastPart ~= currentPart or LastPartNum ~= currentPartNum)) then
|
|
|
|
if
|
|
(LastHospital ~= nil and LastPart ~= nil and LastPartNum ~= nil) and
|
|
(LastHospital ~= currentHospital or LastPart ~= currentPart or LastPartNum ~= currentPartNum)
|
|
then
|
|
TriggerEvent('esx_ambulancejob:hasExitedMarker', LastHospital, LastPart, LastPartNum)
|
|
hasExited = true
|
|
end
|
|
|
|
HasAlreadyEnteredMarker, LastHospital, LastPart, LastPartNum = true, currentHospital, currentPart, currentPartNum
|
|
|
|
TriggerEvent('esx_ambulancejob:hasEnteredMarker', currentHospital, currentPart, currentPartNum)
|
|
|
|
end
|
|
|
|
if not hasExited and not isInMarker and HasAlreadyEnteredMarker then
|
|
HasAlreadyEnteredMarker = false
|
|
TriggerEvent('esx_ambulancejob:hasExitedMarker', LastHospital, LastPart, LastPartNum)
|
|
end
|
|
|
|
if letSleep then
|
|
Citizen.Wait(500)
|
|
end
|
|
|
|
end
|
|
end
|
|
end)
|
|
|
|
AddEventHandler('esx_ambulancejob:hasEnteredMarker', function(hospital, part, partNum)
|
|
if ESX.PlayerData.job and ESX.PlayerData.job.name == 'ambulance' then
|
|
if part == 'AmbulanceActions' then
|
|
CurrentAction = part
|
|
CurrentActionMsg = _U('actions_prompt')
|
|
CurrentActionData = {}
|
|
elseif part == 'Pharmacy' then
|
|
CurrentAction = part
|
|
CurrentActionMsg = _U('open_pharmacy')
|
|
CurrentActionData = {}
|
|
elseif part == 'Vehicles' then
|
|
CurrentAction = part
|
|
CurrentActionMsg = _U('garage_prompt')
|
|
CurrentActionData = {hospital = hospital, partNum = partNum}
|
|
elseif part == 'Helicopters' then
|
|
CurrentAction = part
|
|
CurrentActionMsg = _U('helicopter_prompt')
|
|
CurrentActionData = {hospital = hospital, partNum = partNum}
|
|
elseif part == 'FastTravelsPrompt' then
|
|
local travelItem = Config.Hospitals[hospital][part][partNum]
|
|
|
|
CurrentAction = part
|
|
CurrentActionMsg = travelItem.Prompt
|
|
CurrentActionData = {to = travelItem.To.coords, heading = travelItem.To.heading}
|
|
end
|
|
end
|
|
end)
|
|
|
|
AddEventHandler('esx_ambulancejob:hasExitedMarker', function(hospital, part, partNum)
|
|
if not isInShopMenu then
|
|
ESX.UI.Menu.CloseAll()
|
|
end
|
|
|
|
CurrentAction = nil
|
|
end)
|
|
|
|
-- Key Controls
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
Citizen.Wait(0)
|
|
|
|
if CurrentAction then
|
|
ESX.ShowHelpNotification(CurrentActionMsg)
|
|
|
|
if IsControlJustReleased(0, Keys['E']) then
|
|
|
|
if CurrentAction == 'AmbulanceActions' then
|
|
OpenAmbulanceActionsMenu()
|
|
elseif CurrentAction == 'Pharmacy' then
|
|
OpenPharmacyMenu()
|
|
elseif CurrentAction == 'Vehicles' then
|
|
OpenVehicleSpawnerMenu(CurrentActionData.hospital, CurrentActionData.partNum)
|
|
elseif CurrentAction == 'Helicopters' then
|
|
OpenHelicopterSpawnerMenu(CurrentActionData.hospital, CurrentActionData.partNum)
|
|
elseif CurrentAction == 'FastTravelsPrompt' then
|
|
FastTravel(CurrentActionData.to, CurrentActionData.heading)
|
|
end
|
|
|
|
CurrentAction = nil
|
|
|
|
end
|
|
|
|
elseif ESX.PlayerData.job ~= nil and ESX.PlayerData.job.name == 'ambulance' and not IsDead then
|
|
if IsControlJustReleased(0, Keys['F6']) then
|
|
OpenMobileAmbulanceActionsMenu()
|
|
end
|
|
else
|
|
Citizen.Wait(500)
|
|
end
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('esx_ambulancejob:putInVehicle')
|
|
AddEventHandler('esx_ambulancejob:putInVehicle', function()
|
|
local playerPed = PlayerPedId()
|
|
local coords = GetEntityCoords(playerPed)
|
|
|
|
if IsAnyVehicleNearPoint(coords, 5.0) then
|
|
local vehicle = GetClosestVehicle(coords, 5.0, 0, 71)
|
|
|
|
if DoesEntityExist(vehicle) then
|
|
local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(vehicle)
|
|
|
|
for i=maxSeats - 1, 0, -1 do
|
|
if IsVehicleSeatFree(vehicle, i) then
|
|
freeSeat = i
|
|
break
|
|
end
|
|
end
|
|
|
|
if freeSeat then
|
|
TaskWarpPedIntoVehicle(playerPed, vehicle, freeSeat)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
function OpenCloakroomMenu()
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'cloakroom',
|
|
{
|
|
title = _U('cloakroom'),
|
|
align = 'top-left',
|
|
elements = {
|
|
{label = _U('ems_clothes_civil'), value = 'citizen_wear'},
|
|
{label = _U('ems_clothes_ems'), value = 'ambulance_wear'},
|
|
}
|
|
}, function(data, menu)
|
|
if data.current.value == 'citizen_wear' then
|
|
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
|
|
TriggerEvent('skinchanger:loadSkin', skin)
|
|
end)
|
|
elseif data.current.value == 'ambulance_wear' then
|
|
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
|
|
if skin.sex == 0 then
|
|
TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_male)
|
|
else
|
|
TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_female)
|
|
end
|
|
end)
|
|
end
|
|
|
|
menu.close()
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
end
|
|
|
|
function OpenVehicleSpawnerMenu(hospital, partNum)
|
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
|
local elements = {
|
|
{label = _U('garage_storeditem'), action = 'garage'},
|
|
{label = _U('garage_storeitem'), action = 'store_garage'},
|
|
{label = _U('garage_buyitem'), action = 'buy_vehicle'}
|
|
}
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle', {
|
|
title = _U('garage_title'),
|
|
align = 'top-left',
|
|
elements = elements
|
|
}, function(data, menu)
|
|
|
|
if data.current.action == 'buy_vehicle' then
|
|
local shopCoords = Config.Hospitals[hospital].Vehicles[partNum].InsideShop
|
|
local shopElements = {}
|
|
|
|
local authorizedVehicles = Config.AuthorizedVehicles[ESX.PlayerData.job.grade_name]
|
|
|
|
if #authorizedVehicles > 0 then
|
|
for k,vehicle in ipairs(authorizedVehicles) do
|
|
table.insert(shopElements, {
|
|
label = ('%s - <span style="color:green;">%s</span>'):format(vehicle.label, _U('shop_item', ESX.Math.GroupDigits(vehicle.price))),
|
|
name = vehicle.label,
|
|
model = vehicle.model,
|
|
price = vehicle.price,
|
|
type = 'car'
|
|
})
|
|
end
|
|
else
|
|
return
|
|
end
|
|
|
|
OpenShopMenu(shopElements, playerCoords, shopCoords)
|
|
elseif data.current.action == 'garage' then
|
|
local garage = {}
|
|
|
|
ESX.TriggerServerCallback('esx_vehicleshop:retrieveJobVehicles', function(jobVehicles)
|
|
if #jobVehicles > 0 then
|
|
for k,v in ipairs(jobVehicles) do
|
|
local props = json.decode(v.vehicle)
|
|
local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
|
|
local label = ('%s - <span style="color:darkgoldenrod;">%s</span>: '):format(vehicleName, props.plate)
|
|
|
|
if v.stored then
|
|
label = label .. ('<span style="color:green;">%s</span>'):format(_U('garage_stored'))
|
|
else
|
|
label = label .. ('<span style="color:darkred;">%s</span>'):format(_U('garage_notstored'))
|
|
end
|
|
|
|
table.insert(garage, {
|
|
label = label,
|
|
stored = v.stored,
|
|
model = props.model,
|
|
vehicleProps = props
|
|
})
|
|
end
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_garage', {
|
|
title = _U('garage_title'),
|
|
align = 'top-left',
|
|
elements = garage
|
|
}, function(data2, menu2)
|
|
if data2.current.stored then
|
|
local foundSpawn, spawnPoint = GetAvailableVehicleSpawnPoint(hospital, 'Vehicles', partNum)
|
|
|
|
if foundSpawn then
|
|
menu2.close()
|
|
|
|
ESX.Game.SpawnVehicle(data2.current.model, spawnPoint.coords, spawnPoint.heading, function(vehicle)
|
|
ESX.Game.SetVehicleProperties(vehicle, data2.current.vehicleProps)
|
|
|
|
TriggerServerEvent('esx_vehicleshop:setJobVehicleState', data2.current.vehicleProps.plate, false)
|
|
ESX.ShowNotification(_U('garage_released'))
|
|
end)
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('garage_notavailable'))
|
|
end
|
|
end, function(data2, menu2)
|
|
menu2.close()
|
|
end)
|
|
|
|
else
|
|
ESX.ShowNotification(_U('garage_empty'))
|
|
end
|
|
end, 'car')
|
|
|
|
elseif data.current.action == 'store_garage' then
|
|
StoreNearbyVehicle(playerCoords)
|
|
end
|
|
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
|
|
end
|
|
|
|
function StoreNearbyVehicle(playerCoords)
|
|
local vehicles, vehiclePlates = ESX.Game.GetVehiclesInArea(playerCoords, 30.0), {}
|
|
|
|
if #vehicles > 0 then
|
|
for k,v in ipairs(vehicles) do
|
|
|
|
-- Make sure the vehicle we're saving is empty, or else it wont be deleted
|
|
if GetVehicleNumberOfPassengers(v) == 0 and IsVehicleSeatFree(v, -1) then
|
|
table.insert(vehiclePlates, {
|
|
vehicle = v,
|
|
plate = ESX.Math.Trim(GetVehicleNumberPlateText(v))
|
|
})
|
|
end
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('garage_store_nearby'))
|
|
return
|
|
end
|
|
|
|
ESX.TriggerServerCallback('esx_ambulancejob:storeNearbyVehicle', function(storeSuccess, foundNum)
|
|
if storeSuccess then
|
|
local vehicleId = vehiclePlates[foundNum]
|
|
local attempts = 0
|
|
ESX.Game.DeleteVehicle(vehicleId.vehicle)
|
|
IsBusy = true
|
|
|
|
Citizen.CreateThread(function()
|
|
while IsBusy do
|
|
Citizen.Wait(0)
|
|
drawLoadingText(_U('garage_storing'), 255, 255, 255, 255)
|
|
end
|
|
end)
|
|
|
|
-- Workaround for vehicle not deleting when other players are near it.
|
|
while DoesEntityExist(vehicleId.vehicle) do
|
|
Citizen.Wait(500)
|
|
attempts = attempts + 1
|
|
|
|
-- Give up
|
|
if attempts > 30 then
|
|
break
|
|
end
|
|
|
|
vehicles = ESX.Game.GetVehiclesInArea(playerCoords, 30.0)
|
|
if #vehicles > 0 then
|
|
for k,v in ipairs(vehicles) do
|
|
if ESX.Math.Trim(GetVehicleNumberPlateText(v)) == vehicleId.plate then
|
|
ESX.Game.DeleteVehicle(v)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
IsBusy = false
|
|
ESX.ShowNotification(_U('garage_has_stored'))
|
|
else
|
|
ESX.ShowNotification(_U('garage_has_notstored'))
|
|
end
|
|
end, vehiclePlates)
|
|
end
|
|
|
|
function GetAvailableVehicleSpawnPoint(hospital, part, partNum)
|
|
local spawnPoints = Config.Hospitals[hospital][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(_U('garage_blocked'))
|
|
return false
|
|
end
|
|
end
|
|
|
|
function OpenHelicopterSpawnerMenu(hospital, partNum)
|
|
local playerCoords = GetEntityCoords(PlayerPedId())
|
|
ESX.PlayerData = ESX.GetPlayerData()
|
|
local elements = {
|
|
{label = _U('helicopter_garage'), action = 'garage'},
|
|
{label = _U('helicopter_store'), action = 'store_garage'},
|
|
{label = _U('helicopter_buy'), action = 'buy_helicopter'}
|
|
}
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'helicopter_spawner', {
|
|
title = _U('helicopter_title'),
|
|
align = 'top-left',
|
|
elements = elements
|
|
}, function(data, menu)
|
|
|
|
if data.current.action == 'buy_helicopter' then
|
|
local shopCoords = Config.Hospitals[hospital].Helicopters[partNum].InsideShop
|
|
local shopElements = {}
|
|
|
|
local authorizedHelicopters = Config.AuthorizedHelicopters[ESX.PlayerData.job.grade_name]
|
|
|
|
if #authorizedHelicopters > 0 then
|
|
for k,helicopter in ipairs(authorizedHelicopters) do
|
|
table.insert(shopElements, {
|
|
label = ('%s - <span style="color:green;">%s</span>'):format(helicopter.label, _U('shop_item', ESX.Math.GroupDigits(helicopter.price))),
|
|
name = helicopter.label,
|
|
model = helicopter.model,
|
|
price = helicopter.price,
|
|
type = 'helicopter'
|
|
})
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('helicopter_notauthorized'))
|
|
return
|
|
end
|
|
|
|
OpenShopMenu(shopElements, playerCoords, shopCoords)
|
|
elseif data.current.action == 'garage' then
|
|
local garage = {}
|
|
|
|
ESX.TriggerServerCallback('esx_vehicleshop:retrieveJobVehicles', function(jobVehicles)
|
|
if #jobVehicles > 0 then
|
|
for k,v in ipairs(jobVehicles) do
|
|
local props = json.decode(v.vehicle)
|
|
local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
|
|
local label = ('%s - <span style="color:darkgoldenrod;">%s</span>: '):format(vehicleName, props.plate)
|
|
|
|
if v.stored then
|
|
label = label .. ('<span style="color:green;">%s</span>'):format(_U('garage_stored'))
|
|
else
|
|
label = label .. ('<span style="color:darkred;">%s</span>'):format(_U('garage_notstored'))
|
|
end
|
|
|
|
table.insert(garage, {
|
|
label = label,
|
|
stored = v.stored,
|
|
model = props.model,
|
|
vehicleProps = props
|
|
})
|
|
end
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'helicopter_garage', {
|
|
title = _U('helicopter_garage_title'),
|
|
align = 'top-left',
|
|
elements = garage
|
|
}, function(data2, menu2)
|
|
if data2.current.stored then
|
|
local foundSpawn, spawnPoint = GetAvailableVehicleSpawnPoint(hospital, 'Helicopters', partNum)
|
|
|
|
if foundSpawn then
|
|
menu2.close()
|
|
|
|
ESX.Game.SpawnVehicle(data2.current.model, spawnPoint.coords, spawnPoint.heading, function(vehicle)
|
|
ESX.Game.SetVehicleProperties(vehicle, data2.current.vehicleProps)
|
|
|
|
TriggerServerEvent('esx_vehicleshop:setJobVehicleState', data2.current.vehicleProps.plate, false)
|
|
ESX.ShowNotification(_U('garage_released'))
|
|
end)
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('garage_notavailable'))
|
|
end
|
|
end, function(data2, menu2)
|
|
menu2.close()
|
|
end)
|
|
|
|
else
|
|
ESX.ShowNotification(_U('garage_empty'))
|
|
end
|
|
end, 'helicopter')
|
|
|
|
elseif data.current.action == 'store_garage' then
|
|
StoreNearbyVehicle(playerCoords)
|
|
end
|
|
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
|
|
end
|
|
|
|
function OpenShopMenu(elements, restoreCoords, shopCoords)
|
|
local playerPed = PlayerPedId()
|
|
isInShopMenu = true
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop', {
|
|
title = _U('vehicleshop_title'),
|
|
align = 'top-left',
|
|
elements = elements
|
|
}, function(data, menu)
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'vehicle_shop_confirm',
|
|
{
|
|
title = _U('vehicleshop_confirm', data.current.name, data.current.price),
|
|
align = 'top-left',
|
|
elements = {
|
|
{ label = _U('confirm_no'), value = 'no' },
|
|
{ label = _U('confirm_yes'), value = 'yes' }
|
|
}
|
|
}, function(data2, menu2)
|
|
|
|
if data2.current.value == 'yes' then
|
|
local newPlate = exports['esx_vehicleshop']:GeneratePlate()
|
|
local vehicle = GetVehiclePedIsIn(playerPed, false)
|
|
local props = ESX.Game.GetVehicleProperties(vehicle)
|
|
props.plate = newPlate
|
|
|
|
ESX.TriggerServerCallback('esx_ambulancejob:buyJobVehicle', function (bought)
|
|
if bought then
|
|
ESX.ShowNotification(_U('vehicleshop_bought', data.current.name, ESX.Math.GroupDigits(data.current.price)))
|
|
|
|
isInShopMenu = false
|
|
ESX.UI.Menu.CloseAll()
|
|
|
|
DeleteSpawnedVehicles()
|
|
FreezeEntityPosition(playerPed, false)
|
|
SetEntityVisible(playerPed, true)
|
|
|
|
ESX.Game.Teleport(playerPed, restoreCoords)
|
|
else
|
|
ESX.ShowNotification(_U('vehicleshop_money'))
|
|
menu2.close()
|
|
end
|
|
end, props, data.current.type)
|
|
else
|
|
menu2.close()
|
|
end
|
|
|
|
end, function(data2, menu2)
|
|
menu2.close()
|
|
end)
|
|
|
|
end, function(data, menu)
|
|
isInShopMenu = false
|
|
ESX.UI.Menu.CloseAll()
|
|
|
|
DeleteSpawnedVehicles()
|
|
FreezeEntityPosition(playerPed, false)
|
|
SetEntityVisible(playerPed, true)
|
|
|
|
ESX.Game.Teleport(playerPed, restoreCoords)
|
|
end, function(data, menu)
|
|
DeleteSpawnedVehicles()
|
|
|
|
WaitForVehicleToLoad(data.current.model)
|
|
ESX.Game.SpawnLocalVehicle(data.current.model, shopCoords, 0.0, function(vehicle)
|
|
table.insert(spawnedVehicles, vehicle)
|
|
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
|
|
FreezeEntityPosition(vehicle, true)
|
|
end)
|
|
end)
|
|
|
|
WaitForVehicleToLoad(elements[1].model)
|
|
ESX.Game.SpawnLocalVehicle(elements[1].model, shopCoords, 0.0, function(vehicle)
|
|
table.insert(spawnedVehicles, vehicle)
|
|
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
|
|
FreezeEntityPosition(vehicle, true)
|
|
end)
|
|
end
|
|
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
Citizen.Wait(0)
|
|
|
|
if isInShopMenu then
|
|
DisableControlAction(0, 75, true) -- Disable exit vehicle
|
|
DisableControlAction(27, 75, true) -- Disable exit vehicle
|
|
else
|
|
Citizen.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 GetHashKey(modelHash))
|
|
|
|
if not HasModelLoaded(modelHash) then
|
|
RequestModel(modelHash)
|
|
|
|
while not HasModelLoaded(modelHash) do
|
|
Citizen.Wait(0)
|
|
|
|
DisableControlAction(0, Keys['TOP'], true)
|
|
DisableControlAction(0, Keys['DOWN'], true)
|
|
DisableControlAction(0, Keys['LEFT'], true)
|
|
DisableControlAction(0, Keys['RIGHT'], true)
|
|
DisableControlAction(0, 176, true) -- ENTER key
|
|
DisableControlAction(0, Keys['BACKSPACE'], true)
|
|
|
|
drawLoadingText(_U('vehicleshop_awaiting_model'), 255, 255, 255, 255)
|
|
end
|
|
end
|
|
end
|
|
|
|
function drawLoadingText(text, red, green, blue, alpha)
|
|
SetTextFont(4)
|
|
SetTextProportional(0)
|
|
SetTextScale(0.0, 0.5)
|
|
SetTextColour(red, green, blue, alpha)
|
|
SetTextDropShadow(0, 0, 0, 0, 255)
|
|
SetTextEdge(1, 0, 0, 0, 255)
|
|
SetTextDropShadow()
|
|
SetTextOutline()
|
|
SetTextCentre(true)
|
|
|
|
BeginTextCommandDisplayText("STRING")
|
|
AddTextComponentSubstringPlayerName(text)
|
|
EndTextCommandDisplayText(0.5, 0.5)
|
|
end
|
|
|
|
function OpenPharmacyMenu()
|
|
ESX.UI.Menu.CloseAll()
|
|
|
|
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'pharmacy',
|
|
{
|
|
title = _U('pharmacy_menu_title'),
|
|
align = 'top-left',
|
|
elements = {
|
|
{label = _U('pharmacy_take', _U('medikit')), value = 'medikit'},
|
|
{label = _U('pharmacy_take', _U('bandage')), value = 'bandage'}
|
|
}
|
|
}, function(data, menu)
|
|
TriggerServerEvent('esx_ambulancejob:giveItem', data.current.value)
|
|
end, function(data, menu)
|
|
menu.close()
|
|
end)
|
|
end
|
|
|
|
function WarpPedInClosestVehicle(ped)
|
|
local coords = GetEntityCoords(ped)
|
|
|
|
local vehicle, distance = ESX.Game.GetClosestVehicle(coords)
|
|
|
|
if distance ~= -1 and distance <= 5.0 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(ped, vehicle, freeSeat)
|
|
end
|
|
else
|
|
ESX.ShowNotification(_U('no_vehicles'))
|
|
end
|
|
end
|
|
|
|
RegisterNetEvent('esx_ambulancejob:heal')
|
|
AddEventHandler('esx_ambulancejob:heal', function(healType)
|
|
local playerPed = PlayerPedId()
|
|
local maxHealth = GetEntityMaxHealth(playerPed)
|
|
|
|
if healType == 'small' then
|
|
local health = GetEntityHealth(playerPed)
|
|
local newHealth = math.min(maxHealth, math.floor(health + maxHealth / 8))
|
|
SetEntityHealth(playerPed, newHealth)
|
|
elseif healType == 'big' then
|
|
SetEntityHealth(playerPed, maxHealth)
|
|
end
|
|
|
|
ESX.ShowNotification(_U('healed'))
|
|
end)
|