2026-04-14 17:41:39 +02:00

1520 lines
71 KiB
Lua

--[[
ESX Property - Properties Made Right!
Copyright (C) 2025 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]] local GameBuild = GetGameBuildNumber()
Properties = {}
CurrentId = 0
local CurrentDrawing = {}
InProperty = false
PlayerKeys = {}
InCCTV = false
local Blips = {}
local Shell = nil
local PM = Config.PlayerManagement
local CreateThread = CreateThread
local Wait = Wait
local ShowingUIs = {Exit = false, Wardrobe = false, Storage = false, ExitShell = false}
local ox_inventory = exports.ox_inventory
local DoScreenFadeIn = DoScreenFadeIn
local PlayerPedId = PlayerPedId
local GetEntityCoords = GetEntityCoords
local GetEntityHeading = GetEntityHeading
local IsControlJustPressed = IsControlJustPressed
local IsControlPressed = IsControlPressed
local DoScreenFadeOut = DoScreenFadeOut
function RefreshBlips()
for i = 1, #Blips, 1 do
RemoveBlip(Blips[i])
Blips[i] = nil
end
for k, v in pairs(Properties) do
if v.Owned and Config.OwnedBlips then
if v.Owner == ESX.PlayerData.identifier then
local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
SetBlipSprite(Blip, 40)
SetBlipAsShortRange(Blip, true)
SetBlipScale(Blip, 0.8)
SetBlipColour(Blip, 0)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(v.Name)
EndTextCommandSetBlipName(Blip)
SetBlipCategory(Blip, 11)
Blips[#Blips + 1] = Blip
elseif PlayerKeys[k] then
local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
SetBlipSprite(Blip, GameBuild >= 2699 and 811 or 134)
SetBlipAsShortRange(Blip, true)
SetBlipScale(Blip, 0.9)
SetBlipColour(Blip, 26)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(v.Name)
EndTextCommandSetBlipName(Blip)
SetBlipCategory(Blip, 11)
Blips[#Blips + 1] = Blip
end
elseif not v.Owned and Config.ForSaleBlips then
local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
SetBlipSprite(Blip, 350)
SetBlipAsShortRange(Blip, true)
SetBlipScale(Blip, 0.7)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(v.Name)
EndTextCommandSetBlipName(Blip)
SetBlipCategory(Blip, 10)
Blips[#Blips + 1] = Blip
end
end
if PM.Enabled then
local Blip = AddBlipForCoord(PM.Locations.Entrance)
SetBlipSprite(Blip, 374)
SetBlipColour(Blip, 45)
SetBlipAsShortRange(Blip, true)
SetBlipScale(Blip, 0.7)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString(TranslateCap("office_blip",PM.joblabel))
EndTextCommandSetBlipName(Blip)
Blips[#Blips + 1] = Blip
end
end
RegisterNetEvent("esx_property:syncProperties", function(properties, lastProperty)
while not ESX.PlayerLoaded and not ESX.PlayerData.identifier do
Wait(0)
end
Properties = properties
for house, data in pairs(Properties) do
if data.Keys then
for ident, vaues in pairs(data.Keys) do
if vaues and ident == ESX.PlayerData.identifier then
PlayerKeys[house] = true
end
end
end
end
if lastProperty then
if Properties[lastProperty.id] and (Properties[lastProperty.id].Owner == ESX.PlayerData.identifier or PlayerKeys[lastProperty.id]) then
AttemptHouseEntry(lastProperty.id)
else
ESX.TriggerServerCallback('esx_property:RemoveLastProperty', function()
SetEntityCoords(ESX.PlayerData.ped, vector3(lastProperty.coords.x, lastProperty.coords.y, lastProperty.coords.z))
end)
end
end
RefreshBlips()
end)
RegisterNetEvent("esx_property:giveKeyAccess", function(Property)
ESX.TriggerServerCallback("esx_property:ShouldHaveKey", function(Should)
if Should then
PlayerKeys[Property] = true
end
end, Property)
end)
RegisterNetEvent("esx_property:RemoveKey", function(Property)
PlayerKeys[Property] = false
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
RefreshBlips()
end)
exports("GetProperties", function()
return Properties
end)
function OpenInteractionMenu(PropertyId, Interaction)
local Property = Properties[PropertyId]
if Property.Owned then
if Interaction == "Wardrobe" then
Config.WardrobeInteraction(PropertyId, Interaction)
elseif Interaction == "Storage" then
if Config.OxInventory then
exports.ox_inventory:openInventory('stash', {id = 'property-' .. PropertyId, owner = Property.Owner})
end
end
end
end
function GiveKeysMenu(Property)
ESX.TriggerServerCallback("esx_property:GetInsidePlayers", function(Players)
local Elements = {{unselectable = true, title = TranslateCap("nearby"), icon = "fas fa-user-plus"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"}}
for i = 1, #Players, 1 do
Elements[#Elements + 1] = {title = Players[i].Name, icon = "far fa-user", index = Players[i].Id, value = "user"}
end
ESX.OpenContext("right", Elements, function(menu, element)
if element.value == "go_back" then
ManageKeys(Property)
elseif element.value == "user" then
ESX.TriggerServerCallback("esx_property:GiveKey", function(KeyGiven)
if KeyGiven then
ESX.ShowNotification(TranslateCap("gave_key",element.title), "success")
ESX.CloseContext()
else
ESX.ShowNotification(TranslateCap("key_cannot_give"), "error")
end
end, Property, element.index)
end
end)
end, Property)
end
function RemoveKeysMenu(Property)
ESX.TriggerServerCallback("esx_property:GetPlayersWithKeys", function(Players)
local Elements = {{unselectable = true, title = TranslateCap("remove_title"), icon = "fas fa-user-plus"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"}}
for k, v in pairs(Players) do
local name = v.name
local Id = k
Elements[#Elements + 1] = {title = name, icon = "far fa-user", value = "user", id = Id}
end
ESX.OpenContext("right", Elements, function(menu, element)
if element.value == "go_back" then
ManageKeys(Property)
elseif element.value == "user" then
ESX.TriggerServerCallback("esx_property:RemoveKey", function(KeyGiven)
if KeyGiven then
ESX.ShowNotification(TranslateCap("key_revoke_success", element.title), "success")
ESX.CloseContext()
else
ESX.ShowNotification(TranslateCap("key_revoke_error"), "error")
end
end, Property, element.id)
end
end)
end, Property)
end
function ManageKeys(Property)
ESX.HideUI()
local Elements = {{unselectable = true, title = TranslateCap("key_management"), icon = "fas fa-key"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"},
{title = TranslateCap("give_keys"), icon = "fas fa-plus", value = "give_keys"},
{title = TranslateCap("remove_keys"), icon = "fas fa-minus", value = "remove_keys"}}
ESX.OpenContext("right", Elements, function(menu, element)
if element.value == "go_back" then
OpenPropertyMenu(Property)
end
if element.value == "give_keys" then
GiveKeysMenu(Property)
end
if element.value == "remove_keys" then
RemoveKeysMenu(Property)
end
end)
end
function SetPropertyName(Property)
local Name = Properties[Property].setName ~= "" and Properties[Property].setName or Properties[Property].Name
local Elements = {{unselectable = true, title = TranslateCap("name_edit"), icon = "fa-solid fa-signature"},
{icon = "", title = TranslateCap("name"), input = true, inputType = "text", inputValue = Name, inputPlaceholder = Properties[Property].Name,
name = "setName"}, {icon = "fa-solid fa-check", title = TranslateCap("confirm"), name = "confirm"}}
ESX.OpenContext("right", Elements, function(menu, element)
if element.name == "confirm" then
ESX.TriggerServerCallback("esx_property:SetPropertyName", function(Set)
if Set then
ESX.ShowNotification(TranslateCap("name_edit_success",menu.eles[2].inputValue), "success")
ESX.CloseContext()
else
ESX.ShowNotification(TranslateCap("name_edit_error",menu.eles[2].inputValue), "error")
end
end, Property, menu.eles[2].inputValue)
end
end)
end
local SettingValue = ""
function PropertyMenuElements(PropertyId)
local Property = Properties[PropertyId]
local elements = {{unselectable = true, title = Property.setName ~= "" and Property.setName or Property.Name, icon = "fas fa-home"}}
if Property.Owned then
if Property.Locked then
table.insert(elements, {title = TranslateCap("door_locked"), icon = "fas fa-lock", value = 'property_unlock'})
else
table.insert(elements, {title = TranslateCap("door_unlocked"), icon = "fas fa-unlock", value = 'property_lock'})
end
if ESX.PlayerData.identifier == Property.Owner then
table.insert(elements,
{title = TranslateCap("name_manage"), description = TranslateCap("name_manage_desc"), icon = "fa-solid fa-signature", value = 'property_name'})
end
if not InProperty then
if ESX.PlayerData.identifier == Property.Owner then
table.insert(elements, {title = TranslateCap("key_management"), description = TranslateCap("key_management_desc"), icon = "fas fa-key", value = 'property_keys'})
table.insert(elements,
{title = TranslateCap("sell_title"), description = TranslateCap("sell_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price * 0.6))),
icon = "fas fa-dollar-sign", value = 'property_sell'})
end
if Config.Raiding.Enabled and Property.Locked and ESX.PlayerData.job and ESX.GetPlayerData().job.name == "police" then
table.insert(elements, {title = TranslateCap("raid_title"), description = TranslateCap("raid_desc"), icon = "fas fa-bomb", value = 'property_raid'})
end
else
if (Config.CCTV.Enabled and Properties[PropertyId].cctv.enabled) and (ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
table.insert(elements, {title = TranslateCap("cctv_title"), description = TranslateCap("cctv_desc"), icon = "fas fa-video", value = 'property_cctv'})
end
if (ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
if Config.CanCustomiseInventoryAndWardrobePositions then
if Config.OxInventory then
table.insert(elements, {title = TranslateCap("inventory_title"), description = TranslateCap("inventory_desc"),
icon = "fa-solid fa-up-down-left-right", value = 'property_inventory'})
end
table.insert(elements, {title = TranslateCap("wardrobe_title"), description = TranslateCap("wardrobe_desc"), icon = "fa-solid fa-up-down-left-right",
value = 'property_wardrobe'})
end
table.insert(elements,
{title = TranslateCap("furniture_title"), description = TranslateCap("furniture_desc"), icon = "fas fa-boxes-stacked", value = 'property_furniture'})
end
end
if (not Property.Locked or Config.OwnerCanAlwaysEnter and ESX.PlayerData.identifier == Property.Owner) and not InProperty then
table.insert(elements, {title = TranslateCap("enter_title"), icon = "fas fa-door-open", value = 'property_enter'})
end
if Property.Locked and not InProperty and
not (Config.OwnerCanAlwaysEnter and ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
table.insert(elements, {title = TranslateCap("knock_title"), icon = "fa-solid fa-hand-sparkles", value = 'property_knock'})
end
else
if not PM.Enabled then
table.insert(elements,
{title = TranslateCap("buy_title"), description = TranslateCap("buy_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price))), icon = "fas fa-shopping-cart",
value = 'property_buy'})
else
if ESX.PlayerData.job.name == PM.job and ESX.PlayerData.job.grade >= PM.Permissions.SellProperty then
table.insert(elements, {title = TranslateCap("sellplayer_title"), description = TranslateCap("sellplayer_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price))),
icon = "fas fa-shopping-cart", value = 'property_sell_re'})
end
end
if not Property.Locked and not InProperty then
table.insert(elements, {title = TranslateCap("view_title"), icon = "fas fa-door-open", value = 'property_enter'})
end
end
if InProperty and (not Property.Locked or Config.CanAlwaysExit) then
table.insert(elements, {title = TranslateCap("exit_title"), icon = "fas fa-sign-out-alt", value = 'property_exit'})
end
return elements
end
function OpenPropertyMenu(PropertyId)
if SettingValue ~= "" then
ESX.ShowNotification(TranslateCap("property_editing_error"))
return
end
ESX.HideUI()
local Property = Properties[PropertyId]
local elements = PropertyMenuElements(PropertyId)
ESX.OpenContext("right", elements, function(menu, element)
if element.value == "property_unlock" then
ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
if IsUnlocked then
local eles = PropertyMenuElements(PropertyId)
exports["esx_context"]:Refresh(eles)
else
ESX.ShowNotification(TranslateCap("unlock_error"), "error")
end
end, PropertyId)
end
if element.value == "property_lock" then
ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
if IsUnlocked then
local eles = PropertyMenuElements(PropertyId)
exports["esx_context"]:Refresh(eles)
else
ESX.ShowNotification(TranslateCap("lock_error"), "error")
end
end, PropertyId)
end
if element.value == "property_cctv" then
CCTV(PropertyId)
end
if element.value == "property_raid" then
ESX.TriggerServerCallback("esx_property:CanRaid", function(CanRaid)
if CanRaid then
ESX.Progressbar(TranslateCap("prep_raid"), 15000, {FreezePlayer = true, animation = Config.Raiding.Animation, onFinish = function()
ESX.ShowNotification(TranslateCap("raiding"), "success")
AttemptHouseEntry(PropertyId)
end, onCancel = function()
ESX.ShowNotification(TranslateCap("cancel_raiding"), "error")
end})
else
ESX.ShowNotification(TranslateCap("cannot_raid"), "error")
end
end, PropertyId)
end
if element.value == "property_enter" then
ESX.CloseContext()
AttemptHouseEntry(PropertyId)
end
if element.value == "property_keys" then
ESX.CloseContext()
ManageKeys(PropertyId)
end
if element.value == "property_name" then
ESX.CloseContext()
SetPropertyName(PropertyId)
end
if element.value == "property_furniture" then
ESX.CloseContext()
FurnitureMenu(PropertyId)
end
if element.value == "property_inventory" then
ESX.CloseContext()
ShowingUIs.Exit = false
SettingValue = "Storage"
Wait(20)
ESX.TextUI(TranslateCap("storage_pos_textui"))
while SettingValue ~= "" do
Wait(1)
if IsControlJustPressed(0, 47) then
SettingValue = ""
ESX.HideUI()
ESX.TriggerServerCallback("esx_property:SetInventoryPosition", function(Success)
if Success then
ESX.ShowNotification(TranslateCap("storage_pos_success"), "success")
else
ESX.ShowNotification(TranslateCap("storage_pos_error"), "error")
end
end, PropertyId, GetEntityCoords(ESX.PlayerData.ped))
break
end
end
end
if element.value == "property_wardrobe" then
ESX.CloseContext()
ShowingUIs.Exit = false
SettingValue = "Wardrobe"
Wait(20)
ESX.TextUI(TranslateCap("wardrobe_pos_textui"))
while SettingValue ~= "" do
Wait(1)
if IsControlJustPressed(0, 47) then
SettingValue = ""
ESX.HideUI()
ESX.TriggerServerCallback("esx_property:SetWardrobePosition", function(Success)
if Success then
ESX.ShowNotification(TranslateCap("wardrobe_pos_success"), "success")
else
ESX.ShowNotification(TranslateCap("wardrobe_pos_error"), "error")
end
end, PropertyId, GetEntityCoords(ESX.PlayerData.ped))
break
end
end
end
if element.value == "property_exit" then
ESX.CloseContext()
if SettingValue == "" then
AttemptHouseExit(PropertyId)
else
ESX.ShowNotification(TranslateCap("please_finish", SettingValue))
end
end
if element.value == "property_buy" then
ESX.TriggerServerCallback("esx_property:buyProperty", function(IsBought)
if IsBought then
local eles = PropertyMenuElements(PropertyId)
exports["esx_context"]:Refresh(eles)
else
ESX.ShowNotification(TranslateCap("cannot_afford"), "error")
end
end, PropertyId)
end
if element.value == "property_sell_re" then
local Elements = {{unselectable = true, title = TranslateCap("select_player")}}
ESX.TriggerServerCallback("esx_property:GetNearbyPlayers", function(Players)
if Players then
for i = 1, #Players do
Elements[#Elements + 1] = {title = Players[i].name, value = Players[i].source}
end
ESX.OpenContext("right", Elements, function(menu, element)
if element.value then
ESX.TriggerServerCallback("esx_property:attemptSellToPlayer", function(IsBought)
if IsBought then
local eles = PropertyMenuElements(PropertyId)
exports["esx_context"]:Refresh(eles)
else
ESX.ShowNotification(TranslateCap("cannot_sell"), "error")
end
end, PropertyId, element.value)
end
end)
end
end, PropertyId)
end
if element.value == "property_knock" then
ESX.ShowNotification(TranslateCap("knock_on_door"), "success")
ESX.TriggerServerCallback("esx_property:KnockOnDoor", function(HasKnocked)
if not HasKnocked then
ESX.ShowNotification(TranslateCap("nobody_home"), "error")
end
end, PropertyId)
end
if element.value == "property_sell" then
ESX.TriggerServerCallback("esx_property:sellProperty", function(IsSold)
if IsSold then
local eles = PropertyMenuElements(PropertyId)
exports["esx_context"]:Refresh(eles)
else
ESX.ShowNotification(TranslateCap("cannot_sell"), "error")
end
end, PropertyId)
end
end, function(menu)
CurrentDrawing.Showing = false
end)
end
function AttemptHouseExit(PropertyId)
local Property = Properties[PropertyId]
ESX.ShowNotification(TranslateCap("exiting"), "success")
FreezeEntityPosition(ESX.PlayerData.ped, true)
InProperty = false
CurrentId = 0
SettingValue = ""
ESX.HideUI()
ESX.UI.Menu.CloseAll()
SetRainLevel(-1)
DoScreenFadeOut(1500)
Wait(1500)
TriggerServerEvent("esx_property:leave", PropertyId)
if Shell then
DeleteObject(Shell)
Shell = nil
end
if Config.Furniture.Enabled then
for k, v in pairs(SpawnedFurniture) do
DeleteObject(v.obj)
end
SpawnedFurniture = {}
end
Wait(1500)
FreezeEntityPosition(ESX.PlayerData.ped, false)
DoScreenFadeIn(1500)
end
RegisterCommand("getoffset", function(source)
if InProperty then
local PlayerPed = ESX.PlayerData.ped
local Pcoords = GetEntityCoords(PlayerPed)
local Property = Properties[CurrentId]
local Interior = GetInteriorValues(Property.Interior)
print(vector3(Property.Entrance.x, Property.Entrance.y, 2000) - Pcoords)
SendNUIMessage({
link = tostring(vector3(Property.Entrance.x, Property.Entrance.y, 2000) - Pcoords)
})
end
end)
function AttemptHouseEntry(PropertyId)
local Property = Properties[PropertyId]
local Interior = GetInteriorValues(Property.Interior)
if Interior.type == "shell" and not Config.Shells then
ESX.ShowNotification(TranslateCap("shell_disabled"), "error")
return
end
ESX.ShowNotification(TranslateCap("entering"), "success")
CurrentId = PropertyId
ESX.UI.Menu.CloseAll()
local Property = Properties[CurrentId]
FreezeEntityPosition(ESX.PlayerData.ped, true)
DoScreenFadeOut(1500)
Wait(1500)
if Interior.type == "shell" then
ESX.Streaming.RequestModel(joaat(Property.Interior), function()
if Shell then
DeleteObject(Shell)
Shell = nil
end
local Pos = vector3(Property.Entrance.x, Property.Entrance.y, 2000)
Shell = CreateObjectNoOffset(joaat(Property.Interior), Pos + Interior.pos, false, false, false)
SetEntityHeading(Shell, 0.0)
while not DoesEntityExist(Shell) do
Wait(1)
end
FreezeEntityPosition(Shell, true)
end)
end
if Properties[PropertyId].furniture then
for k, v in pairs(Properties[PropertyId].furniture) do
ESX.Game.SpawnLocalObject(v.Name, v.Pos, function(object)
SetEntityCoordsNoOffset(object, v.Pos.x, v.Pos.y, v.Pos.z)
SetEntityHeading(object, v.Heading)
SetEntityAsMissionEntity(object, true, true)
FreezeEntityPosition(object, true)
SpawnedFurniture[k] = {obj = object, data = v}
end)
end
end
local ShowingTextUI2 = false
FreezeEntityPosition(ESX.PlayerData.ped, false)
TriggerServerEvent("esx_property:enter", PropertyId)
Wait(1500)
DoScreenFadeIn(1800)
InProperty = true
if not Config.OxInventory then
Interior.positions.Storage = nil
Properties[CurrentId].positions.Storage = nil
end
CreateThread(function()
while InProperty do
local Property = Properties[CurrentId]
local Sleep = 1000
local Near = false
SetRainLevel(0.0)
local PlayerPed = ESX.PlayerData.ped
local PlayerCoords = GetEntityCoords(PlayerPed)
if Interior.type == "shell" then
if #(PlayerCoords - vector3(Property.Entrance.x, Property.Entrance.y, 1999)) < 5.0 then
Sleep = 0
DrawMarker(27, vector3(Property.Entrance.x, Property.Entrance.y, 2000.2), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 50, 200, 200,
false, false, 2, true, nil, nil, false)
if #(PlayerCoords.xy - vector2(Property.Entrance.x, Property.Entrance.y)) <= 2.5 then
Near = true
if not ShowingUIs.Exit then
local Pname = Properties[CurrentId].setName ~= "" and Properties[CurrentId].setName or Properties[CurrentId].Name
ESX.TextUI(TranslateCap("access_textui", Pname))
ShowingUIs.Exit = true
end
if IsControlJustPressed(0, 38) then
OpenPropertyMenu(CurrentId)
end
else
if not Near and ShowingUIs.Exit and SettingValue == "" then
ShowingUIs.Exit = false
ESX.HideUI()
ESX.CloseContext()
end
end
end
if Property.Owned then
for k, v in pairs(Properties[CurrentId].positions) do
local v = vector3(v.x, v.y, v.z)
local CanDo = true
if CanDo then
local Poss = vector3(Property.Entrance.x, Property.Entrance.y, 1999) - v
if #(PlayerCoords - Poss) < 5.0 then
Sleep = 0
DrawMarker(27, Poss, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 200, 50, 50, 200, false, false, 2, true, nil, nil, false)
if #(PlayerCoords - Poss) < 2.0 and SettingValue == "" then
Near = true
if not ShowingUIs[k] then
ShowingUIs[k] = true
ESX.TextUI(TranslateCap("access_textui", k))
end
if IsControlJustPressed(0, 38) then
OpenInteractionMenu(CurrentId, k)
end
else
if not Near and ShowingUIs[k] and SettingValue == "" then
ShowingUIs[k] = false
ESX.HideUI()
end
end
end
end
end
if not Near and ShowingUIs and SettingValue == "" then
ShowingTextUI2 = false
ESX.HideUI()
end
end
else
if #(PlayerCoords - Interior.pos) < 5.0 then
Sleep = 0
DrawMarker(27, vector3(Interior.pos.xy, Interior.pos.z - 0.98), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 50, 200, 200, false, false,
2, true, nil, nil, false)
if #(PlayerCoords - Interior.pos) < 2.0 then
if not ShowingUIs.Exit then
ShowingUIs.Exit = true
local Pname = Properties[CurrentId].setName ~= "" and Properties[CurrentId].setName or Properties[CurrentId].Name
ESX.TextUI(TranslateCap("access_textui", Pname))
end
if IsControlJustPressed(0, 38) then
OpenPropertyMenu(CurrentId)
end
else
if ShowingUIs.Exit and SettingValue == "" then
ShowingUIs.Exit = false
ESX.HideUI()
ESX.CloseContext()
end
end
end
if Property.Owned then
for k, v in pairs(Properties[CurrentId].positions) do
v = vector3(v.x, v.y, v.z)
local CanDo = true
if CanDo then
if #(PlayerCoords - v) < 5.0 then
Sleep = 0
DrawMarker(27, vector3(v.xy, v.z - 0.98), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 200, 50, 50, 200, false, false, 2, true, nil,
nil, false)
if #(PlayerCoords - v) < 2.0 then
if not ShowingUIs[k] then
ShowingUIs[k] = true
ESX.TextUI(TranslateCap("access_textui", k))
end
if IsControlJustPressed(0, 38) then
OpenInteractionMenu(CurrentId, k)
end
else
if ShowingUIs[k] and SettingValue == "" then
ShowingUIs[k] = false
ESX.HideUI()
end
end
end
end
end
end
end
Wait(Sleep)
end
end)
end
function StoreVehicle(PropertyId)
local Vehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false)
if Vehicle then
local VehProperties = ESX.Game.GetVehicleProperties(Vehicle)
VehProperties.DisplayName = GetLabelText(GetDisplayNameFromVehicleModel(VehProperties.model))
ESX.TriggerServerCallback("esx_property:StoreVehicle", function(result)
if result then
SetEntityAsMissionEntity(Vehicle, true, true)
DeleteVehicle(Vehicle)
ESX.ShowNotification(TranslateCap("store_success"), "success")
return
else
ESX.ShowNotification(TranslateCap("store_error"), "error")
return
end
end, PropertyId, VehProperties)
end
end
function AccessGarage(PropertyId)
ESX.TriggerServerCallback("esx_property:AccessGarage", function(Vehicles)
if Vehicles then
local elements = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("property_garage")}}
for k, v in pairs(Vehicles) do
elements[#elements + 1] = {title = v.vehicle.DisplayName .. " | " .. v.vehicle.plate, Properties = v.vehicle, index = k}
end
ESX.OpenContext("right", elements, function(menu, element)
if element.Properties then
ESX.CloseContext()
ESX.ShowNotification(TranslateCap("retriving_notify",element.Properties.DisplayName))
if ESX.Game.IsSpawnPointClear(vector3(Properties[PropertyId].garage.pos.x, Properties[PropertyId].garage.pos.y,
Properties[PropertyId].garage.pos.z), 3.0) then
ESX.Game.SpawnVehicle(element.Properties.model, Properties[PropertyId].garage.pos, Properties[PropertyId].garage.Heading,
function(vehicle)
SetEntityAsMissionEntity(vehicle, true, true)
ESX.Game.SetVehicleProperties(vehicle, element.Properties)
TaskWarpPedIntoVehicle(ESX.PlayerData.ped, vehicle, -1)
SetModelAsNoLongerNeeded(element.Properties.model)
TriggerServerEvent("esx_property:SetVehicleOut", PropertyId, element.index)
end)
end
end
end)
else
ESX.ShowNotification(TranslateCap("cannot_access"), "error")
return
end
end, PropertyId)
end
CreateThread(function()
local ShowingTextUI = false
while true do
local Sleep = 2000
if #(Properties) > 0 then
Sleep = 800
local nearby = false
for i = 1, #(Properties) do
if Properties[i].Entrance then
local GetEntityCoords = GetEntityCoords
local IsControlJustPressed = IsControlJustPressed
local DrawMarker = DrawMarker
local Coords = GetEntityCoords(ESX.PlayerData.ped)
local Entrance = vector3(Properties[i].Entrance.x, Properties[i].Entrance.y, Properties[i].Entrance.z)
if not InCCTV then
if #(Coords - Entrance) < 10.0 then
Sleep = 0
DrawMarker(27, Entrance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
if #(Coords - Entrance) < 1.5 then
nearby = true
local PropertyName = Properties[i].setName ~= "" and Properties[i].setName or Properties[i].Name
if not CurrentDrawing.Showing or CurrentDrawing.Name ~= PropertyName then
CurrentDrawing.Name = PropertyName
CurrentDrawing.Showing = true
ESX.TextUI(TranslateCap("access_textui", PropertyName))
end
if IsControlJustPressed(0, 38) then
OpenPropertyMenu(i)
end
end
end
end
if Properties[i].garage.enabled and Properties[i].garage.pos and (ESX.PlayerData.identifier == Properties[i].Owner or PlayerKeys[i]) then
local Garage = vector3(Properties[i].garage.pos.x, Properties[i].garage.pos.y, Properties[i].garage.pos.z)
if #(Coords - Garage) < 10.0 then
Sleep = 0
DrawMarker(36, Garage, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 1.5, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
if #(Coords - Garage) < 3.0 then
nearby = true
if GetVehiclePedIsUsing(ESX.PlayerData.ped) ~= 0 then
local veh = GetVehiclePedIsIn(ESX.PlayerData.ped, false)
local vehmodel = GetEntityModel(veh)
local DisplayName = GetLabelText(GetDisplayNameFromVehicleModel(vehmodel))
if not CurrentDrawing.Showing or CurrentDrawing.Name ~= DisplayName then
CurrentDrawing.Name = DisplayName
CurrentDrawing.Showing = true
ESX.TextUI(TranslateCap("store_textui", DisplayName))
end
else
if not CurrentDrawing.Showing or CurrentDrawing.Name ~= "Garage" then
CurrentDrawing.Name = "Garage"
CurrentDrawing.Showing = true
ESX.TextUI(TranslateCap("access_textui", "garage"))
end
end
if IsControlJustPressed(0, 38) then
if GetVehiclePedIsUsing(ESX.PlayerData.ped) ~= 0 then
StoreVehicle(i)
else
AccessGarage(i)
end
end
end
end
end
end
end
if not nearby and CurrentDrawing.Showing and SettingValue == "" then
ESX.HideUI()
CurrentDrawing.Showing = false
ESX.CloseContext()
end
end
Wait(Sleep)
end
end)
function OpenPMQuickMenu(Action)
if Action == "Entrance" then
DoScreenFadeOut(1500)
Wait(1500)
ESX.TriggerServerCallback("esx_property:PMenterOffice", function(HasEntered)
if HasEntered then
ESX.ShowNotification(TranslateCap("enter_office"), "success")
else
ESX.ShowNotification(TranslateCap("enter_office_error"), "error")
end
Wait(1500)
DoScreenFadeIn(1500)
end)
elseif Action == "Exit" then
DoScreenFadeOut(1500)
Wait(1500)
ESX.TriggerServerCallback("esx_property:PMexitOffice", function(HasExited)
if HasExited then
ESX.ShowNotification(TranslateCap("exit_office"), "success")
else
ESX.ShowNotification(TranslateCap("exit_office_error"), "error")
end
Wait(1500)
DoScreenFadeIn(1500)
end)
elseif Action == "Properties" then
TriggerEvent("esx_property:AdminMenu")
elseif Action == "ActionsMenu" then
local elements = {{unselectable = true, title = TranslateCap("actions"), value = "RealEstateActions"}}
if ESX.PlayerData.job.name == PM.job then
if ESX.PlayerData.job.grade >= PM.Permissions.CreateProperty then
elements[#elements + 1] = {title = TranslateCap("property_create"), value = "CreateProperty"}
end
if ESX.PlayerData.job.grade >= PM.Permissions.ManagePropertiesFromQuickActions then
elements[#elements + 1] = {title = TranslateCap("property_manage"), value = "manage"}
end
end
ESX.OpenContext("right", elements, function(menu, element)
if element.value == "CreateProperty" then
TriggerEvent("esx_property:CreateProperty")
end
if element.value == "manage" then
TriggerEvent("esx_property:AdminMenu")
end
end)
end
end
ESX.RegisterInput(TranslateCap("realestate_command"), TranslateCap("realestate_command_desc"), "keyboard", "F5", function()
ESX.TriggerServerCallback('esx_property:CanAccessRealEstateMenu', function(Access)
if Access then
OpenPMQuickMenu("ActionsMenu")
end
end)
end)
local PMdrawing = {Entrance = false, Exit = false}
CreateThread(function()
while PM.Enabled do
local Sleep = 2500
local DrawMarker = DrawMarker
if ESX.IsPlayerLoaded() then
if ESX.PlayerData.job and ESX.PlayerData.job.name == PM.job then
Sleep = 1500
local Coords = GetEntityCoords(ESX.PlayerData.ped)
local nearby = false
for k, v in pairs(PM.Locations) do
local Dist = #(Coords - v)
if Dist <= 10.0 then
nearby = true
Sleep = 0
DrawMarker(27, v, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
if Dist <= 1.5 then
if not PMdrawing[k] then
PMdrawing[k] = true
ESX.TextUI(TranslateCap("realestate_textui", k))
end
if IsControlJustPressed(0, 38) then
OpenPMQuickMenu(k)
end
end
else
if not nearby and PMdrawing[k] then
ESX.HideUI()
PMdrawing[k] = false
ESX.CloseContext()
end
end
end
end
end
Wait(Sleep)
end
end)
local HouseData = {}
RegisterNetEvent("esx_property:CreateProperty", function()
ESX.TriggerServerCallback('esx_property:CanCreateProperty', function(data)
if data then
local GetEntityCoords = GetEntityCoords
local GetStreetNameAtCoord = GetStreetNameAtCoord
local GetStreetNameFromHashKey = GetStreetNameFromHashKey
local Pcoords = GetEntityCoords(ESX.PlayerData.ped)
local StreetHash = GetStreetNameAtCoord(Pcoords.x, Pcoords.y, Pcoords.z)
local StreetName = GetStreetNameFromHashKey(StreetHash)
local Zone = GetZoneAtCoords(Pcoords.x, Pcoords.y, Pcoords.z)
local ZoneScum = GetZoneScumminess(Zone)
local SuggestedPrice = Config.ZonePriceOptions.Enabled and Config.ZonePriceOptions.Default * Config.ZonePrices[ZoneScum] or nil
HouseData = {}
local Property = {{unselectable = true, icon = "fas fa-plus", title = TranslateCap("menu_title")},
{value = 0, title = TranslateCap("element_title1"), icon = "fas fa-list-ol", description = TranslateCap("element_description1"), input = true,
inputType = "number", inputPlaceholder = "Number...", inputValue = nil, inputMin = 1, inputMax = 90000, index = "hnumber"},
{title = TranslateCap("element_title2"), icon = "fas fa-dollar-sign", input = true, inputType = "number",description = TranslateCap("element_description2"),
inputPlaceholder = "Price...", inputValue = SuggestedPrice, inputMin = 1, inputMax = 900000000, index = "price"},
{title = TranslateCap("element_title3"), description = TranslateCap("element_description3"), icon = "fas fa-home", index = "interior"},
{title = TranslateCap("element_title4"), description = TranslateCap("element_description4"), icon = "fas fa-warehouse", value = {enabled = false},
index = "garage", disabled = not (Config.Garage.Enabled)},
{title = TranslateCap("element_title5"), description = TranslateCap("element_description5"), icon = "fas fa-video",
value = {enabled = false, rot = GetGameplayCamRot(2), maxleft = 80, maxright = -20}, index = "cctv",
disabled = not (Config.CCTV.Enabled)},
{title = TranslateCap("element_title6"),description = TranslateCap("element_description6"), icon = "fas fa-map-marker-alt", index = "entrance"},
{title = TranslateCap("element_create_title"), icon = "fas fa-check", description = TranslateCap("element_create_desc_1"), index = "creation"}}
local function OpenCreate()
local opos = {}
ESX.OpenContext("right", Property, function(menu, element)
if menu.eles[2] and menu.eles[2].inputValue and menu.eles[1].title == TranslateCap("menu_title") then
Property[2].inputValue = menu.eles[2].inputValue
HouseData.name = menu.eles[2].inputValue .. " " .. StreetName
end
if menu.eles[3] and menu.eles[3].inputValue and menu.eles[1].title == TranslateCap("menu_title") then
Property[3].inputValue = menu.eles[3].inputValue
HouseData.price = menu.eles[3].inputValue
end
if element.index then
if element.index == "entrance" then
local PlayerPos = GetEntityCoords(ESX.PlayerData.ped)
HouseData.entrance = {x = ESX.Math.Round(PlayerPos.x, 2), y = ESX.Math.Round(PlayerPos.y, 2), z = ESX.Math.Round(PlayerPos.z, 2) - 0.98}
Property[7].title = TranslateCap("entrance_set_title")
Property[7].description = TranslateCap("entrance_set_description",HouseData.entrance.x, HouseData.entrance.y, HouseData.entrance.z)
OpenCreate()
end
if element.index == "selectedinterior" then
HouseData.interior = element.value
Property[4].title = TranslateCap("interior_set_title")
Property[4].description = TranslateCap("interior_set_description",element.title)
OpenCreate()
end
if element.index == "IPL" then
local ints = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("ipl_title")}}
for i = 1, #(Config.Interiors.IPL) do
ints[#ints + 1] = {title = Config.Interiors.IPL[i].label, index = "selectedinterior", value = Config.Interiors.IPL[i].value}
exports["esx_context"]:Refresh(ints, "right")
end
end
if element.index == "Shells" then
local ints = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("shell_title")}}
for i = 1, #(Config.Interiors.Shells) do
ints[#ints + 1] = {title = Config.Interiors.Shells[i].label, index = "selectedinterior", value = Config.Interiors.Shells[i].value}
exports["esx_context"]:Refresh(ints, "right")
end
end
if element.index == "interior" then
local catsa = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("types_title")},
{title = TranslateCap("ipl_title"), description = TranslateCap("ipl_description"), index = "IPL"}}
if Config.Shells then
catsa[3] = {title = TranslateCap("shell_title"), description = TranslateCap("shell_description"), index = "Shells"}
end
exports["esx_context"]:Refresh(catsa, "right")
end
if element.index == "return" then
OpenCreate()
end
if element.index == "cctv" then
local status = Property[6].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-video", title = TranslateCap("cctv_settings")},
{title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fas fa-eye" or "fas fa-eye-slash",
description = TranslateCap("toggle_description",status), index = "ToggleCCTV"},
{title = TranslateCap("cctv_set_title"), icon = "fas fa-rotate", disabled = not Property[6].value.enabled,
description = TranslateCap("cctv_set_description"), index = "SetCCTVangle"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}}
exports["esx_context"]:Refresh(opos, "right")
end
if element.index == "ToggleCCTV" then
Property[6].value.enabled = not Property[6].value.enabled
local status = Property[6].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-video", title = TranslateCap("cctv_settings")},
{title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fas fa-eye" or "fas fa-eye-slash",
description = TranslateCap("toggle_description",status), index = "ToggleCCTV"},
{title = TranslateCap("cctv_set_title"), icon = "fas fa-rotate", disabled = not Property[6].value.enabled,
description = TranslateCap("cctv_set_description"), index = "SetCCTVangle"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}}
exports["esx_context"]:Refresh(opos, "right")
end
if Config.Garage.Enabled and element.index == "garage" then
local status = Property[5].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
{title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = TranslateCap("toggle_description",status), index = "ToggleGarage"}}
if Property[5].value.enabled then
opos[#opos + 1] = {title = TranslateCap("garage_set_title"), icon = "fas fa-map-marker-alt", disabled = not Property[5].value.enabled,
description = TranslateCap("garage_set_description"), index = "SetGaragePos"}
if Property[5].value.pos then
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
end
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
end
if element.index == "ToggleGarage" then
Property[5].value.enabled = not Property[5].value.enabled
local status = Property[5].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
{title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = TranslateCap("toggle_description",status), index = "ToggleGarage"}}
if Property[5].value.enabled then
opos[#opos + 1] = {title = TranslateCap("garage_set_title"), icon = "fas fa-map-marker-alt", disabled = not Property[5].value.enabled,
description = TranslateCap("garage_set_description"), index = "SetGaragePos"}
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
end
if element.index == "SetGaragePos" then
ESX.CloseContext()
ESX.TextUI(TranslateCap("garage_textui"))
while true do
Wait(0)
if IsControlJustPressed(0, 38) then
local PlayerPos = GetEntityCoords(ESX.PlayerData.ped)
Property[5].value.pos = GetEntityCoords(ESX.PlayerData.ped)
Property[5].value.heading = GetEntityHeading(ESX.PlayerData.ped)
ESX.HideUI()
OpenCreate()
break
end
end
end
if element.index == "SetCCTVangle" then
ESX.CloseContext()
ESX.TextUI(TranslateCap("cctv_textui_1"))
local stage = "angle"
while true do
Wait(0)
if IsControlJustPressed(0, 38) then
if stage == "angle" then
Property[6].value.rot = GetGameplayCamRot(2)
ESX.TextUI(TranslateCap("cctv_textui_2"))
stage = "maxright"
elseif stage == "maxright" then
Property[6].value.maxright = GetGameplayCamRot(2).z
ESX.TextUI(TranslateCap("cctv_textui_3"))
stage = "maxleft"
elseif stage == "maxleft" then
Property[6].value.maxleft = GetGameplayCamRot(2).z
ESX.HideUI()
OpenCreate()
break
end
end
end
end
if element.index == "creation" then
if HouseData.price and HouseData.name and HouseData.entrance and HouseData.interior then
local newProperty = {name = HouseData.name, price = HouseData.price, interior = HouseData.interior, entrance = HouseData.entrance,
cctv = Property[6].value, garage = Property[5].value}
TriggerServerEvent("esx_property:server:createProperty", newProperty)
ESX.ShowNotification(TranslateCap("create_success"), "success")
ESX.CloseContext()
HouseData = {}
else
ESX.ShowNotification(TranslateCap("missing_data"), "error")
end
end
end
end)
end
OpenCreate()
end
end)
end)
RegisterNetEvent("esx_property:AdminMenu", function()
ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
if data then
function ManageProperty(currentProperty)
local Interior = GetInteriorValues(Properties[currentProperty].Interior)
ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
if data then
local opos = {}
local function GetData()
local elements = {{unselectable = true, icon = "fas fa-cogs", title = "Property Management"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "back"},
{title = "Toggle Lock", icon = (Properties[currentProperty].Locked and "fas fa-lock") or "fas fa-unlock",
description = "Lock/Unlock The Property.", value = "lock"},
{title = "Enter", description = "Force Entry Into The Property.", icon = "fas fa-door-open", value = "enter"},
{title = "Price", icon = "fas fa-dollar-sign", description = "Alter The Price Of The Property.", value = "price"},
{title = "Set Interior", description = "Renovate The Property`s Interior.", icon = "fas fa-home", value = "interior"},
{title = "Entrance", description = "Set The Entrance As Your Position.", icon = "fas fa-map-marker-alt",
value = "entrance"}}
if Properties[currentProperty].setName ~= "" then
elements[#elements + 1] = {title = "Clear Custom Name", icon = "fa-solid fa-ban",
description = "Current Name: " .. Properties[currentProperty].setName, value = "remove_custom_name"}
end
if Config.Furniture.Enabled and #(Properties[currentProperty].furniture) > 0 then
elements[#elements + 1] = {title = "Reset Furniture", description = "Delete All Property Furniture", icon = "fas fa-eraser",
value = "refurni"}
end
if Config.Garage.Enabled then
elements[#elements + 1] = {title = "Garage", description = "Change Garage Settings", icon = "fa-solid fa-warehouse", value = "garage"}
end
if Config.CCTV.Enabled then
elements[#elements + 1] = {title = "CCTV", description = "Change CCTV Settings", icon = "fa-solid fa-camera", value = "cctv"}
end
if (Config.OxInventory) and Properties[currentProperty].positions.Storage and
(ESX.Round(Interior.positions.Storage.x, 2) ~= Properties[currentProperty].positions.Storage.x or
ESX.Round(Interior.positions.Storage.y, 2) ~= Properties[currentProperty].positions.Storage.y) then
elements[#elements + 1] = {title = "Reset Storage Position", description = "Set Storage Position To Interior Default.",
icon = "fas fa-eraser", value = "restorage"}
end
if Interior.positions.Wardrobe then
if ESX.Round(Interior.positions.Wardrobe.x, 2) ~= ESX.Round(Properties[currentProperty].positions.Wardrobe.x, 2) or
ESX.Round(Interior.positions.Wardrobe.y, 2) ~= ESX.Round(Properties[currentProperty].positions.Wardrobe.y, 2) then
elements[#elements + 1] = {title = "Reset Wardrobe Position", description = "Set Wardrobe Position To Interior Default.",
icon = "fas fa-eraser", value = "rewardrobe"}
end
end
if Properties[currentProperty].Owned then
elements[#elements + 1] = {title = "Remove Owner", icon = "fas fa-user-times", description = "Evict The Owner Of The Property.",
value = "removeowner"}
end
return elements
end
ESX.OpenContext("right", GetData(), function(menu, element)
if element.value then
if element.value == "lock" then
ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
if IsUnlocked then
ESX.ShowNotification("Lock Toggled!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Lock This Property", "error")
end
end, currentProperty)
end
if element.value == "enter" then
AttemptHouseEntry(currentProperty)
end
if element.value == "removeowner" then
ESX.TriggerServerCallback("esx_property:evictOwner", function(Evicted)
if Evicted then
ESX.ShowNotification("Owner Evicted!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Evict This Owner!", "error")
end
end, currentProperty)
end
if element.value == "garage" then
local status = Properties[currentProperty].garage.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
{title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = "Current Status: " .. status, value = "ToggleGarage"}}
if Properties[currentProperty].garage.enabled then
opos[#opos + 1] = {title = "Set Position", icon = "fas fa-map-marker-alt",
disabled = not Properties[currentProperty].garage.enabled,
description = "Sets the Garage Position to your Players Position", value = "SetGaragePos"}
if Properties[currentProperty].garage.pos then
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
value = "return"}
end
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management", value = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
end
if element.value == "cctv" then
local status = Properties[currentProperty].cctv.enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("cctv_settings")},
{title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = "Current Status: " .. status, value = "ToggleCCTV"}}
if Properties[currentProperty].cctv.enabled then
opos[#opos + 1] = {title = "Set Angle", icon = "fas fa-map-marker-alt", disabled = not Properties[currentProperty].cctv.enabled,
description = "Sets the Angle of the Camera.", value = "SetCCTVangle"}
if Properties[currentProperty].cctv.rot then
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
value = "return"}
end
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management", value = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
end
if element.value == "ToggleGarage" then
ESX.TriggerServerCallback("esx_property:toggleGarage", function(IsUnlocked, enabled)
if IsUnlocked then
ESX.ShowNotification("Garage Toggled!", "success")
local status = enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
{title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = "Current Status: " .. status, value = "ToggleGarage"}}
if enabled then
opos[#opos + 1] = {title = "Set Position", icon = "fas fa-map-marker-alt", disabled = not enabled,
description = "Sets the Garage Position to your Players Position", value = "SetGaragePos"}
if Properties[currentProperty].garage.pos then
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
value = "return"}
end
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management",
value = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
else
ESX.ShowNotification("You ~r~Cannot~s~ Toggle This Option!", "error")
end
end, currentProperty)
end
if element.value == "ToggleCCTV" then
ESX.TriggerServerCallback("esx_property:toggleCCTV", function(IsUnlocked, enabled)
if IsUnlocked then
ESX.ShowNotification("CCTV Toggled!", "success")
local status = enabled and TranslateCap("enabled") or TranslateCap("disabled")
opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("cctv_settings")},
{title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
description = "Current Status: " .. status, value = "ToggleCCTV"}}
if enabled then
opos[#opos + 1] = {title = "Set Angle", icon = "fas fa-map-marker-alt", disabled = not enabled,
description = "Sets the Angle of the Camera.", value = "SetCCTVangle"}
if Properties[currentProperty].cctv.rot then
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
value = "return"}
end
else
opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management",
value = "return"}
end
exports["esx_context"]:Refresh(opos, "right")
else
ESX.ShowNotification("You ~r~Cannot~s~ Toggle This Option!", "error")
end
end, currentProperty)
end
if element.value == "SetGaragePos" then
ESX.CloseContext()
ESX.TextUI("Press ~b~[E]~s~ to Set Position")
SettingValue = "Garage"
while SettingValue ~= "" do
Wait(0)
if IsControlJustPressed(0, 38) then
ESX.TriggerServerCallback("esx_property:SetGaragePos", function(IsChanged)
if IsChanged then
ESX.HideUI()
SettingValue = ""
ESX.ShowNotification("Position Changed!", "success")
ManageProperty(currentProperty)
else
ESX.ShowNotification("You ~r~Cannot~s~ Change This Option!", "error")
end
end, currentProperty, GetEntityHeading(ESX.PlayerData.ped))
break
end
end
end
if element.value == "SetCCTVangle" then
ESX.CloseContext()
ESX.TextUI("Press ~b~[E]~s~ to Set Angle")
local stage = "angle"
SettingValue = "cctv"
local Angles = {}
while stage do
Wait(0)
if IsControlJustPressed(0, 38) then
if stage == "angle" then
Angles.rot = GetGameplayCamRot(2)
ESX.TextUI("Press ~b~[E]~s~ to Set Max Right Roation")
stage = "maxright"
elseif stage == "maxright" then
Angles.maxright = GetGameplayCamRot(2).z
ESX.TextUI("Press ~b~[E]~s~ to Set Max Left Roation")
stage = "maxleft"
elseif stage == "maxleft" then
Angles.maxleft = GetGameplayCamRot(2).z
ESX.TriggerServerCallback("esx_property:SetCCTVangle", function(IsChanged)
if IsChanged then
SettingValue = ""
stage = nil
ESX.HideUI()
ESX.ShowNotification("Angle Changed!", "success")
ManageProperty(currentProperty)
else
ESX.ShowNotification("You ~r~Cannot~s~ Change This Option!", "error")
end
end, currentProperty, Angles)
break
end
end
end
end
if element.value == "remove_custom_name" then
ESX.TriggerServerCallback("esx_property:RemoveCustomName", function(Cleared)
if Cleared then
ESX.ShowNotification("Property Name Reset!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Reset This Property`s Name!", "error")
end
end, currentProperty)
end
if element.value == "refurni" then
ESX.TriggerServerCallback("esx_property:RemoveAllfurniture", function(Removed)
if Removed then
ESX.ShowNotification("Furniture Reset!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Reset This Property!", "error")
end
end, currentProperty)
end
if element.value == "restorage" then
ESX.TriggerServerCallback("esx_property:SetInventoryPosition", function(Reset)
if Reset then
ESX.ShowNotification("~b~Storage~s~ Position Reset!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Reset This Property!", "error")
end
end, currentProperty, Interior.positions.Storage, true)
end
if element.value == "rewardrobe" then
ESX.TriggerServerCallback("esx_property:SetWardrobePosition", function(Reset)
if Reset then
ESX.ShowNotification("~b~Wardrobe~s~ Position Reset!", "success")
exports["esx_context"]:Refresh(GetData())
else
ESX.ShowNotification("You Cannot Reset This Property!", "error")
end
end, currentProperty, Interior.positions.Wardrobe, true)
end
if element.value == "back" then
AdminOptions(currentProperty)
end
if element.value == "return" then
exports["esx_context"]:Refresh(GetData())
end
if element.value == "price" then
ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'PropertyPrice', {title = "Property Price"}, function(data4, menu4)
if data4.value then
ESX.TriggerServerCallback("esx_property:ChangePrice", function(IsChanged)
if IsChanged then
ESX.ShowNotification("Price Changed!", "success")
menu4.close()
else
ESX.ShowNotification("You Cannot Change this property!", "error")
end
end, currentProperty, tonumber(data4.value))
end
end, function(data4, menu4)
menu4.close()
end)
end
if element.value == "interior" then
local elements = {{unselectable = true, icon = "fas fa-warehouse", title = "Interior Types"},
{title = "IPL Interiors", description = "Native GTA Interiors, Made by R*", value = "IPL"}}
if Config.Shells then
elements[3] = {title = "Custom Interiors", description = "Custom Interiors, Made by You", value = "Shells"}
end
ESX.OpenContext("right", elements, function(menu, element)
if element.value then
local elements = {{unselectable = true, icon = "fas fa-warehouse", title = "Interiors"}}
for i = 1, #(Config.Interiors[element.value]) do
elements[#elements + 1] = {title = Config.Interiors[element.value][i].label, value = Config.Interiors[element.value][i].value}
end
ESX.OpenContext("right", elements, function(menu, element)
if element.value then
ESX.TriggerServerCallback("esx_property:ChangeInterior", function(IsChanged)
if IsChanged then
ESX.ShowNotification("Interior Changed!", "success")
ESX.CloseContext()
else
ESX.ShowNotification("You Cannot Change this property!", "error")
end
end, currentProperty, element.value)
end
end)
end
end, function()
ManageProperty(currentProperty)
end)
end
if element.value == "entrance" then
ESX.TriggerServerCallback("esx_property:ChangeEntrance", function(IsChanged)
if IsChanged then
ESX.ShowNotification("Entrance Changed!", "success")
else
ESX.ShowNotification("You Cannot Change this property!", "error")
end
end, currentProperty, GetEntityCoords(ESX.PlayerData.ped))
end
end
end)
end
end)
end
function AdminOptions(currentProperty)
ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
if data then
local elements = {{unselectable = true, icon = "fas fa-home", title = "Property Options"},
{title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "back"},
{title = "Manage", icon = "fas fa-cogs", description = "Alter This Property's Settings.", value = "manage"},
{title = "Teleport", description = "Teleport To This Property.", icon = "fas fa-map-marker-alt", value = "goto"},
{title = "Set GPS", description = "Set GPS position To Property.", icon = "fa-solid fa-location-dot", value = "gps"},
{title = "Delete", icon = "fas fa-trash-alt", description = "Remove Current Property.", value = "delete"}}
ESX.OpenContext("right", elements, function(menu, element)
if element.value then
if element.value == "goto" then
SetEntityCoords(ESX.PlayerData.ped, Properties[currentProperty].Entrance.x, Properties[currentProperty].Entrance.y,
Properties[currentProperty].Entrance.z)
ESX.ShowNotification("Teleported to Property!")
end
if element.value == "gps" then
SetNewWaypoint(Properties[currentProperty].Entrance.x, Properties[currentProperty].Entrance.y)
ESX.ShowNotification("GPS Set!")
end
if element.value == "back" then
AdminMenu()
end
if element.value == "delete" then
ESX.TriggerServerCallback("esx_property:deleteProperty", function(response)
if response then
ESX.ShowNotification("Property Deleted!", "success")
ESX.CloseContext()
else
ESX.ShowNotification("You Cannot Delete This Property", "error")
end
end, currentProperty)
end
if element.value == "manage" then
ManageProperty(currentProperty)
end
end
end)
end
end)
end
function AdminMenu()
ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
if data then
local elements = {{unselectable = true, icon = "fas fa-home", title = "Properties Management"}}
for i = 1, #(Properties) do
if Properties[i].Entrance then
local description = ""
if Properties[i].setName ~= "" then
description = description .. "\nName: " .. Properties[i].setName
end
if Properties[i].Owned then
description = description .. "\nOwner: " .. Properties[i].OwnerName
end
table.insert(elements, {title = Properties[i].Name, value = i, description = description, icon = "fas fa-home"})
end
end
ESX.OpenContext("right", elements, function(menu, element)
if element.value then
ESX.CloseContext()
AdminOptions(element.value)
end
end)
end
end)
end
AdminMenu()
else
ESX.ShowNotification("You ~r~Cannot~s~ Access This Menu!", 5000, "error")
end
end)
end)