From e2a6cde40b6c9c9501cdfdd15b588f801e8bf407 Mon Sep 17 00:00:00 2001 From: Mycroft Date: Mon, 1 Aug 2022 17:55:02 +0100 Subject: [PATCH] Feat: ESX_Ambulancejob: Allow Camera movement while dead --- [esx_addons]/esx_ambulancejob/client/main.lua | 625 ++++++++++-------- 1 file changed, 364 insertions(+), 261 deletions(-) diff --git a/[esx_addons]/esx_ambulancejob/client/main.lua b/[esx_addons]/esx_ambulancejob/client/main.lua index a68033ec..57224f8d 100644 --- a/[esx_addons]/esx_ambulancejob/client/main.lua +++ b/[esx_addons]/esx_ambulancejob/client/main.lua @@ -4,375 +4,478 @@ isDead, isSearched, medic = false, false, 0 RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(xPlayer) - ESX.PlayerLoaded = true + ESX.PlayerLoaded = true end) RegisterNetEvent('esx:onPlayerLogout') AddEventHandler('esx:onPlayerLogout', function() - ESX.PlayerLoaded = false - firstSpawn = true + ESX.PlayerLoaded = false + firstSpawn = true end) AddEventHandler('esx:onPlayerSpawn', function() - isDead = false + isDead = false + ClearTimecycleModifier() + SetPedMotionBlur(PlayerPedId(), false) + ClearExtraTimecycleModifier() + EndDeathCam() + if firstSpawn then + firstSpawn = false - if firstSpawn then - firstSpawn = false + if Config.SaveDeathStatus then + while not ESX.PlayerLoaded do + Wait(1000) + end - if Config.SaveDeathStatus then - while not ESX.PlayerLoaded do - Wait(1000) - end - - ESX.TriggerServerCallback('esx_ambulancejob:getDeathStatus', function(shouldDie) - if shouldDie then - Wait(1000) - SetEntityHealth(PlayerPedId(), 0) - end - end) - end - end + ESX.TriggerServerCallback('esx_ambulancejob:getDeathStatus', function(shouldDie) + if shouldDie then + Wait(1000) + SetEntityHealth(PlayerPedId(), 0) + end + end) + end + end end) -- Create blips CreateThread(function() - for k,v in pairs(Config.Hospitals) do - local blip = AddBlipForCoord(v.Blip.coords) + 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) + SetBlipSprite(blip, v.Blip.sprite) + SetBlipScale(blip, v.Blip.scale) + SetBlipColour(blip, v.Blip.color) + SetBlipAsShortRange(blip, true) - BeginTextCommandSetBlipName('STRING') - AddTextComponentSubstringPlayerName(_U('blip_hospital')) - EndTextCommandSetBlipName(blip) - end + BeginTextCommandSetBlipName('STRING') + AddTextComponentSubstringPlayerName(_U('blip_hospital')) + EndTextCommandSetBlipName(blip) + end - while true do - local Sleep = 1500 - - if isDead then - Sleep = 0 - DisableAllControlActions(0) - EnableControlAction(0, 47, true) -- G - EnableControlAction(0, 245, true) -- T - EnableControlAction(0, 38, true) -- E + while true do + local Sleep = 1500 - 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 - end + if isDead then + Sleep = 0 + DisableAllControlActions(0) + EnableControlAction(0, 47, true) -- G + EnableControlAction(0, 245, true) -- T + EnableControlAction(0, 38, true) -- E - Wait(Sleep) - end + 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 + end + + Wait(Sleep) + end end) RegisterNetEvent('esx_ambulancejob:clsearch') AddEventHandler('esx_ambulancejob:clsearch', function(medicId) - local playerPed = PlayerPedId() + local playerPed = PlayerPedId() - if isDead then - local coords = GetEntityCoords(playerPed) - local playersInArea = ESX.Game.GetPlayersInArea(coords, 50.0) + 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 + 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() - isDead = true - ESX.UI.Menu.CloseAll() - ESX.HideUI() - TriggerServerEvent('esx_ambulancejob:setDeathStatus', true) - StartDeathTimer() - StartDistressSignal() + isDead = true + ESX.UI.Menu.CloseAll() + ClearTimecycleModifier() + SetTimecycleModifier("REDMIST_blend") + SetTimecycleModifierStrength(0.7) + SetExtraTimecycleModifier("fp_vig_red") + SetExtraTimecycleModifierStrength(1.0) + SetPedMotionBlur(PlayerPedId(), true) + TriggerServerEvent('esx_ambulancejob:setDeathStatus', true) + StartDeathTimer() + StartDeathCam() + StartDistressSignal() end RegisterNetEvent('esx_ambulancejob:useItem') AddEventHandler('esx_ambulancejob:useItem', function(itemName) - ESX.UI.Menu.CloseAll() + ESX.UI.Menu.CloseAll() - if itemName == 'medikit' then - local lib, anim = 'anim@heists@narcotics@funding@gang_idle', 'gang_chatting_idle01' -- TODO better animations - local playerPed = PlayerPedId() + 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) + 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 + Wait(500) + while IsEntityPlayingAnim(playerPed, lib, anim, 3) do + Wait(0) + DisableAllControlActions(0) + end - TriggerEvent('esx_ambulancejob:heal', 'big', true) - ESX.ShowNotification(_U('used_medikit')) - end) + TriggerEvent('esx_ambulancejob:heal', 'big', true) + ESX.ShowNotification(_U('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() + 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) + 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 + Wait(500) + while IsEntityPlayingAnim(playerPed, lib, anim, 3) do + Wait(0) + DisableAllControlActions(0) + end - TriggerEvent('esx_ambulancejob:heal', 'small', true) - ESX.ShowNotification(_U('used_bandage')) - end) - end + TriggerEvent('esx_ambulancejob:heal', 'small', true) + ESX.ShowNotification(_U('used_bandage')) + end) + end end) function StartDistressSignal() - CreateThread(function() - local timer = Config.BleedoutTimer + CreateThread(function() + local timer = Config.BleedoutTimer - while timer > 0 and isDead do - Wait(0) - timer = timer - 30 + 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(_U('distress_send')) - EndTextCommandDisplayText(0.43, 0.77) + SetTextFont(4) + SetTextScale(0.5, 0.5) + SetTextColour(200, 50, 50, 255) + SetTextDropshadow(0.1, 3, 27, 27, 255) + BeginTextCommandDisplayText('STRING') + AddTextComponentSubstringPlayerName(_U('distress_send')) + EndTextCommandDisplayText(0.43, 0.77) - if IsControlJustReleased(0, 47) then - SendDistressSignal() - break - end - end - end) + if IsControlJustReleased(0, 47) then + SendDistressSignal() + break + end + end + end) end function SendDistressSignal() - local playerPed = PlayerPedId() - local coords = GetEntityCoords(playerPed) + local playerPed = PlayerPedId() + local coords = GetEntityCoords(playerPed) - ESX.ShowNotification(_U('distress_sent')) - TriggerServerEvent('esx_ambulancejob:onPlayerDistress') + ESX.ShowNotification(_U('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) + 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 + 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)) + 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 + return mins, secs + end end function StartDeathTimer() - local canPayFine = false + local canPayFine = false - if Config.EarlyRespawnFine then - ESX.TriggerServerCallback('esx_ambulancejob:checkBalance', function(canPay) - canPayFine = canPay - end) - end + 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) + 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) + CreateThread(function() + -- early respawn timer + while earlySpawnTimer > 0 and isDead do + Wait(1000) - if earlySpawnTimer > 0 then - earlySpawnTimer = earlySpawnTimer - 1 - end - end + if earlySpawnTimer > 0 then + earlySpawnTimer = earlySpawnTimer - 1 + end + end - -- bleedout timer - while bleedoutTimer > 0 and isDead do - Wait(1000) + -- bleedout timer + while bleedoutTimer > 0 and isDead do + Wait(1000) - if bleedoutTimer > 0 then - bleedoutTimer = bleedoutTimer - 1 - end - end - end) + if bleedoutTimer > 0 then + bleedoutTimer = bleedoutTimer - 1 + end + end + end) - CreateThread(function() - local text, timeHeld + CreateThread(function() + local text, timeHeld - -- early respawn timer - while earlySpawnTimer > 0 and isDead do - Wait(0) - text = _U('respawn_available_in', secondsToClock(earlySpawnTimer)) + -- early respawn timer + while earlySpawnTimer > 0 and isDead do + Wait(0) + text = _U('respawn_available_in', secondsToClock(earlySpawnTimer)) - DrawGenericTextThisFrame() - BeginTextCommandDisplayText('STRING') - AddTextComponentSubstringPlayerName(text) - EndTextCommandDisplayText(0.5, 0.8) - end + DrawGenericTextThisFrame() + BeginTextCommandDisplayText('STRING') + AddTextComponentSubstringPlayerName(text) + EndTextCommandDisplayText(0.5, 0.8) + end - -- bleedout timer - while bleedoutTimer > 0 and isDead do - Wait(0) - text = _U('respawn_bleedout_in', secondsToClock(bleedoutTimer)) + -- bleedout timer + while bleedoutTimer > 0 and isDead do + Wait(0) + text = _U('respawn_bleedout_in', secondsToClock(bleedoutTimer)) - if not Config.EarlyRespawnFine then - text = text .. _U('respawn_bleedout_prompt') + if not Config.EarlyRespawnFine then + text = text .. _U('respawn_bleedout_prompt') - if IsControlPressed(0, 38) and timeHeld > 120 then - RemoveItemsAfterRPDeath() - break - end - elseif Config.EarlyRespawnFine and canPayFine then - text = text .. _U('respawn_bleedout_fine', ESX.Math.GroupDigits(Config.EarlyRespawnFineAmount)) + if IsControlPressed(0, 38) and timeHeld > 120 then + RemoveItemsAfterRPDeath() + break + end + elseif Config.EarlyRespawnFine and canPayFine then + text = text .. _U('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) and timeHeld > 120 then + TriggerServerEvent('esx_ambulancejob:payFine') + RemoveItemsAfterRPDeath() + break + end + end - if IsControlPressed(0, 38) then - timeHeld += 1 - else - timeHeld = 0 - end + if IsControlPressed(0, 38) then + timeHeld += 1 + else + timeHeld = 0 + end - DrawGenericTextThisFrame() + DrawGenericTextThisFrame() - BeginTextCommandDisplayText('STRING') - AddTextComponentSubstringPlayerName(text) - EndTextCommandDisplayText(0.5, 0.8) - end + BeginTextCommandDisplayText('STRING') + AddTextComponentSubstringPlayerName(text) + EndTextCommandDisplayText(0.5, 0.8) + end - if bleedoutTimer < 1 and isDead then - RemoveItemsAfterRPDeath() - end - end) + if bleedoutTimer < 1 and isDead then + RemoveItemsAfterRPDeath() + end + end) end function GetClosestRespawnPoint() - local PlyCoords = GetEntityCoords(PlayerPedId()) - local ClosestDist, ClosestHospital, ClosestCoord = 10000, {}, nil + local PlyCoords = GetEntityCoords(PlayerPedId()) + local ClosestDist, ClosestHospital, ClosestCoord = 10000, {}, nil - for k,v in pairs(Config.RespawnPoints) do - local Distance = #(PlyCoords - vector3(v.coords.x, v.coords.y, v.coords.z)) - if Distance <= ClosestDist then - ClosestDist = Distance - ClosestHospital = v - ClosestCoord = vector3(v.coords.x, v.coords.y, v.coords.z) - end - end + for k, v in pairs(Config.RespawnPoints) do + local Distance = #(PlyCoords - vector3(v.coords.x, v.coords.y, v.coords.z)) + if Distance <= ClosestDist then + ClosestDist = Distance + ClosestHospital = v + ClosestCoord = vector3(v.coords.x, v.coords.y, v.coords.z) + end + end - return ClosestCoord, ClosestHospital + return ClosestCoord, ClosestHospital end function RemoveItemsAfterRPDeath() - TriggerServerEvent('esx_ambulancejob:setDeathStatus', false) + TriggerServerEvent('esx_ambulancejob:setDeathStatus', false) - CreateThread(function() - ESX.TriggerServerCallback('esx_ambulancejob:removeItemsAfterRPDeath', function() - local RespawnCoords, ClosestHospital = GetClosestRespawnPoint() - - ESX.SetPlayerData('loadout', {}) + CreateThread(function() + ESX.TriggerServerCallback('esx_ambulancejob:removeItemsAfterRPDeath', function() + local RespawnCoords, ClosestHospital = GetClosestRespawnPoint() - DoScreenFadeOut(800) - RespawnPed(PlayerPedId(), RespawnCoords, ClosestHospital.heading) - while not IsScreenFadedOut() do - Wait(0) - end - DoScreenFadeIn(800) - end) - end) + ESX.SetPlayerData('loadout', {}) + + DoScreenFadeOut(800) + RespawnPed(PlayerPedId(), RespawnCoords, 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) + 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) - TriggerServerEvent('esx:onPlayerSpawn') - TriggerEvent('esx:onPlayerSpawn') - TriggerEvent('playerSpawned') -- compatibility with old scripts, will be removed soon + 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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' - } + 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) + TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon) end) AddEventHandler('esx:onPlayerDeath', function(data) - OnPlayerDeath() + 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) + local playerPed = PlayerPedId() + local coords = GetEntityCoords(playerPed) + TriggerServerEvent('esx_ambulancejob:setDeathStatus', false) - while not IsScreenFadedOut() do - Wait(50) - end + DoScreenFadeOut(800) - local formattedCoords = { - x = ESX.Math.Round(coords.x, 1), - y = ESX.Math.Round(coords.y, 1), - z = ESX.Math.Round(coords.z, 1) - } + while not IsScreenFadedOut() do + Wait(50) + end - RespawnPed(playerPed, formattedCoords, 0.0) - isDead = false - DoScreenFadeIn(800) + 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 + RequestIpl('Coroner_Int_on') -- Morgue +end + +local cam = nil + +local isDead = false + +local angleY = 0.0 + +local angleZ = 0.0 + +------------------------------------------------------- + +-----------------DEATH CAMERA FUNCTIONS --------------- + +-------------------------------------------------------- + +-- initialize camera + +function StartDeathCam() + ClearFocus() + local playerPed = PlayerPedId() + cam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", GetEntityCoords(playerPed), 0, 0, 0, GetGameplayCamFov()) + SetCamActive(cam, true) + RenderScriptCams(true, true, 1000, true, false) +end + +-- destroy camera + +function EndDeathCam() + ClearFocus() + RenderScriptCams(false, false, 0, true, false) + DestroyCam(cam, false) + cam = nil +end +-- process camera controls +function ProcessCamControls() + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + -- disable 1st person as the 1st person camera can cause some glitches + DisableFirstPersonCamThisFrame() + -- calculate new position + local newPos = ProcessNewPosition() + SetFocusArea(newPos.x, newPos.y, newPos.z, 0.0, 0.0, 0.0) + -- set coords of cam + SetCamCoord(cam, newPos.x, newPos.y, newPos.z) + -- set rotation + PointCamAtCoord(cam, playerCoords.x, playerCoords.y, playerCoords.z + 0.5) +end + +function ProcessNewPosition() + local mouseX = 0.0 + local mouseY = 0.0 + -- keyboard + if (IsInputDisabled(0)) then + -- rotation + mouseX = GetDisabledControlNormal(1, 1) * 8.0 + + mouseY = GetDisabledControlNormal(1, 2) * 8.0 + -- controller + else + mouseX = GetDisabledControlNormal(1, 1) * 1.5 + + mouseY = GetDisabledControlNormal(1, 2) * 1.5 + end + + angleZ = angleZ - mouseX -- around Z axis (left / right) + + angleY = angleY + mouseY -- up / down + -- limit up / down angle to 90° + + if (angleY > 89.0) then + angleY = 89.0 + elseif (angleY < -89.0) then + angleY = -89.0 + end + local pCoords = GetEntityCoords(PlayerPedId()) + local behindCam = {x = pCoords.x + ((Cos(angleZ) * Cos(angleY)) + (Cos(angleY) * Cos(angleZ))) / 2 * (5.5 + 0.5), + + y = pCoords.y + ((Sin(angleZ) * Cos(angleY)) + (Cos(angleY) * Sin(angleZ))) / 2 * (5.5 + 0.5), + + z = pCoords.z + ((Sin(angleY))) * (5.5 + 0.5)} + local rayHandle = StartShapeTestRay(pCoords.x, pCoords.y, pCoords.z + 0.5, behindCam.x, behindCam.y, behindCam.z, -1, PlayerPedId(), 0) + + local a, hitBool, hitCoords, surfaceNormal, entityHit = GetShapeTestResult(rayHandle) + + local maxRadius = 1.9 + if (hitBool and Vdist(pCoords.x, pCoords.y, pCoords.z + 0.5, hitCoords) < 5.5 + 0.5) then + maxRadius = Vdist(pCoords.x, pCoords.y, pCoords.z + 0.5, hitCoords) + end + + local offset = {x = ((Cos(angleZ) * Cos(angleY)) + (Cos(angleY) * Cos(angleZ))) / 2 * maxRadius, + y = ((Sin(angleZ) * Cos(angleY)) + (Cos(angleY) * Sin(angleZ))) / 2 * maxRadius, z = ((Sin(angleY))) * maxRadius} + + local pos = {x = pCoords.x + offset.x, y = pCoords.y + offset.y, z = pCoords.z + offset.z} + + return pos end