Housing
Configurables
All config & open sourced files included within this script.
Config Files
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config = {}
Config.Locale = 'en'
Config.DiscordWebhook = ''
Config.SaveInterval = 10 -- In Minutes
Config.DefaultRoutingBucket = 0
Config.UseMoney = 'bank' -- Money account used for payments
Config.PostMessageCooldown = 300 -- In Seconds, cooldown on sending post messages to a house
Config.MaxHouses = 5 -- Amount of houses a player can own
Config.SellReturn = 0.5 -- Percentage of the house price you get back when selling (0 - 1)
Config.LaptopProp = 'prop_laptop_01a' -- Prop used for the laptop
Config.UseLaptop = true -- Set to false if you dont want to use/spawn the laptop for the properties
Config.UseStash = true -- Set to false if you dont want to make use of the stash & upgrading the stash
Config.UseStashUpgrade = true -- Set to false if you want to disable the stash upgrades (for if ur using an inventory that doesnt offer this feature)
Config.UseWardrobe = true -- Set to false if you dont want to make use of the wardrobe
Config.AllowedToCreate = {
jobs = {
-- 'real_estate_agent',
},
groups = {
'admin',
'superadmin',
}
}
Config.Commands = {
create = 'housing:create',
delete = 'housing:delete',
enterfix = 'housing:enterfix', -- Used to tp back into the property if fallen through the map
}
Config.Ringing = {
refreshCooldown = 3000, -- In MS
canOpenStash = true, -- Can the player open the stash whilst being let in by ringing the doorbell?
canOpenWardrobe = true, -- Can the player open the wardrobe whilst being let in by ringing the doorbell?
}
Config.Keyholders = {
maxKeyholders = 5, -- false to make unlimited
canOpenStash = true, -- Can the player open the stash as a keyholder?
canOpenWardrobe = true, -- Can the player open the wardrobe as a keyholder?
}
Config.BreakIn = {
enabled = true,
canOpenStash = true,
canOpenWardrobe = true,
minimumCops = 0,
copsJob = 'police',
requiredItem = 'lockpick',
}
Config.Raid = {
enabled = true,
canOpenStash = true,
canOpenWardrobe = true,
requiredItem = 'phone',
allowedJobs = { -- Minimum grade required
{ job = "police", grade = 0 },
}
}
Config.Blips = {
ownedPropertyOwner = { -- When you have the key to the property
enabled = true,
color = 26,
sprite = 40,
scale = 0.8,
display = 4,
},
ownedPropertyStranger = { -- When you don't own the property
enabled = true,
color = 62,
sprite = 40,
scale = 0.8,
display = 4,
},
unownedProperty = { -- When the property is unowned
enabled = true,
color = 0,
sprite = 40,
scale = 0.8,
display = 4,
},
}
Config.StashGrades = {
{ -- DEFAULT GRADE
price = 0,
weight = 150000,
slots = 10,
},
{
price = 25000,
weight = 300000,
slots = 20,
},
{
price = 50000,
weight = 500000,
slots = 30,
}
}
Config.ShellsZ = -50 -- Z axis for shells
--[[
ONLY CHANGE THIS PART IF YOU HAVE RENAMED SCRIPTS SUCH AS FRAMEWORK, TARGET, INVENTORY ETC
RENAME THE SCRIPT NAME TO THE NEW NAME
--]]
---@type table Only change these if you have changed the name of a resource
Resources = {
ESX = { name = 'es_extended', export = 'getSharedObject' }, -- Puts the export in the ESX variable
QB = { name = 'qb-core', export = 'GetCoreObject' },
OXInv = 'ox_inventory', -- Puts all exports in the OXInv variable
QBInv = 'qb-inventory',
QSInv = 'qs-inventory',
PSInv = 'ps-inventory',
JPRInv = 'jpr-inventory',
CODEMInv = 'codem-inventory',
FMAPP = 'fivem-appearance',
ILA = { name = 'illenium-appearance', export = false }, -- Sets ILA variable to 'true' if started (used for no exports, but events)
OKOKG = { name = 'okokGarage', export = false },
QBClothing = { name = 'qb-clothing', export = false },
ESXSKIN = { name = 'esx_skin', export = false },
CRM = { name = 'crm-appearance', export = false },
JGGARAGE = { name = 'jg-advancedgarages', export = false },
CODEMG = { name = 'mGarage', export = false },
CDGARAGE = { name = 'cd_garage', export = false },
RXGARAGE = 'RxGarages',
}
IgnoreScriptFoundLogs = false
Opensource Files
All script-related open source code is contained within these files. Third-party components, including frameworks, inventory systems, and other external code, are separately maintained & open sourced in our fmLib repository.
--[[
BY RX Scripts © rxscripts.xyz
--]]
local function isNewQBInv()
local version = GetResourceMetadata('qb-inventory', 'version', 0)
if not version then return false end
local vNums = {}
for num in version:gmatch("(%d+)") do
vNums[#vNums + 1] = tonumber(num)
end
return vNums and vNums[1] >= 2
end
local function isNewPSInv()
local version = GetResourceMetadata('ps-inventory', 'version', 0)
if not version then return false end
local vNums = {}
for num in version:gmatch("(%d+)") do
vNums[#vNums + 1] = tonumber(num)
end
return vNums and vNums[1] >= 2
end
function OpenStash(stashId, owner, weight, slots)
if OXInv then
OXInv:openInventory('stash', { id = stashId, owner = owner })
elseif QBInv or QSInv or PSInv or CODEMInv then
if (QBInv and isNewQBInv()) or (PSInv and isNewPSInv()) then
TriggerServerEvent('housing:openStash', stashId, owner, weight, slots)
else
TriggerServerEvent('inventory:server:OpenInventory', 'stash', stashId, {
maxweight = weight,
slots = slots,
})
TriggerEvent('inventory:client:SetCurrentStash', stashId)
end
elseif JPRInv then
TriggerServerEvent('housing:openStash', stashId, owner, weight, slots)
else
Error("No inventory found for opening stash (client/opensource.lua:OpenStash)")
end
end
function StoreVehicleInGarage(garageId)
if RXGARAGE then
RXGARAGE:ParkVehicle("House Garage ("..tostring(garageId)..")", 'garage', 'car')
elseif OKOKG then
TriggerEvent("okokGarage:StoreVehiclePrivate")
elseif JGGARAGE then
TriggerEvent("jg-advancedgarages:client:store-vehicle", "House: "..tostring(garageId), "car")
elseif CODEMG then
TriggerEvent("codem-garage:storeVehicle", garageId)
elseif CDGARAGE then
TriggerEvent('cd_garage:StoreVehicle_Main', 1, false, false)
else
Error("No garage resource found (client/opensource.lua:StoreVehicleInGarage)")
end
end
function OpenGarage(garageId, coords)
if RXGARAGE then
RXGARAGE:OpenGarage("House Garage ("..tostring(garageId)..")", 'garage', 'car', coords)
elseif OKOKG then
TriggerEvent("okokGarage:OpenPrivateGarageMenu", vector3(coords.x, coords.y, coords.z), coords.w)
elseif JGGARAGE then
TriggerEvent("jg-advancedgarages:client:open-garage", "House: "..tostring(garageId), "car", coords)
elseif CODEMG then
TriggerEvent("codem-garage:openHouseGarage", garageId)
elseif CDGARAGE then
-- Choose either 'quick' or 'inside' in the 1st argument.
-- Replace nil with '10cargarage_shell' or '40cargarage_shell' in the 2nd argument.
TriggerEvent('cd_garage:PropertyGarage', 'quick', nil)
else
Error("No garage resource found (client/opensource.lua:OpenGarage)")
end
end
function ShowMarker(type, coords)
if type == 'laptop' or type == 'door' or type == 'stash' or type == 'clothing' then
DrawMarker(2, coords, 0, 0, 0, 0, 180.0, 0, 0.3, 0.3, 0.3, 204, 0, 102, 100, false, false, 2, true, false, false, false)
elseif type == 'entranceForSale' then
DrawMarker(29, coords, 0, 0, 0, 0, 180.0, 0, 0.5, 0.5, 0.5, 255, 204, 0, 100, false, false, 2, true, false, false, false)
elseif type == 'entranceHasKey' or type == 'entranceNoKey' then
local rgb = type == 'entranceHasKey' and { 4, 107, 200 } or { 217, 217, 217 }
DrawMarker(1, coords, 0, 0, 0, 0, 0, 0, 2.0, 2.0, 0.5, rgb[1], rgb[2], rgb[3], 100, false, false, 2, false, false, false, false)
elseif type == 'storeVehicle' then
DrawMarker(1, coords, 0, 0, 0, 0, 0, 0, 3.0, 3.0, 0.5, 4, 107, 200, 100, false, false, 2, false, false, false, false)
elseif type == 'takeVehicle' then
DrawMarker(36, coords, 0, 0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 4, 107, 200, 100, false, false, 2, true, false, false, false)
end
end
---@param propertyId string The property ID (u can use this to make a unique identifier if needed)
function OpenWardrobe(propertyId)
if FMAPP then
FMAPP:openWardrobe()
elseif ILA then
TriggerEvent("illenium-appearance:client:openOutfitMenu")
elseif QBClothing then
TriggerEvent('qb-clothing:client:openMenu')
elseif ESXSKIN then
TriggerEvent('esx_skin:openSaveableMenu')
elseif CRM then
TriggerEvent('crm-appearance:show-outfits')
else
Error("No wardrobe resource found (client/opensource.lua:OpenWardrobe)")
end
end
function BreakInMinigame()
TaskStartScenarioInPlace(PlayerPedId(), "WORLD_HUMAN_STAND_MOBILE", 0, true)
local result = lib.skillCheck({'easy', 'easy', 'easy'}, {'w', 'a', 's', 'd'})
ClearPedTasks(PlayerPedId())
return result
end
function RaidMinigame()
TaskStartScenarioInPlace(PlayerPedId(), "WORLD_HUMAN_STAND_MOBILE", 0, true)
local result = lib.skillCheck({'easy', 'easy', 'easy'}, {'w', 'a', 's', 'd'})
ClearPedTasks(PlayerPedId())
return result
end
function Notify(msg, type)
if ESX then
ESX.ShowNotification(msg, type)
elseif QB then
if type == 'info' then type = nil end
QB.Functions.Notify(msg, type)
end
end
function GetPlayerData()
if ESX then
return ESX.GetPlayerData()
elseif QB then
return QB.Functions.GetPlayerData()
end
end
function IsPlayerLoaded()
if ESX then
return GetPlayerData() and GetPlayerData().identifier
elseif QB then
return GetPlayerData() and GetPlayerData().citizenid
end
end
function GetIdentifier()
if ESX then
return GetPlayerData().identifier
elseif QB then
return GetPlayerData().citizenid
end
end
function GetJob()
if ESX then
return ESX.GetPlayerData().job
elseif QB then
return QB.Functions.GetPlayerData().job
end
end
function GetJobGrade()
local job = GetJob()
if ESX then
return job.grade
elseif QB then
return job.grade.level
end
end
function ShowHelpNotification(msg, thisFrame, beep, duration)
AddTextEntry('helpNotification', msg)
if thisFrame then
DisplayHelpTextThisFrame('helpNotification', false)
else
if beep == nil then
beep = true
end
BeginTextCommandDisplayHelp('helpNotification')
EndTextCommandDisplayHelp(0, false, beep, duration or -1)
end
end
--[[
BY RX Scripts © rxscripts.xyz
--]]
function RegisterStash(stash)
if OXInv then
OXInv:RegisterStash(stash.id, stash.label, stash.slots, stash.weight, stash.owner, false)
elseif not QBInv and not QSInv and not PSInv and not CODEMInv then
Error("No inventory found for registering stash (server/opensource.lua:5)")
end
end
function UpgradeStash(stashId, newWeight, newSlots)
if OXInv then
OXInv:SetMaxWeight(stashId, newWeight)
OXInv:SetSlotCount(stashId, newSlots)
elseif not QBInv and not QSInv and not PSInv and not CODEMInv then
Error("No inventory found for upgrading stash (server/opensource.lua:11)")
end
end
function Notify(src, msg, type)
if ESX then
TriggerClientEvent('esx:showNotification', src, msg, type)
elseif QB then
if type == 'info' then type = nil end
TriggerClientEvent('QBCore:Notify', src, msg, type)
end
end
function GetPlayerBySrc(src)
if ESX then
return ESX.GetPlayerFromId(src)
elseif QB then
return QB.Functions.GetPlayer(src)
end
end
function HasGroup(src, group)
if ESX then
return ESX.GetPlayerFromId(src).getGroup() == group
elseif QB then
return QB.Functions.HasPermission(src, group) or IsPlayerAceAllowed(src, 'command')
end
end
function GetJob(src)
if ESX then
return ESX.GetPlayerFromId(src).job
elseif QB then
return QB.Functions.GetPlayer(src).PlayerData.job
end
end
function GetJobGrade(src)
local job = GetJob(src)
if ESX then
return job.grade
elseif QB then
return job.grade.level
end
end
function HasItem(src, item)
if ESX then
return ESX.GetPlayerFromId(src).getInventoryItem(item).count > 0
elseif QB then
item = QB.Functions.GetPlayer(src).Functions.GetItemByName(item)
if not item then return false end
return item.amount > 0
end
end
function GetItemLabel(src, item)
if ESX then
return ESX.GetPlayerFromId(src).getInventoryItem(item).label
elseif QB then
return QB.Shared.Items[item].label
end
end
function GetPlayerByIdentifier(identifier)
if ESX then
return ESX.GetPlayerFromIdentifier(identifier)
elseif QB then
return QB.Functions.GetPlayerByCitizenId(identifier)
end
end
function GetIdentifier(src)
if ESX then
return ESX.GetPlayerFromId(src).identifier
elseif QB then
return QB.Functions.GetPlayer(src).PlayerData.citizenid
end
end
--[[
CURRENT FUNCTION = ESX 1.9+
IF USING ESX <1.8, COMMENT OUT THE CURRENT FUNCTION AND UNCOMMENT THE FUNCTION BELOW
--]]
function GetJobOnlineSources(job)
local players = {}
if ESX then
for _, player in pairs(ESX.GetExtendedPlayers("job", job)) do
players[#players+1] = player.source
end
elseif QB then
for _, src in pairs(QB.Functions.GetPlayers()) do
if GetJob(src).name == job then
players[#players+1] = src
end
end
end
return players
end
-- function GetJobOnlineSources(job)
-- local players = {}
-- if ESX then
-- local playerSources = GetPlayers()
-- for _, src in pairs(playerSources) do
-- if GetJob(src).name == job then
-- players[#players+1] = src
-- end
-- end
-- elseif QB then
-- for _, src in pairs(QB.Functions.GetPlayers()) do
-- if GetJob(src).name == job then
-- players[#players+1] = src
-- end
-- end
-- end
-- return players
-- end
--[[
--]]
function GetMoney(src, type)
if ESX then
return ESX.GetPlayerFromId(src).getAccount(type).money
elseif QB then
return QB.Functions.GetPlayer(src).PlayerData.money[type]
end
end
function RemoveMoney(src, type, amount)
if ESX then
ESX.GetPlayerFromId(src).removeAccountMoney(type, amount)
elseif QB then
QB.Functions.GetPlayer(src).Functions.RemoveMoney(type, amount)
end
end
function AddMoney(src, type, amount)
if ESX then
ESX.GetPlayerFromId(src).addAccountMoney(type, amount)
elseif QB then
QB.Functions.GetPlayer(src).Functions.AddMoney(type, amount)
end
end
function GetPlayerName(src)
if ESX then
return ESX.GetPlayerFromId(src).name
elseif QB then
return QB.Functions.GetPlayer(src).PlayerData.charinfo.firstname .. " " .. QB.Functions.GetPlayer(src).PlayerData.charinfo.lastname
end
end
function IsAdmin(src)
if ESX then
return ESX.GetPlayerFromId(src).getGroup() == "admin"
elseif QB then
return QB.Functions.HasPermission(src, "admin") or QB.Functions.HasPermission(src, "god") or IsPlayerAceAllowed(src, 'command')
end
end
function GetSrcByPlayer(player)
if ESX then
return player.source
elseif QB then
return player.PlayerData.source
end
end
RegisterNetEvent('housing:openStash', function(stashId, owner, weight, slots)
local src = source
if QBInv then
QBInv:OpenInventory(src, stashId, {
maxweight = weight,
slots = slots,
})
elseif PSInv then
PSInv:OpenInventory(src, stashId, {
maxweight = weight,
slots = slots,
})
elseif JPRInv then
JPRInv:OpenInventory(src, stashId, {
label = 'House Stash',
maxweight = weight,
slots = slots
})
end
end)
RegisterNetEvent('housing:onHouseEntered', function(src, property, isBreakIn, isRaid)
-- You can utilize this event for any custom needs
end)
RegisterNetEvent('housing:onHouseExited', function(src, propertyId)
-- You can utilize this event for any custom needs
end)
RegisterNetEvent('housing:onHouseBought', function(playerId, property)
-- This event will be called whenever a player bought a house
end)