RX Scripts Logo
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