# Accessible files

<details>

<summary>config.lua</summary>

```lua
----------------------------------------------------------------------------------------------
-------------------------------------| BRUTAL HOUSING :) |------------------------------------
----------------------------------------------------------------------------------------------

--[[
Hi, thank you for buying our script, We are very grateful!

For help join our Discord server:     https://discord.gg/85u2u5c8q9
More informations about the script:   https://docs.brutalscripts.com
--]]

Config = {
    Core = 'ESX',  -- 'ESX' / 'QBCORE' | Other core setting on the 'core' folder.
    VoiceSytem = 'pma-voice', -- "pma-voice" / "mumble" / "SaltyChat"
    Inventory = 'ox_inventory', -- 'ox_inventory' / 'qb_inventory_old'/ 'qb_inventory_new' / 'quasar_inventory' / 'chezza_inventory' / 'codem_inventory' / 'core_inventory' // Custom can be add in the cl_utils.lua!!!
    Wardrobe = 'default', -- 'default' / 'ak47_clothing' / 'codem_apperance' / 'fivem_appearance' / 'illenium_appearance' / 'qb_clothing' / 'raid_clothes' / 'rcore_clothes' / 'rcore_clothing' / 'sleek_clothestore' / 'tgiann_clothing' // Custom can be add in the cl_utils.lua!!!
    TextUI = 'brutal_textui', -- false / 'brutal_textui' / 'ox_lib' / 'okokTextUI' / 'ESXTextUI' / 'QBDrawText' // Custom can be add in the cl_utils.lua!!!
    BrutalKeys = true, -- Buy here: https://store.brutalscripts.com
    BrutalPoliceJob = true, -- Buy here: https://store.brutalscripts.com | Better connection
    BrutalNotify = true, -- Buy here: (4€+VAT) https://store.brutalscripts.com | Or set up your own notify >> cl_utils.lua
    
    SteamName = false, -- true = Steam name | false = character name
    MenuBackgroundBlur = true, -- Menu background blur | true / false
    AdminGroups = {'superadmin', 'admin', 'mod', 'god'},
    HousingDataPrint = true, -- Server side print, like that: Brutal Housing: Houses: 1  Apartments: 97  Garages: 9
    
    DataStorage = {
        --[[
        optimized = Saves the data when the script is restarted, the server is shut down or restarted, or during a scheduled server restart.
            events: "txAdmin:events:serverShuttingDown" & "txAdmin:events:scheduledRestart" or fixed restart times.
        resource_heavy = all data will be saved immediately, this is very stressful for the server so we don't recommend using this, but the choice is up to you.
        ]]--

        Type = "resource_heavy", -- "optimized" / "resource_heavy"
        Restarts = {}, -- example: "11:59" | Save the data 1 minute before restart. Save data at 15:59 instead of 16:00
    },

    Blips = {
        available = true,
            availableHouse = {label = "Available House", size = 0.7, sprite = 40, color = 2},
            availableGarage = {label = "Available Garage", size = 0.7, sprite = 357, color = 2},
        owned = true,
            myHouse = {label = "My House", size = 0.7, sprite = 40, color = 53},
            myGarage = {label = "My Garage", size = 0.7, sprite = 357, color = 53},
            hasKeyHouse = {label = "House", size = 0.7, sprite = 40, color = 53},
            hasKeyGarage = {label = "House", size = 0.7, sprite = 40, color = 53},
            ownedHouse = {label = "House", size = 0.7, sprite = 40, color = 1},
            ownedGarage = {label = "Garage", size = 0.7, sprite = 357, color = 1},
        police = true,
            burglarAlarm = {label = "Burglar alarm", size = 1.0, sprite = 161, color = 1},
    },

    MaxProperties = 12, -- Maximum number of properties a player can own
    MaxObject = 50, -- Maximum placing object, 50-50 by default, outside and inside separately
    MaxBargainPercent = 5,  -- Maximum bargain rate in percentage | Bargain rate i random between 0 and this value
    InstantSalePurchasePrice = 0.9, -- 100 000$ * 0.9 = 90 000$ | The player can immediately sell his property for this much compared to the base price.
    DelayedSalePurchasePrice = 1.2, -- 100 000$ * 1.2 = 120 000$ | This is the maximum price a player can sell the house he has bought.
    DeleteInactiveProperty = {use = true, days = 45}, -- -- If use is true, the property will be deleted if the player does not use it for X days. | Only the owned ones.
    CopJobs = {"police", "sheriff"}, -- Cop jobs
    GarageUpgrade = {
        Repair = {use = true, time = 48, price = 25000}, -- The car stored in the garage will be repaired after 48hours.
        Clean = {use = true, time = 24, price = 5000} -- The car stored in the garage will be cleaned after 24hours.
    },

    ForeclosureDebtThreshold = 1000, -- If the owner's debt exceeds $1000, the property will go into foreclosure.
    Utilities = {
        BillingCycle = 7, -- The default billing cycle for utilities is every 7 days.

        RentalPrice = 0.004,  -- 0.4% rental fee based on property price | 100,000$ * 0.004 = 400$
        ElectricityPrice = 0.0005,
        GasPrice = 0.00025,
        WaterPrice = 0.0001,
        WifiUnlockPrice = 5000, -- One-time fee
        WifiPrice = 70, -- Fix price/month
    },

    NewKeyPrice = 25,
    LockReplacementPrice = 100,
    CCTVStationRepairPrice = 250,

    Security = {
        DatabaseDesroyEnabled = true, -- true / false
        Objects = {
            cameras = {"prop_cs_cctv", "prop_cctv_cam_01b"},
            databases = {"hei_prop_heist_pc_01", "prop_dyn_pc", "prop_dyn_pc_02", "prop_pc_01a", "prop_pc_02a"}
        },
        
        Levels = {
            [0] = {
                alertToPolice = false,
                maxAttempts = 6,
                showIntruderName = false
            }, 
            [1] = {
                price = 4750,

                alertToPolice = true,
                maxAttempts = 4,
                showIntruderName = false
            }, 
            [2] = {
                price = 9500,

                alertToPolice = true,
                maxAttempts = 2,
                showIntruderName = true
            }, 
            [3] = {
                price = 25000,

                alertToPolice = true,
                maxAttempts = 0, -- if it is 0, there is no chance to break into the house
                showIntruderName = true
            },
        },
    },

    BreakIn = {
        use = true,
        minimumCopsCount = 0,
        requiredItem = 'lockpick',
        removeItem = true
    },

    Raid = {
        use = true,
        allowedJobs = {
            { job = "police", minGrade = 0 },
        }
    },

    RealEstateagents = {
        ProfitRatioPercent = 6, -- Profit share of the real estate agency based on the purchase price | 6 = 6% of the property price
        Jobs = {
            ["dynasty"] = { -- job name
                [0] = {
                    label = 'Trainee', -- Rank name
                    permissions = {    -- Permissions
                        canCreate = true, -- Property Creation
                        canManageProperties = false, -- Created property management
                        balanceMenu = false -- Balance Menu
                    }
                },
                [1] = {
                    label = 'Agent',
                    permissions = {
                        canCreate = true,
                        canManageProperties = true,
                        balanceMenu = false
                    }
                },
                [2] = {
                    label = 'Senior Agent',
                    permissions = {
                        canCreate = true,
                        canManageProperties = true,
                        balanceMenu = true
                    }               
                }
            },
        
            -- you can add more jobs too.
        }
    },

    Commands = {
        MyProperties = {
            Command = 'myproperties', 
            Suggestion = 'To manage your propertys',
            Control = '',  -- Controls list:  https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/
        },

        ServerDestroy = {
            Command = 'serverdestroy',
            Suggestion = 'To destroy the camera server',
            requiredItem = 'laptop'
        },

        GetHousingVehicleBack = {
            Command = 'gethousingvehicleback', --  /gethousingvehicleback all | /gethousingvehicleback DHR 432
            Suggestion = 'To get back your vehicle(s)',
        },

        -- Admin / Real Estate --

        StaffMode = {
            Command = 'hstaff', 
            Suggestion = 'To switch Housing Staff mode',
        },

        Properties = {
            Command = 'properties', 
            Suggestion = 'To open the propertys menu',
        },

        CreateHouse = {
            Command = 'createhouse', 
            Suggestion = 'To create a house',
        },

        CreateGarage = {
            Command = 'creategarage', 
            Suggestion = 'To create a garage',
        },
    },

    -----------------------------------------------------------
    -----------------------| TRANSLATE |-----------------------
    -----------------------------------------------------------

    NUILanguage = "en", -- "en", "es", "fr", "de", "pt", "it", "pl", "nl", "ru", "tr", "hu", "ro", "cs", "sv", "ar"

    MoneyForm = '$', -- Money form

    Locales = {
        Stash = "Stash",
        None = "None",
        AdminRemoved = "Admin removed",

        ShellPlacement = "Shell Placement",
        DoorLocation = "Door Location",
        VehiclePlacement = "Vehicle Placement",
        FurniturePlacement = "Furniture Placement",

        NewCoords = "Set the new coords",
        MovingFreecam = "Moving Freecam",
        GoBack = "Go Back",
        ObjectMovement = "Object movement",
        ObjectVertical = "Object Vertical Movement",
        ObjectRotate = "Object Rotate",
        FinishEditing = "Finish Editing",
        TranslateMode = "Translate Mode",
        CameraFix = "Camera Fix",
        DoneEditing = "Done Editing",

        BreakIn = "A burglar broke into the house! Go to the designated place!",
        
        Messages = {
            Rent = {title = "Rent", message = "You have started renting the property."},
            StopRent = {title = "Rental stopped", message = "The rental of the property has been stopped."},
            Purchase = {title = "Purchase", message = "You have purchased the property."},
            LevelUpgrade = {title = "Level Upgrade", message = "Success upgrade: Level"},
            BrakeIn = {title = "Break-in", message = "Someone has broken into the property:"},
            Raid = {title = "Raid", message = "Police raided the property."},
            WifiUnlock = {title = "Wifi", message = "The Wifi has been connected!"},
            CleaningUnlock = {title = "Cleaning", message = "Vehicle cleaning function now available"},
            RepairingUnlock = {title = "Repairing", message = "Vehicle repairing function now available"},
            DoorLockReplacement = {title = "Lock replacement", message = "You have successfully changed the lock on your property!"},
            Rename = {title = "Property renaming", message = "New name of the property:"},
            Unknown = "Unknown",
        },

        CCTV = "BACK: ~INPUT_CELLPHONE_CANCEL~\nUP/DOWN: ~INPUT_CELLPHONE_UP~ & ~INPUT_CELLPHONE_DOWN~\nLEFT/RIGHT: ~INPUT_CELLPHONE_LEFT~ & ~INPUT_CELLPHONE_RIGHT~",
        CCTVSetup = "BACK: ~INPUT_CELLPHONE_CANCEL~\nUP/DOWN: ~INPUT_CELLPHONE_UP~ & ~INPUT_CELLPHONE_DOWN~\nLEFT/RIGHT: ~INPUT_CELLPHONE_LEFT~ & ~INPUT_CELLPHONE_RIGHT~\nSETUP: ~INPUT_FRONTEND_RDOWN~",
    },

    Texts = {
        [1] = {'[E] - Storage', 38},
        [2] = {'[E] - Wardrobe', 38},
    },

    DoorTexts = {
        ["entry"] = {'E', 'Entry', 38},
        ["leave"] = {'E', 'Leave', 38},
        ["garage"] = {'X', 'Garage', 73},
        ["house"] = {'X', 'House', 73},
        ["open"] = {'G', 'Open the door', 47},
        ["close"] = {'G', 'Close the door', 47},
        ["purchase"] = {'E', 'Purchase menu', 38},
        ["knock"] = {'E', 'Knocking', 38},
        ["raid"] = {'G', 'Raid', 47},
        ["breakin"] = {'G', 'Break In', 47},
        ["inforeclosure"] = {'E', 'In foreclosure', 38}
    },
    
    -- Notify function EDITABLE >> cl_utils.lua
    Notify = { 
        [1] = {"Housing", "You can only enter with your own car!", 5000, "error"},
        [2] = {"Housing", "No more space in the garage!", 5000, "error"},
        [3] = {"Housing", "The door is closed!", 5000, "error"},
        [4] = {"Housing", "You already have a property near you, move away!", 5000, "error"},
        [5] = {"Housing", "The property name must be 3-16 characters long!", 5000, "error"},
        [6] = {"Housing", "The URL must start with 'http://' or 'https://'", 5000, "error"},
        [7] = {"Housing", "The price must be more than ZERO!", 5000, "error"},
        [8] = {"Housing", "You have entered an invalid or already used garage id!", 5000, "error"},
        [9] = {"Housing", "You have successfully created it!", 5000, "success"},
        [10] = {"Housing", "Invalid property ID!", 5000, "error"},
        [11] = {"Housing", "You don't have enough money!", 5000, "error"},
        [12] = {"Housing", "You can sell it for a maximum of 20% more than what you bought it for!", 5000, "error"},
        [13] = {"Housing", "You don't own it, so you can't sell it!", 5000, "error"},
        [14] = {"Housing", "You have successfully purchased!", 5000, "success"},
        [15] = {"Housing", "The house owner is currently unavailable. Please contact them by phone!", 5000, "error"},
        [16] = {"Housing", "You cannot park this vehicle in the garage!", 5000, "error"},
        [17] = {"Housing", "Successful payment!", 5000, "success"},
        [18] = {"Housing", "Successful upgrade!", 5000, "success"},
        [19] = {"Housing", "Someone knocked on the door!", 5000, "info"},
        [20] = {"Housing", "You knocked on the door!", 5000, "success"},
        [21] = {"Housing", "You have paid the outstanding debt on the property:", 5000, "error"},
        [22] = {"Housing", "You have successfully sold the property:", 5000, "success"},
        [23] = {"Housing", "The garage door cannot be more than 50 metres from the entrance to the house.", 5000, "error"},
        [24] = {"Housing", "Not enough money for the real estate agency!", 5000, "error"},
        [25] = {"Housing", "You do not have permission!", 5000, "error"},
        [26] = {"Housing", "You can only connect a house and a garage!", 5000, "error"},
        [27] = {"Housing", "The property is already connected!", 5000, "error"},
        [28] = {"Housing", "These two properties are not connected!", 5000, "error"},
        [29] = {"Housing", "Successful connection!", 5000, "success"},
        [30] = {"Housing", "You have successfully detached the garage!", 5000, "success"},
        [31] = {"Housing", "You've got it back:", 5000, "success"},
        [32] = {"Housing", "No vehicle to get back!", 5000, "error"},
        [33] = {"Housing", "There was a problem loading the IPL/Shell.", 5000, "error"},
        [34] = {"Housing", "You spammed the housing system, so you have been put on a 3-minute cooldown.", 5000, "error"},
        [35] = {"Housing", "You can now use the housing system again.", 5000, "success"},
        [36] = {"Housing", "Please avoid doing this again in the future.", 5000, "info"},
        [37] = {"Housing", "You cannot buy/rent more property! Maximum quantity:", 5000, "error"},
        [38] = {"Housing", "You have to wait 2 minutes because you've failed the minigame!", 5000, "error"},
        [39] = {"Housing", "You have successfully completed the minigame! The door is open!", 5000, "success"},
        [40] = {"Housing", "You failed to complete the minigame!", 5000, "error"},
        [41] = {"Housing", "You have successfully completed the minigame!", 5000, "success"},
        [42] = {"Housing", "This house has too good security, you can't break in!", 5000, "error"},
        [43] = {"Housing", "You have reached the maximum attempt!", 5000, "error"},
        [44] = {"Housing", "Not enough police in the city!", 5000, "error"},
        [45] = {"Housing", "You need a lockpick item!", 5000, "error"},
        [46] = {"Housing", "You need a laptop item!", 5000, "error"},
        [47] = {"Housing", "Invalid Player ID!", 5000, "error"},
        [48] = {"Housing", "Invalid Identifier!", 5000, "error"},
        [49] = {"Housing", "Successful modification!", 5000, "success"},
        [50] = {"Housing", "This address already exist!", 5000, "error"},
        [51] = {"Housing", "The two properties must be owned by the same person/job!", 5000, "error"},
        [52] = {"Housing", "The amount you offered is too low!", 5000, "error"},
        [53] = {"Housing", "The spawn coordinates of the vehicle must be within 15 meters of the garage door!", 5000, "error"},
        [54] = {"Housing", "You don't have property!", 5000, "error"},
        [55] = {"Housing", "Staff mode: ON", 5000, "success"},
        [56] = {"Housing", "Staff mode: OFF", 5000, "error"},
        [57] = {"Housing", "You have started to rent the property!", 5000, "success"},
        [58] = {"Housing", "You've put your property up for sale!", 5000, "success"},
        [59] = {"Housing", "You cancelled the sale!", 5000, "info"},
        [60] = {"Housing", "Invalid Price!", 5000, "error"},
        [61] = {"Housing", "You cannot buy your own property! You can cancel the sale in the Myproperties menu!", 5000, "error"},
        [62] = {"Housing", "You have stopped to rent the property!", 5000, "info"},
        [63] = {"Housing", "There is not that much money in the account!", 5000, "error"},
        [64] = {"Housing", "Successful deposit:", 5000, "success"},
        [65] = {"Housing", "Successful withdrawal:", 5000, "success"},
        [66] = {"Housing", "A burglar broke into the house! Go to the designated place!", 5000, "info"},
        [67] = {"Housing", "You have successfully deleted it!", 5000, "success"},
        [68] = {"Housing", "You cannot add a garage to an apartment!", 5000, "error"},
        [69] = {"Housing", "You cannot place objects here!", 5000, "error"},
        [70] = {"Housing", "You cannot create a house/garage near Apartment buildings!", 5000, "error"},
        [71] = {"Housing", "You have successfully renamed the property!", 5000, "success"},
        [72] = {"Housing", "You have successfully replaced the door lock!", 5000, "success"},
        [73] = {"Housing", "You have successfully bought a new key!", 5000, "success"},
        [74] = {"Housing", "Place %d car spawn coordinates inside the shell!", 5000, "info"},
        [75] = {"Housing", "You can't put a door lock that far away!", 5000, "error"},
        [76] = {"Housing", "You paid for furniture:", 5000, "info"},
        [77] = {"Housing", "You sold furniture for:", 5000, "info"},
        [78] = {"Housing", "You are too far from the object!", 5000, "error"},
        [79] = {"Housing", "You have successfully destroyed it, the owner has lost the camera data!", 5000, "error"},
        [80] = {"Housing", "You can't sit in a car!", 5000, "error"},
        [81] = {"Housing", "There is no database near you!", 5000, "error"},
        [82] = {"Housing", "This has already been destroyed!", 5000, "error"},
        [83] = {"Housing", "You have successfully repaired it!", 5000, "success"},
        [84] = {"Housing", "You cannot open the menu now!", 5000, "error"},
        [85] = {"Housing", "The property is in foreclosure! The owner must pay the bills before we can use it.", 5000, "error"},
        [86] = {"Housing", "This car is out of the garage!", 5000, "error"},
        [87] = {"Housing", "The maximum number of objects you can place:", 5000, "error"},
        [88] = {"Housing", "The garage must be empty if you want to sell the property!", 5000, "error"},
    },

    Webhooks = {
        Locale = {
            ['houseCreateTitle'] = "🆕 House created...",
            ['houseCreateSubtitle'] = "created a house.",
            ['garageCreateTitle'] = "🆕 Garage created...",
            ['garageCreateSubtitle'] = "created a garage.",
            ['deleteTitle'] = "❌ Deleted property...",
            ['deleteSubtitle'] = "deleted a property.",
            ['purchaseTitle'] = "💵 Purchased property...",
            ['purchaseSubtitle'] = "purchased a property.",
            ['rentTitle'] = "💵 Rented property...",
            ['rentSubtitle'] = "rented a property.",
            ['newOwnerTitle'] = "🔄 Change of owner...",
            ['newOwnerSubtitle'] = "changed the property owner.",

            ['Identifier'] = "Identifier",
            ['PropertyID'] = "Property ID",
            ['Type'] = "Type",
            ['Price'] = "Price",
            ['Rent'] = "Rent",
            ['Coords'] = "Coords",
            ['Address'] = "Address",
            ['Garage'] = "Garage",
            ['Reason'] = "Reason",
            ['PreviousOwner'] = "Previous Owner",
            ['NewOwner'] = "New Owner",
            ['Inactivity'] = "Since Config.DeleteInactiveProperty.use is true, this property is deleted due to inactivity.",


            ['Time'] = "Time ⏲️"
        },

        -- To change a webhook color you need to set the decimal value of a color, you can use this website to do that - https://www.mathsisfun.com/hexadecimal-decimal-colors.html
        Colors = {
            ['houseCreateTitle']   = 65280,
            ['garageCreateTitle']  = 255,
            ['deleteTitle']        = 16711680,
            ['purchaseTitle']      = 16776960,
            ['rentTitle']          = 65535,
            ['newOwnerTitle']      = 16711935,
        }
    },
}
```

</details>

<details>

<summary>client-utils.lua</summary>

```lua
ESX = Core
QBCore = Core

-- Buy here: (4€+VAT) https://store.brutalscripts.com
function notification(title, text, time, type)
    if Config.BrutalNotify then
        exports['brutal_notify']:SendAlert(title, text, time, type)
    else
        -- Put here your own notify and set the Config.BrutalNotify to false
        SetNotificationTextEntry("STRING")
        AddTextComponentString(text)
        DrawNotification(0,1)

        -- Default ESX Notify:
        --TriggerEvent('esx:showNotification', text)

        -- Default QB Notify:
        --TriggerEvent('QBCore:Notify', text, 'info', 5000)

        -- OKOK Notify:
        -- exports['okokNotify']:Alert(title, text, time, type, false)

    end
end

function TextUIFunction(type, text)
    if type == 'open' then
        if Config.TextUI:lower() == 'ox_lib' then
            lib.showTextUI(text)
        elseif Config.TextUI:lower() == 'okoktextui' then
            exports['okokTextUI']:Open(text, 'darkblue', 'right')
        elseif Config.TextUI:lower() == 'esxtextui' then
            ESX.TextUI(text)
        elseif Config.TextUI:lower() == 'qbdrawtext' then
            exports['qb-core']:DrawText(text,'left')
        elseif Config.TextUI:lower() == 'brutal_textui' then
            exports['brutal_textui']:Open(text, "blue")
        end
    elseif type == 'hide' then
        if Config.TextUI:lower() == 'ox_lib' then
            lib.hideTextUI()
        elseif Config.TextUI:lower() == 'okoktextui' then
            exports['okokTextUI']:Close()
        elseif Config.TextUI:lower() == 'esxtextui' then
            ESX.HideUI()
        elseif Config.TextUI:lower() == 'qbdrawtext' then
            exports['qb-core']:HideText()
        elseif Config.TextUI:lower() == 'brutal_textui' then
            exports['brutal_textui']:Close()
        end
    end
end

function AbleToOpenThePropertiesMenu()
    local able = true

    if Config.BrutalPoliceJob and GetResourceState("brutal_policejob") == "started" then
        if exports.brutal_policejob:IsHandcuffed() then
            able = false
        end
    end

    if Config['Core']:upper() == 'QBCORE' then
        if GetResourceState("qb-policejob") == "started" then
            if exports["qb-policejob"]:IsHandcuffed() then
                able = false
            end
        end
    end

    -- other blacklists can be added.

    return able
end

function OpenDressingMenu()
    if Config.Wardrobe == 'ak47_clothing' then
        exports['ak47_clothing']:openOutfit() -- if it doesn't work with this export use other event
        -- TriggerEvent('ak47_clothing:openOutfitMenu') -- Use this only if the first export doesn't work, depend of you'r version
    elseif Config.Wardrobe == 'codem_apperance' then 
        TriggerEvent('codem-apperance:OpenWardrobe')
    elseif Config.Wardrobe == 'fivem_appearance' then 
        exports['fivem-appearance']:openWardrobe()
    elseif Config.Wardrobe == 'illenium_appearance' then 
        TriggerEvent('illenium-appearance:client:openOutfitMenu')
    elseif Config.Wardrobe == 'qb_clothing' then 
        TriggerEvent('qb-clothing:client:openOutfitMenu')
    elseif Config.Wardrobe == 'raid_clothes' then 
        TriggerEvent('raid_clothes:openmenu')
    elseif Config.Wardrobe == 'rcore_clothes' then 
        TriggerEvent('rcore_clothes:openOutfits')
    elseif Config.Wardrobe == 'rcore_clothing' then 
        TriggerEvent('rcore_clothing:openChangingRoom')
    elseif Config.Wardrobe == 'sleek_clothestore' then 
        exports['sleek-clothestore']:OpenWardrobe()
    elseif Config.Wardrobe == 'tgiann_clothing' then 
        TriggerEvent('tgiann-clothing:openOutfitMenu')
    end
end

function setPlayerSkin(skinTable)
    if Config['Core']:upper() == 'ESX' then
        TriggerEvent('skinchanger:loadSkin', skinTable.skin)
    elseif Config['Core']:upper() == 'QBCORE' then
        TriggerEvent("qb-clothes:loadSkin", false, tonumber(skinTable.model), skinTable.skin)
        TriggerServerEvent("brutal_housing:server:qbcore-loadPlayerSkin", tonumber(skinTable.model), skinTable.skin)
    end
end

function MiniGames(type, propertyID)
    if type == "raid" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:Circle(function(success)
                TriggerEvent('brutal_housing:client:raidMinigame', propertyID, success)
            end, 3, 10)
        else
            TriggerEvent('brutal_housing:client:raidMinigame', propertyID, true)
        end
    elseif type == "server-destroy" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:Scrambler(function(success)
                TriggerEvent('brutal_housing:client:serverdestroy', propertyID, success)
            end, "alphanumeric", 60, 2) 
        else
            TriggerEvent('brutal_housing:client:serverdestroy', propertyID, true)
        end  
    elseif type == "house-break-in-level_0" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:Scrambler(function(success)
                TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, success)
            end, "alphanumeric", 60, 2) 
        else
            TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, true)
        end
    elseif type == "house-break-in-level_1" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:VarHack(function(success)
                TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, success)
            end, 10, 30) 
        else
            TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, true)
        end
    elseif type == "house-break-in-level_2" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:Thermite(function(success)
                TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, success)
            end, 30, 6, 10)
        else
            TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, true)
        end  
    elseif type == "house-break-in-level_3" then
        if GetResourceState("ps-ui") == "started" then
            exports['ps-ui']:Thermite(function(success)
                TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, success)
            end, 30, 6, 10)
        else
            TriggerEvent('brutal_housing:client:breakInMinigame', propertyID, true)
        end
    end
end

function PoliceBurglarNotify(x,y,z, address)
    if Config.BrutalPoliceJob and GetResourceState("brutal_policejob") == "started" then
        TriggerServerEvent('brutal_policejob:server:citizencall', 'create', Config.Locales.BreakIn, {x,y,z}, address)
    else
        SendNotify(66)
    end
end

function InventoryOpenFunction(propertyID, objectID)
    if Config.Inventory:lower() == 'ox_inventory' then
        if exports.ox_inventory:openInventory('stash', { id = "stash_"..propertyID.."_"..objectID}) == false then
            TriggerServerEvent('brutal_housing:server:loadStash', propertyID, objectID)
            exports.ox_inventory:openInventory('stash', { id = "stash_"..propertyID.."_"..objectID})
        end
    elseif Config.Inventory:lower() == 'qb_inventory_old' then
        TriggerServerEvent("inventory:server:OpenInventory", "stash", "stash_"..propertyID.."_"..objectID, {label = Config.Locales.Stash, maxweight = 1000000, slots = 100})
        TriggerEvent("inventory:client:SetCurrentStash", "stash_"..propertyID.."_"..objectID)
    elseif Config.Inventory:lower() == 'qb_inventory_new' then
        TriggerServerEvent("brutal_housing:qb-inventory:server:OpenInventory", "stash_"..propertyID.."_"..objectID, {label = Config.Locales.Stash, maxweight = 1000000, slots = 100})
    elseif Config.Inventory:lower() == 'quasar_inventory' then
        TriggerServerEvent("inventory:server:OpenInventory", "stash", "stash_"..propertyID.."_"..objectID, { label = Config.Locales.Stash, maxweight = 1000000, slots = 100 })
        TriggerEvent("inventory:client:SetCurrentStash", "stash_"..propertyID.."_"..objectID)
    elseif Config.Inventory:lower() == 'codem_inventory' then
        TriggerServerEvent("inventory:server:OpenInventory", "stash", "stash_"..propertyID.."_"..objectID, { label = Config.Locales.Stash, maxweight = 1000000, slots = 100 })
        TriggerEvent("inventory:client:SetCurrentStash", "stash_"..propertyID.."_"..objectID)
    elseif Config.Inventory:lower() == 'chezza_inventory' then
        TriggerEvent('inventory:openStorage', Config.Locales.Stash, "stash_"..propertyID.."_"..objectID, 1000, 1000)
    elseif Config.Inventory:lower() == 'core_inventory' then
        TriggerServerEvent('core_inventory:server:openInventory', "stash_"..propertyID.."_"..objectID, "big_storage")
    elseif Config.Inventory:lower() == 'origen_inventory' then
        exports.origen_inventory:openInventory("stash", "stash_"..propertyID.."_"..objectID, {label = Config.Locales.Stash, maxweight = 1000000, slots = 100})
    elseif Config.Inventory:lower() == 'ps-inventory' then
        if GetResourceState('ps-inventory') == "started" then
            TriggerServerEvent("ps-inventory:server:OpenInventory", "stash_"..propertyID.."_"..objectID, {label = Config.Locales.Stash, maxweight = 1000000, slots = 100})
            TriggerEvent("ps-inventory:client:SetCurrentStash", "stash_"..propertyID.."_"..objectID)
        else
            TriggerServerEvent("inventory:server:OpenInventory", "stash", "stash_"..propertyID.."_"..objectID, {label = Config.Locales.Stash, maxweight = 1000000, slots = 100})
            TriggerEvent("inventory:client:SetCurrentStash", "stash_"..propertyID.."_"..objectID)
        end
    end
end

RegisterNetEvent('brutal_housing:client:utils:CreateVehicle')
AddEventHandler('brutal_housing:client:utils:CreateVehicle', function(Vehicle)
    SetVehicleFuelLevel(Vehicle, 100.0)
    DecorSetFloat(Vehicle, "_FUEL_LEVEL", GetVehicleFuelLevel(Vehicle))

    if Config['Core']:upper() == 'QBCORE' then
        TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(Vehicle))
    end
end)

RegisterNetEvent('brutal_housing:client:utils:DeleteVehicle')
AddEventHandler('brutal_housing:client:utils:DeleteVehicle', function(Vehicle)
    DeleteEntity(Vehicle)
end)

function OpenMenuUtil()
    InMenu = true
    SetNuiFocus(true, true)

    Citizen.CreateThread(function()
        while InMenu do
            N_0xf4f2c0d4ee209e20() -- it's disable the AFK camera zoom
            Citizen.Wait(15000)
        end 
    end)

    DisplayRadar(false)
end

function DisableMinimap()
    DisplayRadar(false)
    -- Here you can add a trigger to hide your HUD system
end

function EnableMinimap()
    DisplayRadar(true)
    -- Here you can add a trigger to enable your HUD system
end
```

</details>

<details>

<summary>server-utils.lua</summary>

```lua
local Webhooks = {
    create = 'YOUR-WEBHOOK',  -- help: https://docs.brutalscripts.com/site/others/discord-webhook
    delete = 'YOUR-WEBHOOK',
    purchase = 'YOUR-WEBHOOK',
    rent = 'YOUR-WEBHOOK',
    ownerchange = 'YOUR-WEBHOOK',
}

function GetWebhook()
    return Webhooks
end

RESCB("brutal_housing:server:GetDressing",function(source,cb)
    local src = source
    local dressingTable = {}
    local dataArrived = false

    if Config['Core']:upper() == 'ESX' then
        TriggerEvent('esx_datastore:getDataStore', 'property', GetIdentifier(src), function(store)
            local dressings = store.get('dressing') or {}
        
            for k,v in pairs(dressings) do
                table.insert(dressingTable, {label = v.label, skin = v.skin})
            end
        end)
        dataArrived = true
    elseif Config['Core']:upper() == 'QBCORE' then
        local results = MySQL.query.await('SELECT * FROM player_outfits WHERE citizenid = ?', { GetIdentifier(src) })
        for k, v in pairs(results) do
            table.insert(dressingTable, {label = v.outfitname ~= "" and v.outfitname or "None", skin = results[k].skin, model = v.model})
        end
        dataArrived = true
    end

    while not dataArrived do
        Citizen.Wait(10)
    end

    cb(dressingTable)
end)

RegisterNetEvent("brutal_housing:server:qbcore-loadPlayerSkin")
AddEventHandler("brutal_housing:server:qbcore-loadPlayerSkin", function(model, skin)
    local src = source

    if model ~= nil and skin ~= nil then
        MySQL.query('DELETE FROM playerskins WHERE citizenid = ?', { GetIdentifier(src) }, function()
            MySQL.insert('INSERT INTO playerskins (citizenid, model, skin, active) VALUES (?, ?, ?, ?)', {
                GetIdentifier(src),
                model,
                skin,
                1
            })
        end)
    end
end)

function StaffCheck(source)
    local staff = false

    if Config.Core:upper() == 'ESX'then
        local player = Core.GetPlayerFromId(source)
        local playerGroup = player.getGroup()

        for i, Group in ipairs(Config.AdminGroups) do
            if playerGroup == Group then
                staff = true
                break
            end
        end
    elseif Config.Core:upper() == 'QBCORE' then

        for i, Group in ipairs(Config.AdminGroups) do
            if Core.Functions.HasPermission(source, Group) or IsPlayerAceAllowed(source, Group) or IsPlayerAceAllowed(source, 'command') then
                staff = true
                break
            end
        end
    end

    return staff
end

RegisterNetEvent("brutal_housing:qb-inventory:server:OpenInventory", function(job, data)
    local src = source

    exports['qb-inventory']:OpenInventory(src, job, data)
end)
```

</details>

<details>

<summary>client-core.lua</summary>

```lua
Core = nil
defaultVoiceChannel = 0

if Config.VoiceSytem:upper() == 'SALTYCHAT' then
    defaultVoiceChannel = "ingame"
end

if Config['Core']:upper() == 'ESX' then
    local _esx_ = 'new' -- 'new' / 'old'

    if _esx_ then
        Core = exports['es_extended']:getSharedObject()
    else
        while Core == nil do
            TriggerEvent('esx:getSharedObject', function(obj) Core = obj end)
            Citizen.Wait(0)
        end
    end

    LoadedEvent = 'esx:playerLoaded'
    ReviveEvent = 'esx_ambulancejob:revive'
    JobUpdateEvent = 'esx:setJob'
    TSCB = Core.TriggerServerCallback

    function GetPlayerJobDatas()
        return Core.GetPlayerData().job
    end

    function GetPlayersFunction()
        return Core.Game.GetPlayers()
    end

    function GetVehiclePropertiesFunction(vehicle)
        return Core.Game.GetVehicleProperties(vehicle)
    end

    function SetVehiclePropertiesFunction(vehicle, properties)
        return Core.Game.SetVehicleProperties(vehicle, properties)
    end

    function GetClosestVehicleFunction(coords, modelFilter)
        return Core.Game.GetClosestVehicle(coords, modelFilter)
    end

elseif Config['Core']:upper() == 'QBCORE' then
    Core = exports['qb-core']:GetCoreObject()

    LoadedEvent = 'QBCore:Client:OnPlayerLoaded'
    ReviveEvent = 'hospital:client:Revive'
    JobUpdateEvent = 'QBCore:Client:OnJobUpdate'
    TSCB = Core.Functions.TriggerCallback

    function GetPlayerJobDatas()
        return Core.Functions.GetPlayerData().job
    end

    function GetPlayersFunction()
        return Core.Functions.GetPlayers()
    end

    function GetVehiclePropertiesFunction(vehicle)
        return Core.Functions.GetVehicleProperties(vehicle)
    end

    function SetVehiclePropertiesFunction(vehicle, properties)
        return Core.Functions.SetVehicleProperties(vehicle, properties)
    end

    function GetClosestVehicleFunction(coords, modelFilter)
        return Core.Functions.GetClosestVehicle(coords, modelFilter)
    end
    
end
```

</details>

<details>

<summary>server-core.lua</summary>

```lua
Core = nil

if Config['Core']:upper() == 'ESX' then
    local _esx_ = 'new' -- 'new' / 'old'
    
    if _esx_ == 'new' then
        Core = exports['es_extended']:getSharedObject()
    else
        Core = nil
        TriggerEvent('esx:getSharedObject', function(obj) Core = obj end)
        while Core == nil do
            Citizen.Wait(0)
        end
    end

    RESCB = Core.RegisterServerCallback
    GETPFI = Core.GetPlayerFromId
    RUI = Core.RegisterUsableItem
    SetJobEvent = 'esx:setJob'
    onPlayerDeath = 'esx:onPlayerDeath'
    SQLData = {
        users = 'users',
        job = 'job',
        jobs = 'jobs',

    }

    function GetIdentifier(source)
        local xPlayer = GETPFI(source)
        while xPlayer == nil do
            Citizen.Wait(1000)
            xPlayer = GETPFI(source) 
        end
        return xPlayer.identifier
    end

    function GetPlayerByIdentifier(identifier)
        return Core.GetPlayerFromIdentifier(identifier)
    end

    function GetAccountMoney(source,account)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            return xPlayer.getAccount(account).money
        elseif account == 'money' then
            return xPlayer.getMoney()
        end
    end

    function AddMoneyFunction(source, account, amount)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            xPlayer.addAccountMoney('bank', amount)
        elseif account == 'money' then
            xPlayer.addMoney(amount)
        end
    end

    function RemoveAccountMoney(source, account, amount)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            xPlayer.removeAccountMoney('bank', amount)
        elseif account == 'money' then
            xPlayer.removeMoney(amount)
        end
    end

    function GetItemCount(source, item)
        local xPlayer = GETPFI(source)

        if _esx_ == 'new' then
            return xPlayer.getInventoryItem(item).count
        else
            if string.sub(item, 0, 6):lower() == 'weapon' then
                local loadoutNum, weapon = xPlayer.getWeapon(item:upper())

                if weapon then
                    return true
                else
                    return false
                end
            else
                return xPlayer.getInventoryItem(item).count
            end
        end
    end
    
    function RemoveItem(source, item, amount)
        local xPlayer = GETPFI(source)
        if _esx_ == 'new' then
            xPlayer.removeInventoryItem(item, amount)
        else
            if string.sub(item, 0, 6):lower() == 'weapon' then
                xPlayer.removeWeapon(item)
            else
                xPlayer.removeInventoryItem(item, amount)
            end
        end
    end

    function AddItem(source, item, count, info)
        local xPlayer = GETPFI(source)
        if _esx_ == 'new' then
            xPlayer.addInventoryItem(item, count, info)
        else
            if string.sub(item, 0, 6):lower() == 'weapon' then
                xPlayer.addWeapon(item, 90)
            else
                xPlayer.addInventoryItem(item, count)
            end
        end
    end

    function GetPlayerNameFunction(source)
        local name
        if Config.SteamName then
            name = GetPlayerName(source) or 'No Data'
        else
            local xPlayer = GETPFI(source)
            name = xPlayer.getName() or 'No Data'
        end
        return name
    end

    function GetPlayerJob(source)
        local xPlayer = GETPFI(source)
        return xPlayer.job.name
    end

    function CreateCoreJob(name, label, grades)
        Core.CreateJob(name, label, grades)
    end

    function SetCoreJob(source, job, grade)
        local xPlayer = GETPFI(source)
        xPlayer.setJob(job, grade)
    end

    function SetCoreJobOffline(identifier, job, grade)
        MySQL.update('UPDATE users SET job = ?, job_grade = ? WHERE identifier = ?', {job, grade, identifier})
    end

    function GetPlayersFunction()
        return Core.GetPlayers()
    end

elseif Config['Core']:upper() == 'QBCORE' then

    Core = exports['qb-core']:GetCoreObject()
    
    RESCB = Core.Functions.CreateCallback
    GETPFI = Core.Functions.GetPlayer
    RUI = Core.Functions.CreateUseableItem
    SetJobEvent = 'QBCore:Server:SetGang'
    onPlayerDeath = GetResourceState("brutal_ambulancejob") == "started" and 'onPlayerDeath' or 'hospital:server:SetDeathStatus'
    SQLData = {
        players = 'players',
    }

    function GetIdentifier(source)
        local xPlayer = GETPFI(source)
        while xPlayer == nil do
            Citizen.Wait(1000)
            xPlayer = GETPFI(source) 
        end
        return xPlayer.PlayerData.citizenid
    end

    function GetPlayerByIdentifier(identifier)
        return Core.Functions.GetPlayerByCitizenId(identifier)
    end

    function GetAccountMoney(source, account)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            return xPlayer.PlayerData.money.bank
        elseif account == 'money' then
            return xPlayer.PlayerData.money.cash
        end
    end

    function AddMoneyFunction(source, account, amount)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            xPlayer.Functions.AddMoney('bank', amount)
        elseif account == 'money' then
            xPlayer.Functions.AddMoney('cash', amount)
        end
    end

    function RemoveAccountMoney(source, account, amount)
        local xPlayer = GETPFI(source)
        if account == 'bank' then
            xPlayer.Functions.RemoveMoney('bank', amount)
        elseif account == 'money' then
            xPlayer.Functions.RemoveMoney('cash', amount)
        end
    end

    function GetItemCount(source, item)
        local xPlayer = GETPFI(source)
        local items = xPlayer.Functions.GetItemByName(item)
        local item_count = 0
        if items ~= nil then
            item_count = items.amount
        else
            item_count = 0
        end
        return item_count
    end

    function RemoveItem(source, item, amount)
        local xPlayer = GETPFI(source)
        xPlayer.Functions.RemoveItem(item, amount)
    end

    function AddItem(source, item, count, info)
        local xPlayer = GETPFI(source)
        xPlayer.Functions.AddItem(item, count, nil, info)
    end

    function GetPlayerNameFunction(source)
        local name
        if Config.SteamName then
            name = GetPlayerName(source)
        else
            local xPlayer = GETPFI(source)
            name = xPlayer.PlayerData.charinfo.firstname..' '..xPlayer.PlayerData.charinfo.lastname
        end
        return name
    end

    function GetPlayerJob(source)
        local xPlayer = GETPFI(source)
        return xPlayer.PlayerData.gang.name
    end

    function CreateCoreJob(name, label, grades)
        Core.Functions.AddGang(name, 
        {
            label = label,
            grades = grades,
        })
    end

    function UpdateCoreJob(name, label, grades)
        Core.Functions.UpdateGang(name, {
            label = label,
            grades = grades,
        })
    end

    function RemoveCoreJob(name)
        Core.Functions.RemoveGang(name)
    end

    function SetCoreJob(source, job, grade)
        local xPlayer = GETPFI(source)
        xPlayer.Functions.SetGang(job, grade)
    end

    function SetCoreJobOffline(identifier, job)
        local joblabel = "None"
        if Gangs[job] ~= nil and Gangs[job].label ~= nil then
            joblabel = Gangs[job].label
        end

        MySQL.update('UPDATE players SET gang = ? WHERE citizenid = ?', {json.encode({grade = {level = 0, name = "Member"}, name = job, isboss = false, label = joblabel}), identifier})
    end

    function GetPlayersFunction()
        return Core.Functions.GetPlayers()
    end
end
```

</details>
