472 lines
17 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local sharedConfig = require 'config.shared'
local clientConfig = require 'config.client'
local interiorShell
DecorationObjects = {}
local properties = {}
local insideProperty = false
local isPropertyRental = false
local interactions
local isConcealing = false
local concealWhitelist = {}
local blips = {}
local function createBlip(apartmentCoords, label)
local blip = AddBlipForCoord(apartmentCoords.x, apartmentCoords.y, apartmentCoords.z)
SetBlipSprite(blip, 40)
SetBlipAsShortRange(blip, true)
SetBlipScale(blip, 0.8)
SetBlipColour(blip, 2)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString(label)
EndTextCommandSetBlipName(blip)
return blip
end
local function prepareKeyMenu()
local keyholders = lib.callback.await('qbx_properties:callback:requestKeyHolders')
local options = {
{
title = locale('menu.add_keyholder'),
icon = 'plus',
arrow = true,
onSelect = function()
local insidePlayers = lib.callback.await('qbx_properties:callback:requestPotentialKeyholders')
local options = {}
for i = 1, #insidePlayers do
options[#options + 1] = {
title = insidePlayers[i].name,
icon = 'user',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = insidePlayers[i].name,
content = locale('alert.give_keys'),
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:addKeyholder', insidePlayers[i].citizenid)
end
end
}
end
lib.registerContext({
id = 'qbx_properties_insideMenu',
title = locale('menu.people_inside'),
menu = 'qbx_properties_keyMenu',
options = options
})
lib.showContext('qbx_properties_insideMenu')
end
}
}
for i = 1, #keyholders do
options[#options + 1] = {
title = keyholders[i].name,
icon = 'user',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = keyholders[i].name,
content = locale('alert.want_remove_keys'),
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:removeKeyholder', keyholders[i].citizenid)
end
end
}
end
lib.registerContext({
id = 'qbx_properties_keyMenu',
title = locale('menu.keyholders'),
menu = 'qbx_properties_manageMenu',
options = options
})
lib.showContext('qbx_properties_keyMenu')
end
local function prepareDoorbellMenu()
local ringers = lib.callback.await('qbx_properties:callback:requestRingers')
local options = {}
for i = 1, #ringers do
options[#options + 1] = {
title = ringers[i].name,
icon = 'user',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = ringers[i].name,
content = locale('alert.want_let_person_in'),
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:letRingerIn', ringers[i].citizenid)
end
end
}
end
lib.registerContext({
id = 'qbx_properties_doorbellMenu',
title = locale('menu.doorbell_ringers'),
menu = 'qbx_properties_manageMenu',
options = options
})
lib.showContext('qbx_properties_doorbellMenu')
end
local function prepareManageMenu()
local hasAccess = lib.callback.await('qbx_properties:callback:checkAccess')
if not hasAccess then exports.qbx_core:Notify(locale('notify.no_access'), 'error') return end
local options = {
{
title = locale('menu.manage_keys'),
icon = 'key',
arrow = true,
onSelect = function()
prepareKeyMenu()
end
},
{
title = locale('menu.doorbell'),
icon = 'bell',
arrow = true,
onSelect = function()
prepareDoorbellMenu()
end
},
{
title = locale('menu.start_decorating'),
icon = 'shrimp',
onSelect = function()
ToggleDecorating()
end
}
}
if isPropertyRental then
options[#options+1] = {
title = 'Stop Renting',
icon = 'file-invoice-dollar',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = 'Stop Renting',
content = 'Are you sure that you want to stop renting this place?',
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:stopRenting')
end
end
}
end
lib.registerContext({
id = 'qbx_properties_manageMenu',
title = locale('menu.manage_property'),
options = options
})
lib.showContext('qbx_properties_manageMenu')
end
local function checkInteractions()
local interactOptions = {
['stash'] = function(coords)
qbx.drawText3d({ coords = coords, text = locale('drawtext.stash') })
if IsControlJustPressed(0, 38) then
TriggerServerEvent('qbx_properties:server:openStash')
end
end,
['exit'] = function(coords)
qbx.drawText3d({ coords = coords, text = locale('drawtext.exit') })
if IsControlJustPressed(0, 38) then
DoScreenFadeOut(1000)
while not IsScreenFadedOut() do Wait(0) end
TriggerServerEvent('qbx_properties:server:exitProperty')
end
if IsControlJustPressed(0, 47) then
prepareManageMenu()
end
end,
['clothing'] = function(coords)
qbx.drawText3d({ coords = coords, text = locale('drawtext.clothing') })
if IsControlJustPressed(0, 38) then
exports['illenium-appearance']:startPlayerCustomization(function(appearance)
if appearance then
TriggerServerEvent("illenium-appearance:server:saveAppearance", appearance)
end
end, {
components = true, componentConfig = { masks = true, upperBody = true, lowerBody = true, bags = true, shoes = true, scarfAndChains = true, bodyArmor = true, shirts = true, decals = true, jackets = true },
props = true, propConfig = { hats = true, glasses = true, ear = true, watches = true, bracelets = true },
enableExit = true,
})
end
if IsControlJustPressed(0, 47) then
TriggerEvent('illenium-appearance:client:openOutfitMenu')
end
end,
['logout'] = function(coords)
qbx.drawText3d({ coords = coords, text = locale('drawtext.logout') })
if IsControlJustPressed(0, 38) then
DoScreenFadeOut(1000)
while not IsScreenFadedOut() do Wait(0) end
TriggerServerEvent('qbx_properties:server:logoutProperty')
end
end,
}
CreateThread(function()
while insideProperty do
local sleep = 800
local playerCoords = GetEntityCoords(cache.ped)
for i = 1, #interactions do
if #(playerCoords - interactions[i].coords) < 1.5 and not IsDecorating then
sleep = 0
interactOptions[interactions[i].type](interactions[i].coords)
end
end
Wait(sleep)
end
end)
end
local function hideExterior(name)
local models = clientConfig.exteriorHashs[name]
if not models then return end
CreateThread(function()
while insideProperty do
for i = 1, #models, 1 do
EnableExteriorCullModelThisFrame(models[i])
end
Wait(0)
end
end)
end
RegisterNetEvent('qbx_properties:client:updateInteractions', function(interactionsData, interiorString, isRental)
DoScreenFadeIn(1000)
interactions = interactionsData
insideProperty = true
isPropertyRental = isRental
checkInteractions()
hideExterior(interiorString)
end)
RegisterNetEvent('qbx_properties:client:createInterior', function(interiorHash, interiorCoords)
lib.requestModel(interiorHash, 2000)
interiorShell = CreateObjectNoOffset(interiorHash, interiorCoords.x, interiorCoords.y, interiorCoords.z, false, false, false)
FreezeEntityPosition(interiorShell, true)
SetModelAsNoLongerNeeded(interiorHash)
end)
RegisterNetEvent('qbx_properties:client:loadDecorations', function(decorations)
for i = 1, #decorations do
local decoration = decorations[i]
lib.requestModel(decoration.model, 5000)
DecorationObjects[decoration.id] = CreateObjectNoOffset(decoration.model, decoration.coords.x, decoration.coords.y, decoration.coords.z, false, false, false)
SetEntityCollision(DecorationObjects[decoration.id], true, true)
FreezeEntityPosition(DecorationObjects[decoration.id], true)
SetEntityRotation(DecorationObjects[decoration.id], decoration.rotation.x, decoration.rotation.y, decoration.rotation.z, 2, false)
SetModelAsNoLongerNeeded(decoration.model)
end
end)
RegisterNetEvent('qbx_properties:client:addDecoration', function(id, hash, coords, rotation)
lib.requestModel(hash, 5000)
DecorationObjects[id] = CreateObjectNoOffset(hash, coords.x, coords.y, coords.z, false, false, false)
FreezeEntityPosition(DecorationObjects[id], true)
SetEntityRotation(DecorationObjects[id], rotation.x, rotation.y, rotation.z, 2, false)
SetModelAsNoLongerNeeded(hash)
end)
RegisterNetEvent('qbx_properties:client:removeDecoration', function(objectId)
if DoesEntityExist(DecorationObjects[objectId]) then DeleteEntity(DecorationObjects[objectId]) end
DecorationObjects[objectId] = nil
end)
RegisterNetEvent('qbx_properties:client:unloadProperty', function()
DoScreenFadeIn(1000)
insideProperty = false
if DoesEntityExist(interiorShell) then DeleteEntity(interiorShell) end
for _, v in pairs(DecorationObjects) do
if DoesEntityExist(v) then DeleteEntity(v) end
end
interiorShell = nil
DecorationObjects = {}
end)
local function singlePropertyMenu(property, noBackMenu)
local options = {}
if QBX.PlayerData.citizenid == property.owner or lib.table.contains(json.decode(property.keyholders), QBX.PlayerData.citizenid) then
options[#options + 1] = {
title = locale('menu.enter'),
icon = 'cog',
arrow = true,
onSelect = function()
DoScreenFadeOut(1000)
while not IsScreenFadedOut() do Wait(0) end
end,
serverEvent = 'qbx_properties:server:enterProperty',
args = { id = property.id }
}
elseif property.owner == nil then
if property.rent_interval then
options[#options + 1] = {
title = 'Rent',
icon = 'dollar-sign',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = string.format('Renting - %s', property.property_name),
content = string.format('Are you sure you want to rent %s for $%s which will be billed every %sh(s)?', property.property_name, property.price, property.rent_interval),
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:rentProperty', property.id)
end
end,
}
else
options[#options + 1] = {
title = 'Buy',
icon = 'dollar-sign',
arrow = true,
onSelect = function()
local alert = lib.alertDialog({
header = string.format('Buying - %s', property.property_name),
content = string.format('Are you sure you want to buy %s for $%s?', property.property_name, property.price),
centered = true,
cancel = true
})
if alert == 'confirm' then
TriggerServerEvent('qbx_properties:server:buyProperty', property.id)
end
end,
}
end
else
options[#options + 1] = {
title = locale('menu.ring_doorbell'),
icon = 'bell',
arrow = true,
serverEvent = 'qbx_properties:server:ringProperty',
args = { id = property.id }
}
end
local menu = 'qbx_properties_propertiesMenu'
---@diagnostic disable-next-line: cast-local-type
if noBackMenu then menu = nil end
lib.registerContext({
id = 'qbx_properties_propertyMenu',
title = property.property_name,
menu = menu,
options = options
})
lib.showContext('qbx_properties_propertyMenu')
end
local function propertyMenu(propertyList, owned)
local options = {
{
title = locale('menu.retrieve_properties'),
description = locale('menu.show_owned_properties'),
icon = 'bars',
onSelect = function()
propertyMenu(propertyList, true)
end
}
}
for i = 1, #propertyList do
if owned and propertyList[i].owner == QBX.PlayerData.citizenid or lib.table.contains(json.decode(propertyList[i].keyholders), QBX.PlayerData.citizenid) then
options[#options + 1] = {
title = propertyList[i].property_name,
icon = 'home',
arrow = true,
onSelect = function()
singlePropertyMenu(propertyList[i])
end
}
elseif not owned then
options[#options + 1] = {
title = propertyList[i].property_name,
icon = 'home',
arrow = true,
onSelect = function()
singlePropertyMenu(propertyList[i])
end
}
end
end
lib.registerContext({
id = 'qbx_properties_propertiesMenu',
title = locale('menu.properties'),
options = options
})
lib.showContext('qbx_properties_propertiesMenu')
end
function PreparePropertyMenu(propertyCoords)
local propertyList = lib.callback.await('qbx_properties:callback:requestProperties', false, propertyCoords)
if #propertyList == 1 then
singlePropertyMenu(propertyList[1], true)
else
propertyMenu(propertyList)
end
end
CreateThread(function()
for i = 1, #sharedConfig.apartmentOptions do
local data = sharedConfig.apartmentOptions[i]
if not blips[data.enter] then
blips[data.enter] = createBlip(data.enter, data.label)
end
end
properties = lib.callback.await('qbx_properties:callback:loadProperties')
while true do
local sleep = 800
local playerCoords = GetEntityCoords(cache.ped)
for i = 1, #properties do
if #(playerCoords - properties[i].xyz) < 1.6 then
sleep = 0
qbx.drawText3d({ coords = properties[i].xyz, text = locale('drawtext.view_property') })
if IsControlJustPressed(0, 38) then
PreparePropertyMenu(properties[i])
end
end
end
Wait(sleep)
end
end)
RegisterNetEvent('qbx_properties:client:concealPlayers', function(playerIds)
local players = GetActivePlayers()
for i = 1, #players do NetworkConcealPlayer(players[i], false, false) end
concealWhitelist = playerIds
if not isConcealing then
isConcealing = true
while isConcealing do
players = GetActivePlayers()
for i = 1, #players do
if not lib.table.contains(concealWhitelist, GetPlayerServerId(players[i])) then
NetworkConcealPlayer(players[i], true, false)
end
end
Wait(3000)
end
end
end)
RegisterNetEvent('qbx_properties:client:revealPlayers', function()
local players = GetActivePlayers()
for i = 1, #players do NetworkConcealPlayer(players[i], false, false) end
isConcealing = false
end)
RegisterNetEvent('qbx_properties:client:addProperty', function(propertyCoords)
if lib.table.contains(properties, propertyCoords) then return end
properties[#properties + 1] = propertyCoords
end)