Took a while because I started rewriting it at work but had a lot of customers, so came home and finished it. Here you goā¦
Please note it is untested, but the changes, other than making it actually work with multiple jobs, includes;
- ESX and QBCore support
- Easier config by only changing config file and not client file
- Unlimited job support instead of only 3 or 4
- Optional notification system for ESX, QBCore or MythicNotify
- Smoother teleportation without ESX dependency
- Combined all elevators into a main config that loops, etc.
- Removed the need to manually number each floor (numbers were wrong anyway)
- Removed redundant need to have duplicate events with different names, for each elevator
- You no longer see your current floor in the list of floors to go to
Now when people want to add elevators, they add a table with the key being the elevator name and the value being a table with a list of floors and their data. The comments have been adjusted to make it easier too. Hope you donāt mind that I took the liberty of improving it. Feel free to update your GitHub with this, once you test it and confirm it works. Any issues, let me know.
config.lua:
Config = {}
Config.UseESX = true -- Use ESX Framework
Config.UseQBCore = false -- Use QBCore Framework (Ignored if Config.UseESX = true)
Config.UseMythicNotify = true -- Use mythic_notify (Requires mythic_notify script)
--[[
USAGE
Dependencies (can be swapped out):
ESX or QBCore
qtarget
nh-context
nh-keyboard
To add an elevator, copy the table below and configure as needed:
coords = Enter vector3 coords of center of elevator
heading = Direction facing out of the elevator
level = What floor are they going to
label = What is on that floor
jobs = Table of job keys that are allowed to access that floor and value of minimum grade of each job
]]
--[[
ExampleElevator = {
{
coords = vector3(xxx, yyy, zzz), heading = 0.0, level = "Floor 2", label = "Roof",
jobs = {
["police"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(xxx, yyy, zzz), heading = 0.0, level = "Floor 1", label = "Ground",
jobs = {
["police"] = 0,
["ambulance"] = 0,
}
},
},
]]
Config.Elevators = {
VPDMainElevator = {
{
coords = vector3(-1096.22, -850.763, 38.20), heading = 36.8, level = "Floor 6", label = "Roof Access",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 34.40), heading = 36.8, level = "Floor 5", label = "Detective Bureau",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 30.80), heading = 36.8, level = "Floor 4", label = "Operations Center",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 27.00), heading = 36.8, level = "Floor 3", label = "Division Offices & Briefing Room",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 23.00), heading = 36.8, level = "Floor 2", label = "Cafe",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 19.00), heading = 36.8, level = "Floor 1", label = "Main Hall",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 4.80), heading = 36.8, level = "Floor -1", label = "Detention Cells & Interrogation",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 10.20), heading = 36.8, level = "Floor -2", label = "Crime Lab & Evidence Rooms",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1096.22, -850.763, 13.70), heading = 36.8, level = "Floor -3", label = "Garage & Armory",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
},
VPDPublicElevator = {
{
coords = vector3(-1066.05, -833.71, 26.82318), heading = 36.1, level = "Floor 3", label = "Division Offices",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1066.05, -833.71, 23.03471), heading = 36.1, level = "Floor 2", label = "UNDER RENOVATIONS",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1066.05, -833.713, 18.9964), heading = 36.1, level = "Floor 1", label = "Main Hall",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1066.05, -833.71, 4.88), heading = 36.1, level = "Floor -1", label = "Detention Cells & Interrogation",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
["hclaw"] = 0,
}
},
{
coords = vector3(-1066.05, -833.71, 10.27282), heading = 36.1, level = "Floor -2", label = "Crime Lab & Evidence Rooms",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(-1066.05, -833.71, 13.69069), heading = 36.1, level = "Floor -3", label = "Garage & Armory",
jobs = {
["police"] = 0,
["sheriff"] = 0,
["ambulance"] = 0,
}
},
},
SkybarElevatorSouth = {
{
coords = vector3(315.49, -929.32, 52.81), heading = 176.67, level = "Skybar 5th Floor", label = "Bar Level for Skybar",
jobs = {}
},
{
coords = vector3(315.49, -929.32, 29.47), heading = 176.67, level = "Skybar Ground", label = "Street Level for Skybar",
jobs = {}
},
},
SkybarElevatorNorth = {
{
coords = vector3(309.81, -929.05, 52.81), heading = 176.67, level = "Skybar 5th Floor", label = "Bar Level for Skybar",
jobs = {}
},
{
coords = vector3(309.81, -929.05, 29.47), heading = 176.67, level = "Skybar Ground", label = "Street Level for Skybar",
jobs = {}
},
},
}
client.lua:
ESX = nil
QBCore = nil
PlayerJob = nil
PlayerGrade = nil
if Config.UseESX then
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent("esx:getSharedObject", function(obj) ESX = obj end)
Wait(0)
end
while not ESX.IsPlayerLoaded() do
Wait(100)
end
local playerData = ESX.GetPlayerData()
PlayerJob = playerData.job.name
PlayerGrade = playerData.job.grade
end)
RegisterNetEvent("esx:setJob", function(job)
PlayerJob = job.name
PlayerGrade = job.grade
end)
elseif Config.UseQBCore then
QBCore = exports["qb-core"]:GetCoreObject()
local playerData = QBCore.Functions.GetPlayerData()
PlayerJob = playerData.job.name
PlayerGrade = playerData.job.grade.level
RegisterNetEvent("QBCore:Client:OnJobUpdate", function(job)
PlayerJob = job.name
PlayerGrade = job.grade.level
end)
end
CreateThread(function()
for elevatorName, elevatorFloors in pairs(Config.Elevators) do
for index, floor in pairs(elevatorFloors) do
exports["qtarget"]:AddBoxZone(elevatorName .. index, floor.coords, 5, 4, {
name = elevatorName,
heading = floor.heading,
debugPoly = false,
minZ = floor.coords.z - 1.5,
maxZ = floor.coords.z + 1.5
},
{
options = {
{
event = "angelicxs_elevator:showFloors",
icon = "fas fa-hand-point-up",
label = "Use Elevator From " .. floor.level,
elevator = elevatorName,
level = index
},
},
distance = 1.5
})
end
end
end)
RegisterNetEvent("angelicxs_elevator:showFloors", function(data)
local elevator = {}
for index, floor in pairs(Config.Elevators[data.elevator]) do
table.insert(elevator, {
header = floor.level,
context = floor.label,
disabled = (index == data.level or not hasRequiredJob(floor.jobs)),
event = "angelicxs_elevator:movement",
args = { floor }
})
end
TriggerEvent("nh-context:createMenu", elevator)
end)
RegisterNetEvent("angelicxs_elevator:movement", function(floor)
if hasRequiredJob(floor.jobs) then
local ped = PlayerPedId()
DoScreenFadeOut(1500)
while not IsScreenFadedOut() do
Wait(10)
end
RequestCollisionAtCoord(floor.coords.x, floor.coords.y, floor.coords.z)
while not HasCollisionLoadedAroundEntity(ped) do
Citizen.Wait(0)
end
SetEntityCoords(ped, floor.coords.x, floor.coords.y, floor.coords.z, false, false, false, false)
SetEntityHeading(ped, floor.heading and floor.heading or 0.0)
Wait(3000)
DoScreenFadeIn(1500)
else
TriggerEvent("angelicxs_elevator:notify", "You don't have clearance for this floor!", "error")
end
end)
RegisterNetEvent("angelicxs_elevator:notify", function(message, type)
if Config.UseMythicNotify then
exports.mythic_notify:SendAlert(type, message, 4000)
elseif Config.UseESX then
ESX.ShowNotification(message)
elseif Config.UseQBCore then
QBCore.Functions.Notify(message, type)
end
end)
function hasRequiredJob(jobs)
if next(jobs) then
for jobName, gradeLevel in pairs(jobs) do
if PlayerJob == jobName and PlayerGrade >= gradeLevel then
return true
end
end
return false
end
return true
end
Adding new elevators:
Inside Config.Elevators, add the following structure (as provided in the config file comments)ā¦
ExampleElevator = {
{
coords = vector3(xxx, yyy, zzz), heading = 0.0, level = "Floor 2", label = "Roof",
jobs = {
["police"] = 0,
["ambulance"] = 0,
}
},
{
coords = vector3(xxx, yyy, zzz), heading = 0.0, level = "Floor 1", label = "Ground",
jobs = {}
},
},
Thatās all. Now you have a new elevator. No messing with events for the context menu or teleportation. Enjoy!