This commit is contained in:
2026-07-07 21:08:52 +02:00
commit 4c20cfc716
2613 changed files with 318021 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
function GetShapeTestResultSync(shape)
local handle, hit, coords, normal, entity
repeat handle, hit, coords, normal, entity = GetShapeTestResult(shape)
until handle ~= 1 or Wait()
return hit, coords, normal, entity
end
local camera
local x = 0
local y = 0
local camera_radius = 5
local zoom = Config.zoom
local playerPed
function StartDeathCam()
camera = CreateCamWithParams('DEFAULT_SCRIPTED_CAMERA', 0, 0, 0, 0, 0, 0, GetGameplayCamFov(), 1)
RenderScriptCams(true, true, 1000, true, false)
playerPed = PlayerPedId()
end
function EndDeathCam()
RenderScriptCams(0)
camera = DestroyCam(camera)
end
function ProcessCamControls()
local playerCoords = GetEntityCoords(playerPed)
if camera_radius < zoom.max and IsDisabledControlPressed(0, 14) then
camera_radius += zoom.step
elseif camera_radius > zoom.min and IsDisabledControlPressed(0, 15) then
camera_radius -= zoom.step
end
local coords = ProcessNewPosition(playerCoords)
SetCamCoord(camera, coords)
PointCamAtCoord(camera, playerCoords.x, playerCoords.y, playerCoords.z)
end
function ProcessNewPosition(playerCoords)
x -= GetDisabledControlNormal(0, 1)
y -= GetDisabledControlNormal(0, 2)
if y < math.rad(15) then
y = math.rad(15)
elseif y > math.rad(90) then
y = math.rad(90)
end
local normal = vector3(
math.sin(y) * math.cos(x),
math.sin(y) * math.sin(x),
math.cos(y)
)
local pos = playerCoords + normal * camera_radius
local hit, coords = GetShapeTestResultSync(StartShapeTestLosProbe(playerCoords, pos, -1, playerPed))
return (hit == 1 and playerCoords + normal * (#(playerCoords - coords) - 1)) or pos
end

View File

@@ -0,0 +1,604 @@
local CurrentAction, CurrentActionMsg, CurrentActionData = nil, '', {}
local HasAlreadyEnteredMarker, LastHospital, LastPart, LastPartNum
local isBusy, deadPlayers, deadPlayerBlips, isOnDuty = false, {}, {}, false
isInShopMenu = false
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
ESX.PlayerData = xPlayer
ESX.PlayerLoaded = true
end)
function OpenAmbulanceActionsMenu()
local elements = {
{ unselectable = true, icon = "fas fa-shirt", title = TranslateCap('ambulance') },
{ icon = "fas fa-shirt", title = TranslateCap('cloakroom'), value = 'cloakroom' }
}
if Config.EnablePlayerManagement and ESX.PlayerData.job.grade_name == 'boss' then
elements[#elements + 1] = {
icon = "fas fa-ambulance",
title = TranslateCap('boss_actions'),
value = 'boss_actions'
}
end
ESX.OpenContext("right", elements, function(menu, element)
if element.value == 'cloakroom' then
OpenCloakroomMenu()
elseif element.value == 'boss_actions' then
TriggerEvent('esx_society:openBossMenu', 'ambulance', function(data, menu)
menu.close()
end, { wash = false })
end
end)
end
function OpenMobileAmbulanceActionsMenu()
local elements = {
{ unselectable = true, icon = "fas fa-ambulance", title = TranslateCap('ambulance') },
{ icon = "fas fa-ambulance", title = TranslateCap('ems_menu'), value = "citizen_interaction" }
}
ESX.OpenContext("right", elements, function(menu, element)
if element.value == "citizen_interaction" then
local elements2 = {
{ unselectable = true, icon = "fas fa-ambulance", title = element.title },
{ icon = "fas fa-syringe", title = TranslateCap('ems_menu_revive'), value = "revive" },
{ icon = "fas fa-bandage", title = TranslateCap('ems_menu_small'), value = "small" },
{ icon = "fas fa-bandage", title = TranslateCap('ems_menu_big'), value = "big" },
{ icon = "fas fa-car", title = TranslateCap('ems_menu_putincar'), value = "put_in_vehicle" },
{ icon = "fas fa-syringe", title = TranslateCap('ems_menu_search'), value = "search" },
}
ESX.OpenContext("right", elements2, function(menu2, element2)
if isBusy then return end
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer()
if element2.value == 'search' then
TriggerServerEvent('esx_ambulancejob:svsearch')
elseif closestPlayer == -1 or closestDistance > 1.0 then
ESX.ShowNotification(TranslateCap('no_players'))
else
if element2.value == 'revive' then
revivePlayer(closestPlayer)
elseif element2.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(TranslateCap('heal_inprogress'))
TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true)
Wait(10000)
ClearPedTasks(playerPed)
TriggerServerEvent('esx_ambulancejob:removeItem', 'bandage')
TriggerServerEvent('esx_ambulancejob:heal', GetPlayerServerId(closestPlayer), 'small')
ESX.ShowNotification(TranslateCap('heal_complete', GetPlayerName(closestPlayer)))
isBusy = false
else
ESX.ShowNotification(TranslateCap('player_not_conscious'))
end
else
ESX.ShowNotification(TranslateCap('not_enough_bandage'))
end
end, 'bandage')
elseif element2.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(TranslateCap('heal_inprogress'))
TaskStartScenarioInPlace(playerPed, 'CODE_HUMAN_MEDIC_TEND_TO_DEAD', 0, true)
Wait(10000)
ClearPedTasks(playerPed)
TriggerServerEvent('esx_ambulancejob:removeItem', 'medikit')
TriggerServerEvent('esx_ambulancejob:heal', GetPlayerServerId(closestPlayer), 'big')
ESX.ShowNotification(TranslateCap('heal_complete', GetPlayerName(closestPlayer)))
isBusy = false
else
ESX.ShowNotification(TranslateCap('player_not_conscious'))
end
else
ESX.ShowNotification(TranslateCap('not_enough_medikit'))
end
end, 'medikit')
elseif element2.value == 'put_in_vehicle' then
TriggerServerEvent('esx_ambulancejob:putInVehicle', GetPlayerServerId(closestPlayer))
end
end
end)
end
end)
end
function revivePlayer(closestPlayer)
isBusy = true
ESX.TriggerServerCallback('esx_ambulancejob:getItemAmount', function(quantity)
if quantity > 0 then
local closestPlayerPed = GetPlayerPed(closestPlayer)
local closestPlayerSrc = GetPlayerServerId(closestPlayer)
if Player(closestPlayerSrc).state.isDead then
local playerPed = PlayerPedId()
local lib, anim = 'mini@cpr@char_a@cpr_str', 'cpr_pumpchest'
ESX.ShowNotification(TranslateCap('revive_inprogress'))
for i = 1, 15 do
Wait(900)
ESX.Streaming.RequestAnimDict(lib, function()
TaskPlayAnim(playerPed, lib, anim, 8.0, -8.0, -1, 0, 0.0, false, false, false)
RemoveAnimDict(lib)
end)
end
TriggerServerEvent('esx_ambulancejob:removeItem', 'medikit')
TriggerServerEvent('esx_ambulancejob:revive', GetPlayerServerId(closestPlayer))
else
ESX.ShowNotification(TranslateCap('player_not_unconscious'))
end
else
ESX.ShowNotification(TranslateCap('not_enough_medikit'))
end
isBusy = false
end, 'medikit')
end
function FastTravel(coords, heading)
local playerPed = PlayerPedId()
DoScreenFadeOut(800)
while not IsScreenFadedOut() do
Wait(500)
end
ESX.Game.Teleport(playerPed, coords, function()
DoScreenFadeIn(800)
if heading then
SetEntityHeading(playerPed, heading)
end
end)
end
-- Draw markers & Marker logic
CreateThread(function()
while true do
local sleep = 1500
if ESX.PlayerData.job and ESX.PlayerData.job.name == 'ambulance' then
local playerCoords = GetEntityCoords(PlayerPedId())
local isInMarker, hasExited = 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 = #(playerCoords - v)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < Config.Marker.x then
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'AmbulanceActions', k
end
end
end
-- Pharmacies
for k, v in ipairs(hospital.Pharmacies) do
local distance = #(playerCoords - v)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < Config.Marker.x then
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Pharmacy', k
end
end
end
-- Vehicle Spawners
for k, v in ipairs(hospital.Vehicles) do
local distance = #(playerCoords - v.Spawner)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < v.Marker.x then
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Vehicles', k
end
end
end
-- Helicopter Spawners
for k, v in ipairs(hospital.Helicopters) do
local distance = #(playerCoords - v.Spawner)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < v.Marker.x then
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'Helicopters', k
end
end
end
-- Fast Travels (Prompt)
for k, v in ipairs(hospital.FastTravelsPrompt) do
local distance = #(playerCoords - v.From)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < v.Marker.x then
isInMarker, currentHospital, currentPart, currentPartNum = true, hospitalNum, 'FastTravelsPrompt', k
end
end
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
end
Wait(sleep)
end
end)
AddEventHandler('esx_ambulancejob:hasEnteredMarker', function(hospital, part, partNum)
if part == 'AmbulanceActions' then
CurrentAction = part
CurrentActionMsg = TranslateCap('actions_prompt')
CurrentActionData = {}
elseif part == 'Pharmacy' then
CurrentAction = part
CurrentActionMsg = TranslateCap('open_pharmacy')
CurrentActionData = {}
elseif part == 'Vehicles' then
CurrentAction = part
CurrentActionMsg = TranslateCap('garage_prompt')
CurrentActionData = { hospital = hospital, partNum = partNum }
elseif part == 'Helicopters' then
CurrentAction = part
CurrentActionMsg = TranslateCap('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
ESX.TextUI(CurrentActionMsg)
end)
AddEventHandler('esx_ambulancejob:hasExitedMarker', function(hospital, part, partNum)
if not isInShopMenu then
ESX.CloseContext()
end
ESX.HideUI()
CurrentAction = nil
end)
-- Key Controls
CreateThread(function()
while true do
local sleep = 1500
if CurrentAction then
sleep = 0
if IsControlJustReleased(0, 38) then
if CurrentAction == 'AmbulanceActions' then
OpenAmbulanceActionsMenu()
elseif CurrentAction == 'Pharmacy' then
OpenPharmacyMenu()
elseif CurrentAction == 'Vehicles' then
OpenVehicleSpawnerMenu('car', CurrentActionData.hospital, CurrentAction, CurrentActionData.partNum)
elseif CurrentAction == 'Helicopters' then
OpenVehicleSpawnerMenu('helicopter', CurrentActionData.hospital, CurrentAction, CurrentActionData.partNum)
elseif CurrentAction == 'FastTravelsPrompt' then
FastTravel(CurrentActionData.to, CurrentActionData.heading)
end
CurrentAction = nil
end
end
local playerCoords, letSleep = GetEntityCoords(PlayerPedId()), true
for hospitalNum, hospital in pairs(Config.Hospitals) do
-- Fast Travels
for k, v in ipairs(hospital.FastTravels) do
local distance = #(playerCoords - v.From)
if distance < Config.DrawDistance then
sleep = 0
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)
if distance < v.Marker.x then
FastTravel(v.To.coords, v.To.heading)
end
end
end
end
Wait(sleep)
end
end)
RegisterCommand("ambulance", function(src)
if ESX.PlayerData.job and ESX.PlayerData.job.name == 'ambulance' and not ESX.PlayerData.dead then
OpenMobileAmbulanceActionsMenu()
end
end)
RegisterKeyMapping("ambulance", "Open Ambulance Actions Menu", "keyboard", "F6")
RegisterNetEvent('esx_ambulancejob:putInVehicle')
AddEventHandler('esx_ambulancejob:putInVehicle', function()
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)
end
end
end)
function OpenCloakroomMenu()
local elements = {
{ unselectable = true, icon = "fas fa-shirt", title = TranslateCap('cloakroom') },
{ icon = "fas fa-shirt", title = TranslateCap('ems_clothes_civil'), value = "citizen_wear" },
{ icon = "fas fa-shirt", title = TranslateCap('ems_clothes_ems'), value = "ambulance_wear" },
}
ESX.OpenContext("right", elements, function(menu, element)
if element.value == "citizen_wear" then
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
TriggerEvent('skinchanger:loadSkin', skin)
isOnDuty = false
for playerId, v in pairs(deadPlayerBlips) do
RemoveBlip(v)
deadPlayerBlips[playerId] = nil
end
deadPlayers = {}
if Config.Debug then
print("[^2INFO^7] Off Duty")
end
end)
elseif element.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
isOnDuty = true
ESX.TriggerServerCallback('esx_ambulancejob:getDeadPlayers', function(_deadPlayers)
TriggerEvent('esx_ambulancejob:setDeadPlayers', _deadPlayers)
end)
if Config.Debug then
print("[^2INFO^7] Player Sex |^5" .. tostring(skin.sex) .. "^7")
print("[^2INFO^7] On Duty")
end
end)
end
end)
end
function OpenPharmacyMenu()
local elements = {
{ unselectable = true, icon = "fas fa-pills", title = TranslateCap('pharmacy_menu_title') }
}
for k, v in pairs(Config.PharmacyItems) do
elements[#elements + 1] = {
icon = "fas fa-pills",
title = v.title,
item = v.item
}
end
ESX.OpenContext("right", elements, function(menu, element)
local elements2 = {
{ unselectable = true, icon = "fas fa-pills", title = element.title },
{ title = "Amount", input = true, inputType = "number", inputMin = 1, inputMax = 100,
inputPlaceholder = "Amount to buy.." },
{ icon = "fas fa-check-double", title = "Confirm", val = "confirm" }
}
ESX.OpenContext("right", elements2, function(menu2, element2)
local amount = menu2.eles[2].inputValue
if Config.Debug then
print("[^2INFO^7] Attempting to Give Item - ^5" .. tostring(element.item) .. "^7")
end
TriggerServerEvent('esx_ambulancejob:giveItem', element.item, amount)
end, function(menu)
OpenPharmacyMenu()
end)
end)
end
RegisterNetEvent('esx_ambulancejob:heal')
AddEventHandler('esx_ambulancejob:heal', function(healType, quiet)
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
if Config.Debug then
print("[^2INFO^7] Healing Player - ^5" .. tostring(healType) .. "^7")
end
if not quiet then
ESX.ShowNotification(TranslateCap('healed'))
end
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
if isOnDuty and job.name ~= 'ambulance' then
for playerId, v in pairs(deadPlayerBlips) do
if Config.Debug then
print("[^2INFO^7] Removing dead blip - ^5" .. tostring(playerId) .. "^7")
end
RemoveBlip(v)
deadPlayerBlips[playerId] = nil
end
isOnDuty = false
end
end)
RegisterNetEvent('esx_ambulancejob:PlayerDead')
AddEventHandler('esx_ambulancejob:PlayerDead', function(Player)
if Config.Debug then
print("[^2INFO^7] Player Dead | ^5" .. tostring(Player) .. "^7")
end
deadPlayers[Player] = "dead"
end)
RegisterNetEvent('esx_ambulancejob:PlayerNotDead')
AddEventHandler('esx_ambulancejob:PlayerNotDead', function(Player)
if deadPlayerBlips[Player] then
RemoveBlip(deadPlayerBlips[Player])
deadPlayerBlips[Player] = nil
end
if Config.Debug then
print("[^2INFO^7] Player Alive | ^5" .. tostring(Player) .. "^7")
end
deadPlayers[Player] = nil
end)
RegisterNetEvent('esx_ambulancejob:setDeadPlayers')
AddEventHandler('esx_ambulancejob:setDeadPlayers', function(_deadPlayers)
deadPlayers = _deadPlayers
if isOnDuty then
for playerId, v in pairs(deadPlayerBlips) do
RemoveBlip(v)
deadPlayerBlips[playerId] = nil
end
for playerId, status in pairs(deadPlayers) do
if Config.Debug then
print("[^2INFO^7] Player Dead | ^5" .. tostring(playerId) .. "^7")
end
if status == 'distress' then
if Config.Debug then
print("[^2INFO^7] Creating Distress Blip for Player - ^5" .. tostring(playerId) .. "^7")
end
local player = GetPlayerFromServerId(playerId)
local playerPed = GetPlayerPed(player)
local blip = AddBlipForEntity(playerPed)
SetBlipSprite(blip, 303)
SetBlipColour(blip, 1)
SetBlipFlashes(blip, true)
SetBlipCategory(blip, 7)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(TranslateCap('blip_dead'))
EndTextCommandSetBlipName(blip)
deadPlayerBlips[playerId] = blip
end
end
end
end)
RegisterNetEvent('esx_ambulancejob:PlayerDistressed')
AddEventHandler('esx_ambulancejob:PlayerDistressed', function(playerId, playerCoords)
deadPlayers[playerId] = 'distress'
if isOnDuty then
if Config.Debug then
print("[^2INFO^7] Player Distress Recived - ID:^5" .. tostring(playerId) .. "^7")
end
ESX.ShowNotification(TranslateCap('unconscious_found'), "error", 10000)
deadPlayerBlips[playerId] = nil
local blip = AddBlipForCoord(playerCoords.x, playerCoords.y, playerCoords.z)
SetBlipSprite(blip, Config.DistressBlip.Sprite)
SetBlipColour(blip, Config.DistressBlip.Color)
SetBlipScale(blip, Config.DistressBlip.Scale)
SetBlipFlashes(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(TranslateCap('blip_dead'))
EndTextCommandSetBlipName(blip)
deadPlayerBlips[playerId] = blip
end
end)

View File

@@ -0,0 +1,396 @@
local firstSpawn = true
isDead, isSearched, medic = false, false, 0
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
ESX.PlayerLoaded = true
end)
RegisterNetEvent('esx:onPlayerLogout')
AddEventHandler('esx:onPlayerLogout', function()
ESX.PlayerLoaded = false
firstSpawn = true
end)
AddEventHandler('esx:onPlayerSpawn', function()
if firstSpawn then
firstSpawn = false
return
end
isDead = false
ClearTimecycleModifier()
SetPedMotionBlur(PlayerPedId(), false)
ClearExtraTimecycleModifier()
EndDeathCam()
end)
-- Create blips
CreateThread(function()
for k, v in pairs(Config.Hospitals) do
local blip = AddBlipForCoord(v.Blip.coords)
SetBlipSprite(blip, v.Blip.sprite)
SetBlipScale(blip, v.Blip.scale)
SetBlipColour(blip, v.Blip.color)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(TranslateCap('blip_hospital'))
EndTextCommandSetBlipName(blip)
end
end)
RegisterNetEvent('esx_ambulancejob:clsearch')
AddEventHandler('esx_ambulancejob:clsearch', function(medicId)
local playerPed = PlayerPedId()
if isDead then
local coords = GetEntityCoords(playerPed)
local playersInArea = ESX.Game.GetPlayersInArea(coords, 50.0)
for i = 1, #playersInArea, 1 do
local player = playersInArea[i]
if player == GetPlayerFromServerId(medicId) then
medic = tonumber(medicId)
isSearched = true
break
end
end
end
end)
function OnPlayerDeath()
ESX.CloseContext()
ClearTimecycleModifier()
SetTimecycleModifier("REDMIST_blend")
SetTimecycleModifierStrength(0.7)
SetExtraTimecycleModifier("fp_vig_red")
SetExtraTimecycleModifierStrength(1.0)
SetPedMotionBlur(PlayerPedId(), true)
TriggerServerEvent('esx_ambulancejob:setDeathStatus', true)
StartDeathTimer()
StartDeathCam()
isDead = true
StartDeathLoop()
StartDistressSignal()
if Config.DeathAnim.enabled then
local coords = GetEntityCoords(ESX.PlayerData.ped)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, 0.0, 0.0, false)
ESX.Streaming.RequestAnimDict(Config.DeathAnim.dict)
TaskPlayAnim(ESX.PlayerData.ped, Config.DeathAnim.dict, Config.DeathAnim.name, Config.DeathAnim.fadeIn, Config.DeathAnim.fadeOut,
-1, Config.DeathAnim.flags, Config.DeathAnim.playbackRate, false, false, false)
FreezeEntityPosition(ESX.PlayerData.ped, true)
Citizen.CreateThreadNow(function()
while ESX.PlayerData.dead do
if not IsEntityPlayingAnim(ESX.PlayerData.ped, Config.DeathAnim.dict, Config.DeathAnim.name, 3) then
TaskPlayAnim(ESX.PlayerData.ped, Config.DeathAnim.dict, Config.DeathAnim.name, Config.DeathAnim.fadeIn, Config.DeathAnim.fadeOut,
-1, Config.DeathAnim.flags, Config.DeathAnim.playbackRate, false, false, false)
end
Wait(0)
end
RemoveAnimDict(Config.DeathAnim.dict)
end)
end
end
RegisterNetEvent('esx_ambulancejob:useItem')
AddEventHandler('esx_ambulancejob:useItem', function(itemName)
ESX.CloseContext()
if itemName == 'medikit' then
local lib, anim = 'anim@heists@narcotics@funding@gang_idle', 'gang_chatting_idle01' -- TODO better animations
local playerPed = PlayerPedId()
ESX.Streaming.RequestAnimDict(lib, function()
TaskPlayAnim(playerPed, lib, anim, 8.0, -8.0, -1, 0, 0, false, false, false)
RemoveAnimDict(lib)
Wait(500)
while IsEntityPlayingAnim(playerPed, lib, anim, 3) do
Wait(0)
DisableAllControlActions(0)
end
TriggerEvent('esx_ambulancejob:heal', 'big', true)
ESX.ShowNotification(TranslateCap('used_medikit'))
end)
elseif itemName == 'bandage' then
local lib, anim = 'anim@heists@narcotics@funding@gang_idle', 'gang_chatting_idle01' -- TODO better animations
local playerPed = PlayerPedId()
ESX.Streaming.RequestAnimDict(lib, function()
TaskPlayAnim(playerPed, lib, anim, 8.0, -8.0, -1, 0, 0, false, false, false)
RemoveAnimDict(lib)
Wait(500)
while IsEntityPlayingAnim(playerPed, lib, anim, 3) do
Wait(0)
DisableAllControlActions(0)
end
TriggerEvent('esx_ambulancejob:heal', 'small', true)
ESX.ShowNotification(TranslateCap('used_bandage'))
end)
end
end)
function StartDeathLoop()
CreateThread(function()
while isDead do
DisableAllControlActions(0)
EnableControlAction(0, 47, true) -- G
EnableControlAction(0, 245, true) -- T
EnableControlAction(0, 38, true) -- E
ProcessCamControls()
if isSearched then
local playerPed = PlayerPedId()
local ped = GetPlayerPed(GetPlayerFromServerId(medic))
isSearched = false
AttachEntityToEntity(playerPed, ped, 11816, 0.54, 0.54, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true)
Wait(1000)
DetachEntity(playerPed, true, false)
ClearPedTasksImmediately(playerPed)
end
Wait(0)
end
end)
end
function StartDistressSignal()
CreateThread(function()
local timer = Config.BleedoutTimer
while timer > 0 and isDead do
Wait(0)
timer = timer - 30
SetTextFont(4)
SetTextScale(0.5, 0.5)
SetTextColour(200, 50, 50, 255)
SetTextDropshadow(0.1, 3, 27, 27, 255)
BeginTextCommandDisplayText('STRING')
AddTextComponentSubstringPlayerName(TranslateCap('distress_send'))
EndTextCommandDisplayText(0.446, 0.77)
if IsControlJustReleased(0, 47) then
SendDistressSignal()
break
end
end
end)
end
function SendDistressSignal()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
ESX.ShowNotification(TranslateCap('distress_sent'))
TriggerServerEvent('esx_ambulancejob:onPlayerDistress')
end
function DrawGenericTextThisFrame()
SetTextFont(4)
SetTextScale(0.0, 0.5)
SetTextColour(255, 255, 255, 255)
SetTextDropshadow(0, 0, 0, 0, 255)
SetTextDropShadow()
SetTextOutline()
SetTextCentre(true)
end
function secondsToClock(seconds)
local seconds, hours, mins, secs = tonumber(seconds), 0, 0, 0
if seconds <= 0 then
return 0, 0
else
local hours = string.format('%02.f', math.floor(seconds / 3600))
local mins = string.format('%02.f', math.floor(seconds / 60 - (hours * 60)))
local secs = string.format('%02.f', math.floor(seconds - hours * 3600 - mins * 60))
return mins, secs
end
end
function StartDeathTimer()
local canPayFine = false
if Config.EarlyRespawnFine then
ESX.TriggerServerCallback('esx_ambulancejob:checkBalance', function(canPay)
canPayFine = canPay
end)
end
local earlySpawnTimer = ESX.Math.Round(Config.EarlyRespawnTimer / 1000)
local bleedoutTimer = ESX.Math.Round(Config.BleedoutTimer / 1000)
CreateThread(function()
-- early respawn timer
while earlySpawnTimer > 0 and isDead do
Wait(1000)
if earlySpawnTimer > 0 then
earlySpawnTimer = earlySpawnTimer - 1
end
end
-- bleedout timer
while bleedoutTimer > 0 and isDead do
Wait(1000)
if bleedoutTimer > 0 then
bleedoutTimer = bleedoutTimer - 1
end
end
end)
CreateThread(function()
local text, timeHeld
-- early respawn timer
while earlySpawnTimer > 0 and isDead do
Wait(0)
text = TranslateCap('respawn_available_in', secondsToClock(earlySpawnTimer))
DrawGenericTextThisFrame()
BeginTextCommandDisplayText('STRING')
AddTextComponentSubstringPlayerName(text)
EndTextCommandDisplayText(0.5, 0.8)
end
-- bleedout timer
while bleedoutTimer > 0 and isDead do
Wait(0)
text = TranslateCap('respawn_bleedout_in', secondsToClock(bleedoutTimer))
if not Config.EarlyRespawnFine then
text = text .. TranslateCap('respawn_bleedout_prompt')
if IsControlPressed(0, 38) and timeHeld > 120 then
RemoveItemsAfterRPDeath()
break
end
elseif Config.EarlyRespawnFine and canPayFine then
text = text .. TranslateCap('respawn_bleedout_fine', ESX.Math.GroupDigits(Config.EarlyRespawnFineAmount))
if IsControlPressed(0, 38) and timeHeld > 120 then
TriggerServerEvent('esx_ambulancejob:payFine')
RemoveItemsAfterRPDeath()
break
end
end
if IsControlPressed(0, 38) then
timeHeld += 1
else
timeHeld = 0
end
DrawGenericTextThisFrame()
BeginTextCommandDisplayText('STRING')
AddTextComponentSubstringPlayerName(text)
EndTextCommandDisplayText(0.5, 0.8)
end
if bleedoutTimer < 1 and isDead then
RemoveItemsAfterRPDeath()
end
end)
end
function GetClosestRespawnPoint()
local plyCoords = GetEntityCoords(PlayerPedId())
local closestDist, closestHospital
for i=1, #Config.RespawnPoints do
local dist = #(plyCoords - Config.RespawnPoints[i].coords)
if not closestDist or dist <= closestDist then
closestDist, closestHospital = dist, Config.RespawnPoints[i]
end
end
return closestHospital
end
function RemoveItemsAfterRPDeath()
TriggerServerEvent('esx_ambulancejob:setDeathStatus', false)
CreateThread(function()
ESX.TriggerServerCallback('esx_ambulancejob:removeItemsAfterRPDeath', function()
local ClosestHospital = GetClosestRespawnPoint()
ESX.SetPlayerData('loadout', {})
DoScreenFadeOut(800)
RespawnPed(PlayerPedId(), ClosestHospital.coords, ClosestHospital.heading)
while not IsScreenFadedOut() do
Wait(0)
end
DoScreenFadeIn(800)
end)
end)
end
function RespawnPed(ped, coords, heading)
SetEntityCoordsNoOffset(ped, coords.x, coords.y, coords.z, false, false, false)
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, heading, true, false)
SetPlayerInvincible(ped, false)
ClearPedBloodDamage(ped)
if Config.DeathAnim.enabled then
FreezeEntityPosition(ped, false)
end
TriggerEvent('esx_basicneeds:resetStatus')
TriggerServerEvent('esx:onPlayerSpawn')
TriggerEvent('esx:onPlayerSpawn')
TriggerEvent('playerSpawned') -- compatibility with old scripts, will be removed soon
end
RegisterNetEvent('esx_phone:loaded')
AddEventHandler('esx_phone:loaded', function(phoneNumber, contacts)
local specialContact = {name = 'Ambulance', number = 'ambulance',
base64Icon = 'data:image/png;base64,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'}
TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon)
end)
AddEventHandler('esx:onPlayerDeath', function(data)
OnPlayerDeath()
end)
RegisterNetEvent('esx_ambulancejob:revive')
AddEventHandler('esx_ambulancejob:revive', function()
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
TriggerServerEvent('esx_ambulancejob:setDeathStatus', false)
DoScreenFadeOut(800)
while not IsScreenFadedOut() do
Wait(50)
end
local formattedCoords = {x = ESX.Math.Round(coords.x, 1), y = ESX.Math.Round(coords.y, 1), z = ESX.Math.Round(coords.z, 1)}
RespawnPed(playerPed, formattedCoords, 0.0)
isDead = false
ClearTimecycleModifier()
SetPedMotionBlur(playerPed, false)
ClearExtraTimecycleModifier()
EndDeathCam()
DoScreenFadeIn(800)
end)
-- Load unloaded IPLs
if Config.LoadIpl then
RequestIpl('Coroner_Int_on') -- Morgue
end

View File

@@ -0,0 +1,314 @@
local spawnedVehicles = {}
function OpenVehicleSpawnerMenu(type, hospital, 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 authorizedVehicles = Config.AuthorizedVehicles[type][ESX.PlayerData.job.grade_name]
local shopCoords = Config.Hospitals[hospital][part][partNum].InsideShop
if #authorizedVehicles > 0 then
for k,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
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 k,v in ipairs(jobVehicles) do
local props = json.decode(v.vehicle)
if IsModelInCdimage(props.model) then
local vehicleName = GetLabelText(GetDisplayNameFromVehicleModel(props.model))
local label = ('%s - <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 then
local foundSpawn, spawnPoint = GetAvailableVehicleSpawnPoint(hospital, 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('esx_ambulancejob:storeNearbyVehicle', function(plate)
if plate then
local vehicleId = index[plate]
local attempts = 0
ESX.Game.DeleteVehicle(vehicleId)
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(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(TranslateCap('garage_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 = "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.xyz, shopCoords.w, 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 = "Buy", value = "buy"},
{icon = "fas fa-eye", title = "Stop Viewing", value = "stop"}
}
ESX.OpenContext("right", elements3, function(menu3,element3)
if element3.value == 'stop' then
isInShopMenu = false
ESX.CloseContext()
DeleteSpawnedVehicles()
FreezeEntityPosition(playerPed, false)
SetEntityVisible(playerPed, 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('esx_ambulancejob: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(playerPed, 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(playerPed, true)
ESX.Game.Teleport(playerPed, restoreCoords)
end)
end
end)
end)
end
CreateThread(function()
while true do
sleep = 1500
if isInShopMenu then
sleep = 0
DisableControlAction(0, 75, true) -- Disable exit vehicle
DisableControlAction(27, 75, true) -- Disable exit vehicle
end
Wait(sleep)
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