mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-09-03 11:48:53 +00:00
Merge branch 'esx-framework:main' into main
This commit is contained in:
@@ -35,7 +35,7 @@ function Async.parallelLimit(tasks, limit, cb)
|
||||
local queue, results = {}, {}
|
||||
|
||||
for i=1, #tasks, 1 do
|
||||
queue[queue + 1] = tasks[i]
|
||||
queue[#queue + 1] = tasks[i]
|
||||
end
|
||||
|
||||
local function processQueue()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
PREVIEW_KEYBIND = false -- "LMENU"
|
||||
@@ -11,6 +11,7 @@ ui_page 'index.html'
|
||||
shared_script '@es_extended/imports.lua'
|
||||
|
||||
client_scripts {
|
||||
'config.lua',
|
||||
'main.lua',
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@@ -286,9 +287,13 @@
|
||||
})
|
||||
|
||||
window.addEventListener("keydown",(e) => {
|
||||
if (e.key == "Escape" || e.key == "Backspace") {
|
||||
Close()
|
||||
}
|
||||
if (e.key == "Escape" || e.key == "Backspace") {
|
||||
if (e.target.tagName.toLowerCase() == "input") {
|
||||
return
|
||||
}
|
||||
|
||||
Close()
|
||||
}
|
||||
})
|
||||
|
||||
// Open([
|
||||
|
||||
+68
-45
@@ -20,6 +20,8 @@ function Open(position,eles,onSelect,onClose)
|
||||
onClose = onClose
|
||||
}
|
||||
|
||||
LocalPlayer.state:set("context:active",true)
|
||||
|
||||
Post("Open",eles,position)
|
||||
end
|
||||
|
||||
@@ -31,6 +33,8 @@ function Closed()
|
||||
|
||||
activeMenu = nil
|
||||
|
||||
LocalPlayer.state:set("context:active",false)
|
||||
|
||||
if cb then
|
||||
cb(menu)
|
||||
end
|
||||
@@ -95,7 +99,7 @@ RegisterNUICallback("selected",function(data)
|
||||
return
|
||||
end
|
||||
|
||||
activeMenu.onSelect(activeMenu,ele)
|
||||
activeMenu:onSelect(ele)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("changed",function(data)
|
||||
@@ -130,62 +134,81 @@ RegisterNUICallback("changed",function(data)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Keybind
|
||||
|
||||
local function focusPreview()
|
||||
if not activeMenu
|
||||
or not activeMenu.onSelect
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
SetNuiFocus(true,true)
|
||||
end
|
||||
|
||||
if PREVIEW_KEYBIND then
|
||||
RegisterCommand("previewContext",focusPreview)
|
||||
|
||||
RegisterKeyMapping("previewContext","Preview Active Context","keyboard",PREVIEW_KEYBIND)
|
||||
end
|
||||
|
||||
exports("focusPreview",focusPreview)
|
||||
|
||||
-- Debug/Test
|
||||
-- Commands:
|
||||
-- [ ctx:preview | ctx:open | ctx:close | ctx:form ]
|
||||
|
||||
local position = "right"
|
||||
if Debug then
|
||||
local position = "right"
|
||||
|
||||
local eles = {
|
||||
{
|
||||
unselectable=true,
|
||||
icon="fas fa-info-circle",
|
||||
title="Unselectable Item (Header/Label?)",
|
||||
},
|
||||
{
|
||||
icon="fas fa-check",
|
||||
title="Item A",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
{
|
||||
disabled=true,
|
||||
icon="fas fa-times",
|
||||
title="Disabled Item",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
{
|
||||
icon="fas fa-check",
|
||||
title="Item B",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
}
|
||||
local eles = {
|
||||
{
|
||||
unselectable=true,
|
||||
icon="fas fa-info-circle",
|
||||
title="Unselectable Item (Header/Label?)",
|
||||
},
|
||||
{
|
||||
icon="fas fa-check",
|
||||
title="Item A",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
{
|
||||
disabled=true,
|
||||
icon="fas fa-times",
|
||||
title="Disabled Item",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
{
|
||||
icon="fas fa-check",
|
||||
title="Item B",
|
||||
description="Some description here. Add some words to make the text overflow."
|
||||
},
|
||||
}
|
||||
|
||||
local function onSelect(menu,ele)
|
||||
print("Ele selected",ele.title)
|
||||
local function onSelect(menu,ele)
|
||||
print("Ele selected",ele.title)
|
||||
|
||||
if ele.name == "close" then
|
||||
exports["esx_context"]:Close()
|
||||
end
|
||||
|
||||
if ele.name ~= "submit" then
|
||||
return
|
||||
end
|
||||
|
||||
for _,ele in ipairs(menu.eles) do
|
||||
if ele.input then
|
||||
print(ele.name,ele.inputType,ele.inputValue)
|
||||
end
|
||||
end
|
||||
|
||||
if ele.name == "close" then
|
||||
exports["esx_context"]:Close()
|
||||
end
|
||||
|
||||
if ele.name ~= "submit" then
|
||||
return
|
||||
local function onClose(menu)
|
||||
print("Menu closed.")
|
||||
end
|
||||
|
||||
for _,ele in ipairs(menu.eles) do
|
||||
if ele.input then
|
||||
print(ele.name,ele.inputType,ele.inputValue)
|
||||
end
|
||||
end
|
||||
|
||||
exports["esx_context"]:Close()
|
||||
end
|
||||
|
||||
local function onClose(menu)
|
||||
print("Menu closed.")
|
||||
end
|
||||
|
||||
|
||||
if Debug then
|
||||
RegisterCommand("ctx:preview",function()
|
||||
exports["esx_context"]:Preview(position,eles)
|
||||
end)
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
local CurrentProgress = nil
|
||||
local function Progressbar(message,length,Options)
|
||||
if Options.animation then
|
||||
if Options.animation.type == "anim" then
|
||||
ESX.Streaming.RequestAnimDict(Options.animation.dict, function()
|
||||
TaskPlayAnim(ESX.PlayerData.ped, Options.animation.dict, Options.animation.lib, 1.0, 1.0, length, 1, 1.0, false,false,false)
|
||||
RemoveAnimDict(Options.animation.dict)
|
||||
end)
|
||||
local Canceled = false
|
||||
if not CurrentProgress then
|
||||
CurrentProgress = Options or {}
|
||||
if CurrentProgress.animation then
|
||||
if CurrentProgress.animation.type == "anim" then
|
||||
ESX.Streaming.RequestAnimDict(CurrentProgress.animation.dict, function()
|
||||
TaskPlayAnim(ESX.PlayerData.ped, CurrentProgress.animation.dict, CurrentProgress.animation.lib, 1.0, 1.0, length, 1, 1.0, false,false,false)
|
||||
RemoveAnimDict(CurrentProgress.animation.dict)
|
||||
end)
|
||||
elseif CurrentProgress.animation.type == "Scenario" then
|
||||
TaskStartScenarioInPlace(ESX.PlayerData.ped, CurrentProgress.animation.Scenario, 0, true)
|
||||
end
|
||||
end
|
||||
if CurrentProgress.FreezePlayer then FreezeEntityPosition(PlayerPedId(),CurrentProgress.FreezePlayer) end
|
||||
SendNuiMessage(json.encode({
|
||||
type = "Progressbar",
|
||||
length = length or 3000,
|
||||
message = message or "ESX-Framework"
|
||||
}))
|
||||
CurrentProgress.length = length or 3000
|
||||
while CurrentProgress ~= nil do
|
||||
if CurrentProgress.length > 0 then
|
||||
CurrentProgress.length -= 1000
|
||||
else
|
||||
ClearPedTasks(ESX.PlayerData.ped)
|
||||
if CurrentProgress.FreezePlayer then FreezeEntityPosition(PlayerPedId(), false) end
|
||||
if CurrentProgress.onFinish then CurrentProgress.onFinish() end
|
||||
CurrentProgress = nil
|
||||
end
|
||||
Wait(1000)
|
||||
end
|
||||
end
|
||||
if Options.FreezePlayer then FreezeEntityPosition(PlayerPedId(),Options.FreezePlayer) end
|
||||
SendNuiMessage(json.encode({
|
||||
type = "Progressbar",
|
||||
length = length or 3000,
|
||||
message = message or "ESX-Framework"
|
||||
}))
|
||||
Wait(length)
|
||||
if Options.FreezePlayer then FreezeEntityPosition(PlayerPedId(),not Options.FreezePlayer) end
|
||||
if Options.onFinish then Options.onFinish() end
|
||||
end
|
||||
|
||||
exports('Progressbar', Progressbar)
|
||||
|
||||
ESX.RegisterInput("cancelprog", "[ProgressBar] Cancel Progressbar", "keyboard", "BACK", function()
|
||||
if not CurrentProgress then return end
|
||||
if not CurrentProgress.onCancel then return end
|
||||
SendNuiMessage(json.encode({
|
||||
type = "Close"
|
||||
}))
|
||||
ClearPedTasks(ESX.PlayerData.ped)
|
||||
if CurrentProgress.FreezePlayer then FreezeEntityPosition(PlayerPedId(), false) end
|
||||
CurrentProgress.canceled = true
|
||||
CurrentProgress.length = 0
|
||||
CurrentProgress.onCancel()
|
||||
CurrentProgress = nil
|
||||
end)
|
||||
exports('Progressbar', Progressbar)
|
||||
@@ -1,6 +1,7 @@
|
||||
fx_version 'adamant'
|
||||
game 'gta5'
|
||||
author 'ESX-Framework'
|
||||
lua54 'yes'
|
||||
description 'ESX Progressbar'
|
||||
|
||||
client_scripts { 'Progress.lua' }
|
||||
|
||||
@@ -1,13 +1,46 @@
|
||||
const w = window
|
||||
const doc = document
|
||||
|
||||
const codes = {
|
||||
"~r~": "red",
|
||||
"~b~": "#378cbf",
|
||||
"~g~": "green",
|
||||
"~y~": "yellow",
|
||||
"~p~": "purple",
|
||||
"~c~": "grey",
|
||||
"~m~": "#212121",
|
||||
"~u~": "black",
|
||||
"~o~": "orange"
|
||||
}
|
||||
|
||||
$(function () {
|
||||
w.addEventListener('message', function(e) {
|
||||
$(".text").text(e.data.message)
|
||||
if (e.data.type === "Progressbar") {
|
||||
var message = e.data.message
|
||||
const replaceColors = (str, obj) => {
|
||||
let strToReplace = str
|
||||
|
||||
for (let id in obj) {
|
||||
strToReplace = strToReplace.replace(new RegExp(id, 'g'), obj[id])
|
||||
}
|
||||
|
||||
return strToReplace
|
||||
}
|
||||
for (color in codes) {
|
||||
if (message.includes(color)) {
|
||||
let objArr = {};
|
||||
objArr[color] = `<span style="color: ${codes[color]}">`;
|
||||
objArr["~s~"] = "</span>";
|
||||
|
||||
let newStr = replaceColors(message, objArr);
|
||||
|
||||
message = newStr;
|
||||
}
|
||||
}
|
||||
$(".text").text(message)
|
||||
doc.getElementById("notifyInfo").style.display = "block";
|
||||
const start = new Date();
|
||||
const maxTime = e.data.length
|
||||
const maxTime = e.data.length;
|
||||
const timeoutValue = Math.floor(maxTime/100);
|
||||
animUpdate();
|
||||
|
||||
@@ -21,13 +54,16 @@ $(function () {
|
||||
const prc = Math.round((timeoutDiff/maxTime)*100);
|
||||
if (prc <= 100) {
|
||||
updateProg(prc);
|
||||
setTimeout(animUpdate, timeoutValue);
|
||||
this.timeoutID = setTimeout(animUpdate, timeoutValue);
|
||||
} else {
|
||||
doc.getElementById('notifyInfo').style.display = "none";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
doc.getElementById("notifyInfo").style.display = "none"
|
||||
clearTimeout(this.timeoutID);
|
||||
timeoutValue = 0;
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
```
|
||||
|
||||
* Export
|
||||
|
||||
```lua
|
||||
exports["esx_progressbar"]:Progressbar("Unlocking Storage", 3000,{
|
||||
FreezePlayer = true,
|
||||
@@ -27,5 +28,39 @@
|
||||
onFinish = function()
|
||||
--Code here
|
||||
end})
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
* Cancel
|
||||
|
||||
```lua
|
||||
ESX.Progressbar("Unlocking Storage", 3000,{
|
||||
FreezePlayer = true,
|
||||
animation ={
|
||||
type = "anim",
|
||||
dict = "anim@mp_player_intmenu@key_fob@",
|
||||
lib ="fob_click"
|
||||
},
|
||||
onFinish = function()
|
||||
--Code here
|
||||
end, onCancel = function()
|
||||
--Code here
|
||||
end
|
||||
})
|
||||
```
|
||||
|
||||
* Scenario
|
||||
|
||||
```lua
|
||||
ESX.Progressbar("Unlocking Storage", 3000,{
|
||||
FreezePlayer = true,
|
||||
animation ={
|
||||
type = "Scenario",
|
||||
Scenario = "PROP_HUMAN_BUM_BIN",
|
||||
},
|
||||
onFinish = function()
|
||||
--Code here
|
||||
end, onCancel = function()
|
||||
--Code here
|
||||
end
|
||||
})
|
||||
```
|
||||
@@ -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
|
||||
|
||||
@@ -479,6 +479,7 @@ end)
|
||||
CreateThread(function()
|
||||
while true do
|
||||
local Sleep = 1500
|
||||
local Near = false
|
||||
local playerPed = PlayerPedId()
|
||||
|
||||
if IsPedInAnyVehicle(playerPed, false) then
|
||||
@@ -488,14 +489,14 @@ CreateThread(function()
|
||||
if (ESX.PlayerData.job and ESX.PlayerData.job.name == 'mechanic') or not Config.IsMechanicJobOnly then
|
||||
for k, v in pairs(Config.Zones) do
|
||||
local zonePos = vector3(v.Pos.x, v.Pos.y, v.Pos.z)
|
||||
if #(coords - zonePos) < v.Size.x then
|
||||
if #(coords - zonePos) < 10.0 then
|
||||
Near = true
|
||||
Sleep = 0
|
||||
if not lsMenuIsShowed then
|
||||
if not HintDisplayed then
|
||||
HintDisplayed = true
|
||||
ESX.TextUI(v.Hint)
|
||||
end
|
||||
|
||||
if IsControlJustReleased(0, 38) then
|
||||
lsMenuIsShowed = true
|
||||
|
||||
@@ -527,21 +528,10 @@ CreateThread(function()
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
if HintDisplayed then
|
||||
HintDisplayed = false
|
||||
ESX.HideUI()
|
||||
end
|
||||
end
|
||||
else
|
||||
if HintDisplayed then
|
||||
HintDisplayed = false
|
||||
ESX.HideUI()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if HintDisplayed then
|
||||
if not Near and HintDisplayed then
|
||||
HintDisplayed = false
|
||||
ESX.HideUI()
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ Locales['en'] = {
|
||||
['already_own'] = 'you already own: %s',
|
||||
['not_enough_money'] = 'you cannot afford this mod!',
|
||||
['purchased'] = 'you have purchased the mod!',
|
||||
['press_custom'] = 'press ~INPUT_PICKUP~ to personalize your vehicle.',
|
||||
['press_custom'] = 'press ~b~[E]~s~ to Personalise Your Vehicle',
|
||||
['level'] = 'level %s',
|
||||
['neon'] = 'neon',
|
||||
['blip_name'] = 'los Santos Customs',
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
<h1 align='center'>ESX Legacy</a></h1><p align='center'><b><a href='https://discord.esx-framework.org/'>Discord</a> - <a href='https://esx-framework.org/'>Website</a> - <a href='https://docs.esx-framework.org/legacy/installation'>Documentation</a></b></h5>
|
||||
<h1 align='center'>ESX Legacy</a></h1>
|
||||
<p align="center"><img src="https://docs.esx-framework.org/severcount.svg"/></p>
|
||||
<p align='center'><b><a href='https://discord.esx-framework.org/'>Discord</a> - <a href='https://esx-framework.org/'>Website</a> - <a href='https://docs.esx-framework.org/legacy/installation'>Documentation</a></b></h5>
|
||||
|
||||
**IMPORTANT**: ESX Legacy now supports ox Inventory. **HOWEVER, THIS SHOULD ONLY BE USED IF YOU ARE EXPERIENCED AND KNOW WHAT YOU ARE DOING**.
|
||||
|
||||
##### ESX is the leading framework for creating roleplay servers on FiveM, with many official and community resources designed to utilise the tools provided here. For a taste of what's available
|
||||
|
||||
> esx_identity: Enables character registration defining a players name, sex, height, and date of birth
|
||||
> esx_society: Allows job resources to register a society, gaining employee management, society funds, and more
|
||||
> esx_billing: Allows members of some societies to send fines or bills to other players
|
||||
> esx_vehicleshop: Allow players to purchase vehicles from a dealership, or setup society support for a player-managed dealership
|
||||
> esx_ambulancejob: Adds a death and respawn system while allowing players to work as EMS to heal and revive others
|
||||
|
||||
Many more resources are included in this repository, or you can browse the [ESX Community Github](https://github.com/esx-community/) or [Cfx.re Releases board](https://forum.cfx.re/tag/esx) for more.
|
||||
<p align='center'>Want More resources? You can browse the <a href="https://github.com/esx-community/">ESX Community Github</a> or <a href="https://forum.cfx.re/tag/esx">Cfx.re Releases board</a> for more!
|
||||
<p align='center'><b>ESX is the leading framework, trusted By thousands of commmunitys for the heighest quality roleplay servers on FiveM</b></p>
|
||||
|
||||
<hr>
|
||||
|
||||
### License
|
||||
|
||||
es_extended - ESX framework for FiveM
|
||||
ESX-legacy - ESX framework for FiveM
|
||||
|
||||
Copyright (C) 2015-2022 Jérémie N'gadi
|
||||
Copyright (C) 2015-2022 ESX-Framework
|
||||
|
||||
This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user