354 lines
9.0 KiB
Lua
354 lines
9.0 KiB
Lua
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||
|
|
||
|
PropertiesTable = {}
|
||
|
|
||
|
local showBlipsForSale = false
|
||
|
local showBlipsOwned = false
|
||
|
|
||
|
local blipsForSale = {}
|
||
|
local blipsOwned = {}
|
||
|
|
||
|
local UIOpen = false
|
||
|
|
||
|
local tabletObj = nil
|
||
|
local tabletDict = "amb@code_human_in_bus_passenger_idles@female@tablet@base"
|
||
|
local tabletAnim = "base"
|
||
|
local tabletProp = Config.AnimationProp
|
||
|
local tabletBone = 60309
|
||
|
local tabletOffset = vector3(0.03, 0.002, -0.0)
|
||
|
local tabletRot = vector3(10.0, 160.0, 0.0)
|
||
|
|
||
|
local function doAnimation()
|
||
|
if not UIOpen then return end
|
||
|
-- Animation
|
||
|
RequestAnimDict(tabletDict)
|
||
|
while not HasAnimDictLoaded(tabletDict) do Citizen.Wait(100) end
|
||
|
-- Model
|
||
|
RequestModel(tabletProp)
|
||
|
while not HasModelLoaded(tabletProp) do Citizen.Wait(100) end
|
||
|
|
||
|
local plyPed = PlayerPedId()
|
||
|
tabletObj = CreateObject(tabletProp, 0.0, 0.0, 0.0, true, true, false)
|
||
|
local tabletBoneIndex = GetPedBoneIndex(plyPed, tabletBone)
|
||
|
|
||
|
AttachEntityToEntity(tabletObj, plyPed, tabletBoneIndex, tabletOffset.x, tabletOffset.y, tabletOffset.z, tabletRot.x, tabletRot.y, tabletRot.z, true, false, false, false, 2, true)
|
||
|
SetModelAsNoLongerNeeded(tabletProp)
|
||
|
|
||
|
CreateThread(function()
|
||
|
while UIOpen do
|
||
|
Wait(0)
|
||
|
if not IsEntityPlayingAnim(plyPed, tabletDict, tabletAnim, 3) then
|
||
|
TaskPlayAnim(plyPed, tabletDict, tabletAnim, 3.0, 3.0, -1, 49, 0, 0, 0, 0)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
ClearPedSecondaryTask(plyPed)
|
||
|
Citizen.Wait(250)
|
||
|
DetachEntity(tabletObj, true, false)
|
||
|
DeleteEntity(tabletObj)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
RegisterNetEvent('QBCore:Server:UpdateObject', function()
|
||
|
if source ~= '' then return false end
|
||
|
QBCore = exports['qb-core']:GetCoreObject()
|
||
|
end)
|
||
|
|
||
|
local function toggleUI(bool)
|
||
|
UIOpen = bool
|
||
|
SetNuiFocus(bool, bool)
|
||
|
SendNUIMessage({
|
||
|
action = "setVisible",
|
||
|
data = bool
|
||
|
})
|
||
|
|
||
|
if Config.PlayAnimation then
|
||
|
doAnimation()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
RegisterNUICallback("hideUI", function()
|
||
|
toggleUI(false)
|
||
|
end)
|
||
|
|
||
|
local function setRealtor(jobInfo)
|
||
|
if jobInfo.name == Config.RealtorJobName then
|
||
|
SendNUIMessage({
|
||
|
action = "setRealtorGrade",
|
||
|
data = jobInfo.grade.level
|
||
|
})
|
||
|
else
|
||
|
SendNUIMessage({
|
||
|
action = "setRealtorGrade",
|
||
|
data = -1
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
RegisterNetEvent("QBCore:Client:OnJobUpdate", setRealtor)
|
||
|
|
||
|
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
|
||
|
SendNUIMessage({
|
||
|
action = "setConfig",
|
||
|
data = Config.RealtorPerms
|
||
|
})
|
||
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
setRealtor(PlayerData.job)
|
||
|
end)
|
||
|
|
||
|
--this was mainly used for dev
|
||
|
AddEventHandler("onResourceStart", function(resName)
|
||
|
if (GetCurrentResourceName() == resName) then
|
||
|
Wait(2000)
|
||
|
SendNUIMessage({
|
||
|
action = "setConfig",
|
||
|
data = Config.RealtorPerms
|
||
|
})
|
||
|
|
||
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
setRealtor(PlayerData.job)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
if Config.UseCommand then
|
||
|
RegisterCommand("housing", function()
|
||
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
if not PlayerData.metadata["isdead"] and not PlayerData.metadata["inlaststand"] and not PlayerData.metadata["ishandcuffed"] and not IsPauseMenuActive() then
|
||
|
toggleUI(not UIOpen)
|
||
|
end
|
||
|
end, false)
|
||
|
end
|
||
|
|
||
|
RegisterNetEvent('ps-realtor:client:toggleUI', function()
|
||
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
||
|
if not PlayerData.metadata["isdead"] and not PlayerData.metadata["inlaststand"] and not PlayerData.metadata["ishandcuffed"] and not IsPauseMenuActive() then
|
||
|
toggleUI(not UIOpen)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
-- Callbacks
|
||
|
RegisterNUICallback("setWaypoint", function (data, cb)
|
||
|
lib.notify({ description = 'Waypoint was set!' , type = 'success'})
|
||
|
SetNewWaypoint(data.x, data.y)
|
||
|
cb("ok")
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("updatePropertyData", function(data, cb)
|
||
|
local property_id = data.property_id
|
||
|
local newData = data.data
|
||
|
local changeType = data.type
|
||
|
|
||
|
if changeType == 'UpdateShell' then
|
||
|
local currentShells = exports['ps-housing']:GetShells()
|
||
|
local shellName = currentShells[newData.shell].hash
|
||
|
|
||
|
if not IsModelInCdimage(shellName) then
|
||
|
lib.notify({ description = 'The Interior '..newData.shell..' does not exist!', type = 'error'})
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
|
||
|
TriggerServerEvent("ps-realtor:server:updateProperty", changeType, property_id, newData)
|
||
|
cb("ok")
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("addTenantToApartment", function(data, cb)
|
||
|
TriggerServerEvent("ps-realtor:server:addTenantToApartment", data)
|
||
|
cb("ok")
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("getNames", function(data, cb)
|
||
|
if not data then return end
|
||
|
local names = lib.callback.await("ps-realtor:server:getNames",source, data)
|
||
|
cb(names)
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("startZonePlacement", function (data, cb)
|
||
|
cb(1)
|
||
|
SetNuiFocus(false, false)
|
||
|
|
||
|
local type = data.type
|
||
|
local property_id = data.property_id
|
||
|
|
||
|
local newDataPromise = promise.new()
|
||
|
ZoneThread(type, newDataPromise)
|
||
|
local newData = Citizen.Await(newDataPromise)
|
||
|
if not newData then return end
|
||
|
|
||
|
if type == "door" then
|
||
|
type = "UpdateDoor"
|
||
|
elseif type == "garage" then
|
||
|
type = "UpdateGarage"
|
||
|
SendNUIMessage({
|
||
|
action = "garageMade",
|
||
|
data = {
|
||
|
x = newData.x,
|
||
|
y = newData.y,
|
||
|
z = newData.z,
|
||
|
h = newData.heading,
|
||
|
length = 3.0,
|
||
|
width = 5.0,
|
||
|
}
|
||
|
})
|
||
|
end
|
||
|
|
||
|
local streetHash = GetStreetNameAtCoord(newData.x, newData.y, newData.z)
|
||
|
local street = GetStreetNameFromHashKey(streetHash)
|
||
|
|
||
|
local regionHash = GetNameOfZone(newData.x, newData.y, newData.z)
|
||
|
local region = GetLabelText(regionHash)
|
||
|
|
||
|
if type == "UpdateGarage" then
|
||
|
local data = {
|
||
|
garage = newData,
|
||
|
street = street,
|
||
|
region = region,
|
||
|
}
|
||
|
TriggerServerEvent("ps-realtor:server:updateProperty", type, property_id, data)
|
||
|
else
|
||
|
local data = {
|
||
|
door = newData,
|
||
|
street = street,
|
||
|
region = region,
|
||
|
}
|
||
|
TriggerServerEvent("ps-realtor:server:updateProperty", type, property_id, data)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
|
||
|
local function setHide(bool)
|
||
|
SendNUIMessage({
|
||
|
action = "setTempHide",
|
||
|
data = bool
|
||
|
})
|
||
|
SetNuiFocus(not bool, not bool)
|
||
|
end
|
||
|
|
||
|
-- For the zone placement. At some point I will make a proper system but its not a big deal, it works.
|
||
|
function ZoneThread(type, promise)
|
||
|
local findingZone = true
|
||
|
|
||
|
-- default for door
|
||
|
local length = 2.0
|
||
|
local width = 1.0
|
||
|
local zoff = 2.0
|
||
|
local height = 2.5
|
||
|
|
||
|
if type == "garage" then
|
||
|
lib.notify({description="Best to get in a vehicle to see how the zone would look.", type="error"})
|
||
|
|
||
|
length = 3.0
|
||
|
width = 5.0
|
||
|
end
|
||
|
|
||
|
CreateThread(function()
|
||
|
while findingZone do
|
||
|
cache.ped = PlayerPedId()
|
||
|
local coords = GetEntityCoords(cache.ped)
|
||
|
local x = coords.x
|
||
|
local y = coords.y
|
||
|
local z = coords.z
|
||
|
local heading = GetEntityHeading(cache.ped)
|
||
|
DrawMarker(43, x, y, z + zoff, 0.0, 0.0, 0.0, 0.0, 180.0, -heading, length, width, height, 255, 0, 0, 50, false, false, 2, nil, nil, false)
|
||
|
if IsDisabledControlJustPressed(0, 38) then -- E
|
||
|
findingZone = false
|
||
|
setHide(false)
|
||
|
local newData = {
|
||
|
x = x,
|
||
|
y = y,
|
||
|
z = z,
|
||
|
h = heading,
|
||
|
}
|
||
|
promise:resolve(newData)
|
||
|
end
|
||
|
if IsDisabledControlJustPressed(0, 104) then -- H
|
||
|
findingZone = false
|
||
|
setHide(false)
|
||
|
promise:resolve(false)
|
||
|
end
|
||
|
Wait(0)
|
||
|
DisableControlAction(0, 199, true) -- P
|
||
|
DisableControlAction(0, 200, true) -- ESC
|
||
|
DisableControlAction(0, 104, true) -- H
|
||
|
end
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
RegisterNUICallback("getBlipBooleans", function (_, cb)
|
||
|
cb({
|
||
|
showBlipsForSale = showBlipsForSale,
|
||
|
showBlipsOwned = showBlipsOwned,
|
||
|
})
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("showBlipsForSale", function (bool, cb)
|
||
|
if bool then
|
||
|
showBlipsForSale = true
|
||
|
CreateBlipsOnMap("forSale")
|
||
|
else
|
||
|
showBlipsForSale = false
|
||
|
RemoveBlipsOnMap("forSale")
|
||
|
end
|
||
|
cb(1)
|
||
|
end)
|
||
|
|
||
|
RegisterNUICallback("showBlipsOwned", function (bool, cb)
|
||
|
if bool then
|
||
|
showBlipsOwned = true
|
||
|
CreateBlipsOnMap("owned")
|
||
|
else
|
||
|
showBlipsOwned = false
|
||
|
RemoveBlipsOnMap("owned")
|
||
|
end
|
||
|
cb(1)
|
||
|
end)
|
||
|
|
||
|
function CreateBlipsOnMap(type)
|
||
|
if type ~= "forSale" and type ~= "owned" then return end
|
||
|
local blipsTable = type == "forSale" and blipsForSale or blipsOwned
|
||
|
local nameType = type == "forSale" and "Property For Sale" or "Owned Property"
|
||
|
|
||
|
RemoveBlipsOnMap(type)
|
||
|
for k, data in pairs(PropertiesTable) do
|
||
|
if not data.apartment then
|
||
|
local isForSale = data.for_sale
|
||
|
local owner = data.owner
|
||
|
|
||
|
local coords = data.door_data
|
||
|
local blipName = '('..nameType..')' .. ' ' .. data.street .. ' ' .. data.property_id
|
||
|
if type == "forSale" and isForSale then
|
||
|
local blip = CreateBlip(coords, blipName)
|
||
|
blipsTable[#blipsTable + 1] = blip
|
||
|
elseif type == "owned" and (owner and not isForSale) then
|
||
|
local blip = CreateBlip(coords, blipName, false, 0)
|
||
|
blipsTable[#blipsTable + 1] = blip
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function CreateBlip(coords, blipName, sale, price)
|
||
|
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
|
||
|
SetBlipSprite(blip, 375)
|
||
|
SetBlipDisplay(blip, 4)
|
||
|
SetBlipScale(blip, 0.7)
|
||
|
SetBlipColour(blip, 2)
|
||
|
SetBlipAsShortRange(blip, true)
|
||
|
BeginTextCommandSetBlipName("STRING")
|
||
|
AddTextComponentString(blipName)
|
||
|
EndTextCommandSetBlipName(blip)
|
||
|
return blip
|
||
|
end
|
||
|
|
||
|
function RemoveBlipsOnMap(type)
|
||
|
if type == "forSale" then
|
||
|
for k, v in pairs(blipsForSale) do
|
||
|
RemoveBlip(v)
|
||
|
end
|
||
|
elseif type == "owned" then
|
||
|
for k, v in pairs(blipsOwned) do
|
||
|
RemoveBlip(v)
|
||
|
end
|
||
|
end
|
||
|
end
|