# Config Files

## Useful Articles

{% embed url="<https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks>" %}

{% embed url="<https://steamcommunity.com/dev/apikey>" %}

<details>

<summary>MainConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- Dependency Check Helper                                                     
-- (Information) ► Returns the first matching started resource alias from provided table.
-- (Information) ► Used by Fuel/Keys/TextUI/Inventory/Target detection above.
-- ──────────────────────────────────────────────────────────────────────────────
function scriptCheck(data)            -- Do not modify unless you know what you're doing.
    for k, v in pairs(data) do
        if GetResourceState(k):find('started') ~= nil then
            return v
        end
    end
    return false
end

-- ──────────────────────────────────────────────────────────────────────────────
--  OTHERPLANET / OP Gangs 3.0 Main CONFIGURATION
-- ──────────────────────────────────────────────────────────────────────────────
--  This configuration file controls all customizable behaviour of OP Gangs 3.0.
--  Always make a backup before editing.
--  Wrong edits can break the resource.
-- ──────────────────────────────────────────────────────────────────────────────

Config = {}                           

-- ──────────────────────────────────────────────────────────────────────────────
-- Locale & Debug                                                             
-- (Information) ► Locale controls which language file from locales/* will be used.
-- (Information) ► Debug enables extra logging to help with issue tracking.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Locale = "en"                  -- Supported: PL / ES / LT / HU / EN / FR / IT / PT / SK / TW / HR / EL / CZ / SI / AR / TR / DE / SV / NL / NO
Config.Debug  = false                 -- true = verbose debug output in console.

-- ──────────────────────────────────────────────────────────────────────────────
-- TIMEZONE                                                         
-- (Information) ► Full list of timezones is available in AvailableTimeZones.json
-- ──────────────────────────────────────────────────────────────────────────────

Config.TimeZone = "Europe/Warsaw"

-- ──────────────────────────────────────────────────────────────────────────────
-- Fuel Dependency Detection                                                   
-- (Information) ► Auto-detects your active fuel resource.
-- (Information) ► To add support for another fuel script, extend the list below and 
-- (Information) ► handle logic in the integrations where fuel is used.
-- ──────────────────────────────────────────────────────────────────────────────
local fuelScripts = {                 
    ['cdn-fuel']        = "cdn-fuel",
    ['ox_fuel']         = "ox-fuel",
    ['LegacyFuel']      = "LegacyFuel",
    ['rcore_fuel']      = "rcore-fuel",
    ['codem-xfuel']     = "codem-xfuel",
    ['lc_fuel']         = "lc_fuel",
    ['stg-fuel']        = "stg-fuel",
}
Config.FuelDependency = scriptCheck(fuelScripts) or 'none'

-- ──────────────────────────────────────────────────────────────────────────────
-- Vehicle Keys Dependency Detection                                           
-- (Information) ► Auto-detects supported vehicle key systems.
-- (Information) ► If none is found, script will behave as if no key system is present.
-- ──────────────────────────────────────────────────────────────────────────────
local keyScripts = {                  
    ['brutal_keys']        = "brutal_keys",
    ['qbx_vehiclekeys'] = "qb-keys",
    ['qb-vehiclekeys']            = "qb-keys",
    ['wasabi_carlock']     = "wasabi_carlock",
    ['sna-vehiclekeys']    = "sna-vehiclekeys",
    ['dusa_vehiclekeys']   = "dusa_vehiclekeys",
    ['Renewed-Vehiclekeys']= "Renewed-Vehiclekeys",
    ['tgiann-hotwire']     = "tgiann-keys",
    ['ak47_vehiclekeys']   = "ak47_vehiclekeys",
    ['ak47_qb_vehiclekeys']= "ak47_qb_vehiclekeys",
    ['mVehicle']           = "mVehicle",
    ['sy_carkeys']         = "sy_carkeys",
    ['MrNewbVehicleKeys']  = "MrNewbVehicleKeys",
    ['vehicles_keys']      = "vehicles_keys",
}
Config.KeysDependency = scriptCheck(keyScripts) or 'none'

-- ──────────────────────────────────────────────────────────────────────────────
-- Text UI Dependency Detection                                                
-- (Information) ► Auto-detects supported 3D/2D Text UI libraries.
-- (Information) ► If none is found, some prompts may fallback to default behaviour.
-- ──────────────────────────────────────────────────────────────────────────────
local textUIScripts = {              
    ['ox_lib']        = "ox_lib",
    ['jg-textui']     = "jg-textui",
    ['okokTextUI']    = "okokTextUI",
    ['brutal_textui'] = "brutal_textui",
    ['0r-textui']     = "0r-textui",
}
Config.TextUI = scriptCheck(textUIScripts) or 'none' 

-- ──────────────────────────────────────────────────────────────────────────────
-- Garage Script                                                               
-- (Information) ► Manual selection of external garage script integration.
-- (Information) ► If set to 'none', OP-Crime will handle garage logic internally where applicable.
-- ──────────────────────────────────────────────────────────────────────────────
Config.GarageScript = 'none'          -- Options: 'none', 'op-garages', 'jg-advancedgarages'

-- ──────────────────────────────────────────────────────────────────────────────
-- Additional Script Integrations                                              
-- (Information) ► Toggle support for optional helper resources.
-- ──────────────────────────────────────────────────────────────────────────────
Config.AdditionalScripts = {         
    kq_shellcreator  = false,         -- (Information) ► true if you are using kq_shellcreator.
    advancedParking  = false          -- (Information) ► true if you use AdvancedParking.
}

local dispatchScripts = {            
    ['cd_dispatch']        = "cd_dispatch",
    ['codem_dispatch']     = "codem_dispatch",
    ['kartik-mdt']         = "kartik-mdt",
    ['lb-tablet']          = "lb-tablet",
    ['ps-dispatch']        = "ps-dispatch",
    ['rcore_dispatch']     = "rcore_dispatch",
}
Config.dispatchScript = scriptCheck(dispatchScripts) or 'none'

-- ──────────────────────────────────────────────────────────────────────────────
-- Inventory System Detection                                                  
-- (Information) ► Auto-detects currently started inventory system.
-- (Information) ► To support more inventories, extend the list and update inventory integration.
-- ──────────────────────────────────────────────────────────────────────────────
local inventoryScripts = {            
    ['ox_inventory']     = "ox_inventory",
    ['qb-inventory']     = "qb-inventory",
    ['codem-inventory']  = "codem-inventory",
    ['tgiann-inventory'] = "tgiann_inventory",
    ['origen_inventory'] = "origen_inventory",
}

-- If you're using QB Inventory and it's not working properly set below option to:
-- Config.Inventory = {                  
--     inventoryScript = 'old-qb-inventory'
-- }

Config.Inventory = {                  
    inventoryScript = scriptCheck(inventoryScripts) or 'none'
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Currency Formatting                                                         
-- (Information) ► Visual formatting of money values in the UI (JS Intl.NumberFormat).
-- (Information) ► This does NOT change internal game currency logic, only display.
-- ──────────────────────────────────────────────────────────────────────────────
Config.CurrencySettings = {           
    -- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
    currency = "USD",                 -- 'USD','EUR','PLN', etc.
    style    = "currency",            -- 'currency','decimal','percent','unit'
    format   = "en-US"                -- Locale string for formatting.
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Dirty Money Handling                                                        
-- (Information) ► ESX: Uses default 'black_money' account automatically.
-- (Information) ► QB/QBOX: Uses configured item as dirty cash equivalent.
-- ──────────────────────────────────────────────────────────────────────────────
Config.DirtyMoney = {                 
    itemName = "dirty_money" -- Dirty money item name on QB/QBOX.
}

-- ──────────────────────────────────────────────────────────────────────────────
-- ⚒️ MISC CONFIGURATION ⚒️                                                   
-- (Information) ► General behaviour, markers, notifications, ranking limits, etc.
-- ──────────────────────────────────────────────────────────────────────────────

local targets = { -- Target libraries detection
    ['ox_target'] = "ox-target",
    ['qb-target'] = "qb-target"
}

local notifyScripts = { -- Notify libraries detection
    ['op-hud'] = "op_hud",
    ['okokNotify'] = "okokNotify",
    ['vms_notify'] = "vms_notify",
    ['ox_lib'] = "ox_lib",
    ['brutal_notify'] = "brutal_notify",
}

Config.Misc = {                       
    AccessMethod = scriptCheck(targets) or 'none', --  'ox-target' / 'qb-target' / 'none'
    zoneSize = 1.2,                   -- Marker radius for interaction zones.
    zoneColor = {                     -- Marker color (RGB).
        r = 219,
        g = 0,
        b = 0,
    },
    TowingTime = 5,                                -- Towing time in seconds.
    Notify = scriptCheck(notifyScripts) or 'none', -- Notify system: none / ESX / QBCORE / QBOX or auto detected from list 'notifyScripts'
    stashCapacityUpgradePer = 5,                   -- One stash upgrade = +X KG. Note: Changing this requires your changes in Locale file! UI description (will still display that upgrade adds 5kg until you adjust translation)
    ranksLimit   = 5,                              -- Max number of ranks per organisation.
    membersLimit = 20,                             -- Max number of members per organisation.
    limitBossMenu = false,                         -- true = only one player can access bossmenu at once. Note: You can limit bossmenu to one player at a time!
    disableGarage = false,                         -- true = completely disable garages & vehicle shop in bossmenu.
    disableDarkChat = false,                       -- true = disable darkchat in crime tablet.
    disableDarkChatNotificationAboveMap = false,   -- true = disable on-screen darkchat notifications.
    disableRanking = false,                        -- true = disable ranking page in tablet.
    defaultStashWeight = 2,                        -- Default Stash KG for new Gangs.
    defaultRanksSlotsAmount = 2,                   -- Default Ranks Slots for new Gangs.
    defaultRanksMembersAmount = 2,                 -- Default Member Slots for new Gangs.
    useDirtyMoneyInBossmenu = false,               -- Use Dirty money to purchase upgrades in bossmenu.
    disableGangBlip = false,                       -- Disables Gang Location Blip on gta Map
    disableStashes = false,                        -- Disable Stashes
} 

-- ──────────────────────────────────────────────────────────────────────────────
-- Admin Commands & Permissions                                                
-- (Information) ► Configure admin commands and who is allowed to use them.
-- ──────────────────────────────────────────────────────────────────────────────
Config.AdminPanelCommand   = "crimeadmin"   -- Command for Crime Admin Panel.
Config.SetJobCommand       = "setcrimejob"  -- Command to set selected player's crime job.
Config.AddCrimeVehicle     = "addcrimecar"  -- Command to add vehicle to selected organisation.
Config.FireCommand         = "firemember"   -- Command to fire member from current organisation.
Config.ResetGangsStats     = "resetgangstats" -- Wipes all gangs stats (zones, missions, etc.) used in ranking.

-- List of allowed identifiers to use admin Commands /setcrimejob and /addcrimecar
-- (Information) ► Use identifiers from txAdmin -> IDs (no hardware IDs!).
-- (Information) ► You can also use character identifiers or citizenid on QBOX/QB.
-- E.g.: char1:7e0ec7b80d186fd8c29f6631e4377e75812fe8fd
Config.AdminCommandsPlayers = {      
    ['license:94792cad7ae764305aae8f1372d3cd287848ae7c'] = true,
    ['discord:571105311251890186'] = true,
}

-- List of allowed identifiers to use /crimeadmin
-- Same rules as above (txAdmin IDs / character identifiers / citizenid).
Config.AdminPanelPlayers = {          
    ['license:94792cad7ae764305aae8f1372d3cd287848ae7c'] = true,
    ['discord:571105311251890186'] = true,
}

Config.SellVehiclePercentage = 20     -- Percentage of original vehicle price when selling in bossmenu.

-- ──────────────────────────────────────────────────────────────────────────────
-- 📱 TABLET CONFIGURATION 📱                                                 
-- (Information) ► Controls how crime tablet is accessed and how missions are handled.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Tablet = {                     
    tabletASItem = false,             -- true = tablet is usable item, false = command-based.
    commandName = "crimetablet",      -- Command used when tabletASItem is false.
    item = {
        name = "crime_tablet"         -- Required item name if tabletASItem is true.
    },
    MissionsPerRestart = 15,           -- How many missions per organisation per update.
    DisableSeasonPass = false,        -- true = disable season pass feature Completly (As well from Boss Menu and Admin Panel).
    DisableFrames = false,            -- true = hide tablet frame UI elements.
    Animation = { -- Tablet Animation
        enable = true,
        dict = "amb@code_human_in_bus_passenger_idles@female@tablet@idle_a",
        name = "idle_a",
        prop = { -- Replace prop table with false (prop = false) if you want to disable it!
            Prop = "prop_cs_tablet",
            PropBone = 28422,
            PropPlacement = {
                -0.05,
                0.0,
                0.0,
                0.0,
                -90.0,
                0.0
            }
        }
    }
}

Config.SeasonPass = {
    -- To disable/enable season pass check Config.Tablet.DisableSeasonPass
    -- Configure custom currency exports in `op-crime/integrations/server/utils/customCurrency.lua`
    enableCustomCurrency = false, 
    customCurrencyLabel = "GC", -- Label of coins, example: Purchase for 950GC
}

-- ──────────────────────────────────────────────────────────────────────────────
-- 🌍 BLIPS CONFIGURATION 🌍                                                  
-- (Information) ► Map blips for organisations, garages, zones and money laundry.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Blips = {                      
    BlipScale = 0.8,                  -- Global blip scale.
    ShowBlipsOnMap = true,            -- false = hide money laundry, garages and illegal medic blips.
    ZonesShowBlipsOnMap = true,       -- false = hide PVP/turf zone blips.
    Medic = { blipId = 51, blipColor = 7 },
    Organisation = { blipId = 437, blipColor = 1 },
    Zone = { blipId = 379, blipColor = 3 },
    Garage = { blipId = 357, blipColor = 2 },
    MoneyLaundry = { blipId = 318, blipColor = 25 },
    MoneyLaundryLocation = { blipId = 478, blipColor = 1 },
    LaundryLocationRadiusBlip = { 
        Color = 49,
        Alpha = 222,
        Radius = 60.0
    }
}

-- ──────────────────────────────────────────────────────────────────────────────
-- 🧼 MONEY LAUNDRY CONFIGURATION 🧼                                         
-- (Information) ► Settings for dirty money washing missions.
-- ──────────────────────────────────────────────────────────────────────────────
Config.MoneyLaundry = {               
    Disable = false,                  -- true = disable entire money laundry feature.
    laundryAmountPerOneStop = 20000,  -- Amount of dirty money cleaned per location.
    laundryPercentage = 15,           -- Tax percentage taken from laundered amount.
    Ped = {                           -- Set to false to disable ped (Ped = false,).
        model = "a_m_m_afriamer_01",
        gender = "male", -- options: male/female
    },
    laundryMisc = {
        location = vec4(78.8508, 112.5588, 80.1682, 161.7077),
        vehicleSpawnCoords = vec4(68.4445, 119.2293, 79.1232, 161.5234),
        vehicleModel = 'boxville4',
        -- LAUNDRY MISSION OUTFIT IS LOCATED NOW IN config/ClothingConfig.lua
    },
    laundryLocations = {
        {
            coords = vec4(237.7540, 22.6503, 82.6137, 341.4727)
        },
        {
            coords = vec4(-77.5555, -1200.6666, 26.6352, 92.4784)
        },
        {
            coords = vec4(232.4930, -1771.4315, 27.6610, 48.4330)
        },
        {
            coords = vec4(967.5204, -1823.1718, 30.0824, 229.1019)
        },
        {
            coords = vec4(947.5532, -1698.1992, 29.0851, 84.8497)
        },
    }
}

-- ──────────────────────────────────────────────────────────────────────────────
-- 🏥 MEDIC CONFIGURATION 🏥                                                 
-- (Information) ► Illegal medic / healing spot configuration.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Medic = {                      
    Disable = false,                  -- true = disable this feature.
    HealingTime = 10,                 -- Healing time in seconds.
    Ped = {
        model = "s_m_m_scientist_01",
        gender = "male",
        animation = {
            Dict = "missheistdockssetup1clipboard@base",
            Lib  = "base",
            Prop = {
                Prop = 'prop_notepad_01',
                PropBone = 18905,
                PropPlacement = {
                    0.1,
                    0.02,
                    0.05,
                    10.0,
                    0.0,
                    0.0
                }
            }
        }
    },
}

-- ──────────────────────────────────────────────────────────────────────────────
-- 📍 PVP ZONES CONFIGURATION 📍                                             
-- (Information) ► Non-turf PVP zones. For Turf Zones see: config/TurfConfig.lua
-- ──────────────────────────────────────────────────────────────────────────────

-- THIS IS SECTION FOR PVP ZONES (NO TURFZONES)
-- IF YOU WANT TO CONFIGURE TURF ZONES - GO TO config/TurfConfig.lua

Config.ZonesMisc = {                 
    PerOnePlayerInside = 0.3,           -- Time (in seconds) for 1% capture progress for one org.
    -- If there are 2 organisations in zone the zone capturing percentage will stop.
    ZonesCooldown   = 15,             -- Cooldown time (in minutes) after a capture.
    ZoneCaptureEXP  = 150,            -- EXP given per zone capture.
    Disable         = false,          -- true = disable PVP zones completely.
    ZoneTimers = {
        -- Time window when zones can be captured
        enable = false,
        -- WARNING: Make sure you configured correct Config.TimeZone in MainConfig.lua
        -- INFORMATION: Use 24 hours time format
        startTime = "02:00",
        endTime   = "11:00",
    }
}

Config.Zones = {                      -- Add custom PVP zones here.
    -- To create new zones use /pzcreate poly
    -- To add new point to created poly use /pzadd 
    -- More info: https://github.com/mkafrin/PolyZone
    {
        label = "Sandy Scrapy Yard",
        index = "sandyscrapy",
        coords = vec3(2404.2021, 3104.1765, 48.1648),
        rewards = {
            enable = false,
            list = {
                {
                    rewardType = "item",       ---@param rewardType "item" | "money" | "blackmoney"
                    itemName   = "spray_can",
                    amount     = 10,
                    -- EXAMPLE OF METADATA USAGE (only for ox_inv):
                    -- metadata   = {
                    --     testmeta = 69
                    -- }
                },
            }
        },
        Zone = function()
            return PolyZone:Create({
                vector2(2329.3020019532, 3053.681640625),
                vector2(2330.888671875, 3081.3254394532),
                vector2(2361.8330078125, 3087.1943359375),
                vector2(2379.0219726562, 3105.4108886718),
                vector2(2404.3395996094, 3163.1628417968),
                vector2(2437.2124023438, 3160.5307617188),
                vector2(2434.8149414062, 3024.4143066406),
                vector2(2329.9057617188, 3024.9143066406)
            }, {
                name = "SandyScrapyYard",
            })
        end,
    },
}

-- ──────────────────────────────────────────────────────────────────────────────
-- ROPE MENU                                                                 
-- (Information) ► Enables rope item / keybind usage with optional target integration.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Rope = {                       
    Enable = true, -- false = disable rope completly
    Item = {
        Enable   = true,
        ItemName = "rope",             -- Rope item name.
        RemoveItem = false            -- Remove item when tie/untie
    },
    Keybind = {
        Enable = true,
        Bind   = "F6"                 -- Keybind used for rope menu when enabled.
    },
    Target = {
        RequireItemInInventory = true, 
        RequiredItemName = "rope",
        Enable = true                 -- true = add target options to every player.
        -- When it's enabled - will add options to every player on the server.
    },
}

-- ──────────────────────────────────────────────────────────────────────────────
-- GANG WARS                                                               
-- (Information) ► All configuration for Gang Wars.
-- ──────────────────────────────────────────────────────────────────────────────
Config.GangWars = {
    enable = true, -- Enable/Disable Gangwars
    requiredLevel = 1, -- Required minimum level to use gangwars!
}

-- ──────────────────────────────────────────────────────────────────────────────
-- AIRDROPS                                                                  
-- (Information) ► Global configuration for Airdrop events, guards and rewards.
-- ──────────────────────────────────────────────────────────────────────────────
Config.AirDrop = {                    
    Guards = {
        enable = true,
        amount = 8, 
        weaponsList = {
            `weapon_SNSPISTOL`,
            `WEAPON_SNSPISTOL_MK2`,
            `WEAPON_VINTAGEPISTOL`,
            `WEAPON_PISTOL`
        },
        guardModels = { 
            "s_m_y_blackops_01", 
            "s_m_y_blackops_02", 
            "s_m_m_armoured_01", 
            "s_m_m_marine_01" 
        }
    },
    RequiredItems = {
        --["crowbar"] = {
        --    itemName = "crowbar",
        --    quanity = 1
        --},
    },
    SpawnTimeWindow = {
        -- Time window when Air Drops are auto started.
        enable = false,
        -- WARNING: Make sure you configured correct Config.TimeZone in MainConfig.lua
        -- INFORMATION: Use 24 hours time format
        startTime = "17:00",
        endTime   = "23:00",
    },
    StartCommand = {
        Enable = true,               -- Allow your admins to start AirDrop manually.
        CommandName = "startAirDrop" -- Command name to start Airdrop.
    },
    TimeToLand = 2,                  -- Time in minutes before airdrop starts going down.
    Enable = true,                   -- Master toggle for Airdrop system.
    Timer = 2,                       -- Interval in hours between automatic airdrops.
    DespawnTime = 25,                -- Minutes after which unopened airdrop will despawn.
    Locations = {
        vec4(470.7527, 2942.3884, 40.7600, 95.2011),
        vec4(1350.2504, 4354.7686, 42.7147, 315.9569),
        vec4(2034.9507, 4764.8198, 40.0590, 290.3700),
        vec4(3700.1226, 4533.2456, 22.2974, 193.3774),
        vec4(1518.1498, 6341.2002, 23.0057, 171.9430),
        vec4(-70.5034, 1910.8385, 195.1936, 196.7471),
    },
    Exp = 100,                       -- EXP given for opening Airdrop.
    Blip = {
        EnableRadiusBlip = true, 
        Blip      = 550,
        BlipColor = 3,
    },
    RewardsAmount = 3,               -- Number of random rewards per airdrop.
    Rewards = {

        {
            rewardType = "item",       ---@param rewardType "item" | "money" | "blackmoney"
            itemName   = "spray_can",
            amount     = 10,
            chance     = 50,
        },
        {
            rewardType = "item",       ---@param rewardType "item" | "money" | "blackmoney"
            itemName   = "spray_remover",
            amount     = 10,
            chance     = 50,
        },
        {
            rewardType = "blackmoney", ---@param rewardType "item" | "money" | "blackmoney"
            itemName   = "black_money",
            amount     = 100000,
            chance     = 50,
        },
        --[[
        EXAMPLE ITEM WITH METADATA:
        {
            rewardType = "item",       --@param rewardType "item" | "money" | "blackmoney"
            itemName   = "testitem",
            amount     = 15,
            chance     = 50,
            metadata   = {
                testmeta = 69
            }
        },--]]
        -- [Note]: Metadata currently works only for ox_inventory. 
        -- If you want metadata compatible with your inventory script:
        -- Files that need to be edited: `integrations/server/inventory/`
        -- and one of `framework/server` functions Fr.AddItem
    },
    ProgressTime = 10000,            -- Time in milliseconds for opening progress bar.
    SkillCheck = function()          -- Custom skill check function (uses ox_lib by default).
        return lib.skillCheck({'easy', 'easy', 'medium', 'easy', 'medium'}, {'w', 'a', 's', 'd'})
    end,
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Garage Disable Marker Helper                                               
-- (Information) ► Some external garage scripts manage their own markers/blips.
-- (Information) ► This helper allows OP-Crime to disable its own markers when needed.
-- ──────────────────────────────────────────────────────────────────────────────
-- Do not touch function below if you don't know what you're changing!
Config.GarageDisableMarker = function() 
    if Config.GarageScript == 'jg-advancedgarages' then 
        return true
    else 
        return false
    end
end
```

</details>

<details>

<summary>TurfConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- Turf Zones System Configuration                                             
--        racketeering, rivalry conflicts and drug-selling influence.
-- ──────────────────────────────────────────────────────────────────────────────

-- ──────────────────────────────────────────────────────────────────────────────
-- Turf Zones Base                                                             
-- (Information) ► Enables or disables the entire turf zone mechanic.
-- ──────────────────────────────────────────────────────────────────────────────
Config.DisableTurfZones = false              -- Disable all Turf Zone features
Config.DisableEnterNotifications = true      -- Disable enter/leave zone notifications

Config.TurfActivitiesTimers = {
    -- Time window when activities in Rivalries are allowed
    -- This is regarding when graffiti, drugs sales etc counts to reputation.
    enable = false,
    -- WARNING: Make sure you configured correct Config.TimeZone in MainConfig.lua
    -- INFORMATION: Use 24 hours time format
    startTime = "23:00",
    endTime   = "11:00",
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Rivalry System                                                              
-- (Information) ► A timed gang–vs–gang conflict inside a turf zone.
-- (Information) ► EXP and costs scale with your server economy.
-- ──────────────────────────────────────────────────────────────────────────────

Config.Rivalry = {
    Disable = false,             -- Disable/Enable rivalry system
    RivalryStartPrice = 5000,    -- Cost (dirty money). Set to 0 for free rivalry.
    RivalryDuration = 1,         -- Duration in HOURS
    RivalryWinEXP = 250,         -- EXP reward for winning rivalry
    RivarlyBonusMultiplier = 0.5 -- 0.5 - 50% will be added to rivalry after sale of drug 
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Graffiti System                                                             
-- (Information) ► Allows gangs to paint and remove graffiti inside turf zones.
-- (Information) ► Graffiti contributes to zone loyalty and gang EXP.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Graffiti = {
    Disable = false,             -- Disable/Enable graffiti system
    RenderDistance = 30.0,       -- Distance at which graffiti becomes visible
    CooldownTime = 1,            -- Minutes between spraying graffiti
    CooldownTimeRemover = 1,     -- Minutes between removing graffiti
    SprayingTime = 10,           -- Time in seconds for Spraying Progressbar
    RemovingTime = 10,           -- Time in seconds for removing spray Progressbar

    Dispatch = {
        enable = true,
        title = "Graffiti in Progress",
        message = "Individuals are marking territory with graffiti. Possible gang-related activity.",
        type = "Graffiti", -- Reffer to dispatch type of your Dispatch script.
        blip = {
            color = 1, 
            sprite = 1, 
        }
    },

    Items = {                    -- Required items
        graffitiSpray = "spray_can",
        graffitiRemover = "spray_remover"
    },

    loyality = {                 -- Loyalty mechanics
        LoyalityPerGraffiti = 75,     -- Loyalty gained when gang paints graffiti
        loyalityIncreaseOnRemove = 15, -- Loyalty for removing enemy graffiti
        loyalityDecreaseOnRemove = 15, -- Loyalty lost when enemy removes your graffiti
        loyalityDecreaseOnPaint = 5,   -- Loyalty lost when enemy paints in your zone
        -- Zone ownership changes when a gang reaches ≥51% loyalty.
    },

    exp = {
        SprayingEXPgain = 50,         -- EXP for successfully spraying
        RemovingGraffitiEXPgain = 50  -- EXP for removing enemy graffiti
        -- Note: Removing your own graffiti gives no EXP.
    },

    -- Turf zone graffiti blips (only visible to gang members)
    Blip = {
        Enable = true,
        Radius = 80.0,                -- Min 25. Larger radius = bigger zone highlight.
    },

    Settings = {
        MaxSize = 9.75,               -- Optimal max graffiti size
        MinSize = 1.75,               -- Optimal min graffiti size
    },

    CleanGraffitiInterval = 1,       -- Every X hours all graffiti is auto-cleaned
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Racketeering System                                                         
-- (Information) ► “Protection” spots generating EXP and rewards for controlling gangs.
-- ──────────────────────────────────────────────────────────────────────────────
Config.Racketeering = {
    DisableBlips = false,   -- True = disables blips on map for racketeering
    Cooldown = 30,          -- Minutes between collect attempts
    Exp = 50,               -- EXP for claiming a racketeering point
    Blip = {
        BlipId = 358,
        BlipColor = 1,
    },
    Dispatch = {
        enable = true,
        title = "Extortion in Progress",
        message = "An individual is collecting protection money from a local store. Immediate attention may be required.",
        type = "Robbery", -- Reffer to dispatch type of your Dispatch script.
        blip = {
            color = 1, 
            sprite = 1, 
        }
    }
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Kills Inside Zone                                                        
-- (Information) ► Configure Influance from Killing other Gangs Members inside Turf
--                 and kills on NPC'S
-- ──────────────────────────────────────────────────────────────────────────────
Config.Kills = {
    enable = true,
    Gangs = {
        loyality = {                       -- Loyalty mechanics
            LoyalityPerKill = 15,          -- Loyalty gained when gang kills other gang member
            loyalityDecreasePerKill = 5,   -- Loyalty lost when enemy kills your gang member
            -- Zone ownership changes when a gang reaches ≥51% loyalty.
        },
        exp = {
            killEXPgain = 50, -- EXP for killing enemy gang
        },
    },
    NPCS = {
        LoyalityDecreasePerKill = 15, -- Loyalty decrease when killing NPC'S inside turf
    }
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Drug Selling Integration                                                    
-- (Information) ► Influence for selling drugs inside turf zones.
-- (Information) ► Supports custom drug scripts via integrations.
-- ──────────────────────────────────────────────────────────────────────────────

local drugSellingAvailable = {
    ['drugs_creator'] = "jaksam_drugs",
    ['envi-trap-phone'] = "envi-trap-phone",
}

Config.DrugSelling = {
    expOnDrugSell = 15,         -- EXP per drug transaction in zone

    loyality = {
        -- Ownership uses the ≥51% loyalty rule
        LoyalityPerTransaction = 50,  -- Loyalty gained when gang sells drugs in zone
        loyalityDecreaseOnOtherOrgs = 15 -- Loyalty lost when OTHER gang sells in your zone
    },

    -- Integration Drug Script (follow docs to integrate)
    -- (Information) ► This is regarding fetching data of sold drugs inside turf zones to add loyality etc.

    DrugScript = scriptCheck(drugSellingAvailable) or 'none',

    -- Full integration documentation:
    -- https://docs.otherplanet.dev/scripts/op-gangs/integrations
    --
    -- Fully supported (no config change needed):
    -- - op-drugselling (FREE)
    -- - nc-drugselling
    -- - visualz_selldrugs
    -- - tk_drugs
    -- - lunar_drugscreator
    -- - fs_trapphone
    -- - lation_selling
}
```

</details>

<details>

<summary>ClothingConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- Clothing System Detection                                                   
-- (Information) ► Detects your character appearance system automatically.
-- (Information) ► This is used for outfit switching during the laundry mission.
-- (Information) ► Add new integrations by expanding the list below and implementing
--        the logic inside your clothing adapter handlers.
-- ──────────────────────────────────────────────────────────────────────────────
local compatibleClothingList = { 
    ['skinchanger']           = "skinchanger",
    ['illenium-appearance']   = "illenium-appearance",
    ['fivem-appearance']      = "fivem-appearance",
    ['17mov_CharacterSystem'] = "17mov_CharacterSystem",
    ['rcore_clothing']        = "rcore_clothing",
    ['crm-appearance']        = "crm-appearance",
    ['tgiann-clothing']       = "tgiann_clothing",
    ['0r-clothingv2']         = "0r-clothingv2",
    ['qs-appearance']         = "qs-appearance"
}

Config.Clothing = { 
    enable = true, -- Disable/Enable gang locker.
    clothingScript = scriptCheck(compatibleClothingList) or 'none'
}

-- ──────────────────────────────────────────────────────────────────────────────
-- Laundry Mission: Outfit Configuration                                       
-- (Information) ► Defines the outfit the player will wear during the Laundry Mission.
-- (Information) ► Each clothing script uses its own format (components, props, ids, etc.)
-- (Information) ► Use /getMyOutfit in-game to print your current outfit to the F8 console.
-- (Information) ► Do not mix formats between systems. Only edit the block of the system
--        you are using. Wrong formatting will break outfit application.
-- ──────────────────────────────────────────────────────────────────────────────
Config.LaundryClothing = {
    enable = false, -- Enable/disable outfit swapping during laundry missions.

    -- (Information) ► Outfit lists per clothing script.
    -- (Information) ► The script will automatically choose the correct block based on the
    -- detected clothing system (Config.Clothing.clothingScript).
    playerOutFit = {
        ['qs-appearance'] = {
            { component_id = 0, drawable = 0, texture = 0 },
            { component_id = 1, drawable = 10, texture = 0 },
            { component_id = 2, drawable = 0, texture = 0 },
            { component_id = 3, drawable = 0, texture = 0 },
            { component_id = 4, drawable = 0, texture = 0 },
            { component_id = 5, drawable = 0, texture = 0 },
            { component_id = 6, drawable = 0, texture = 0 },
            { component_id = 7, drawable = 0, texture = 0 },
            { component_id = 8, drawable = 0, texture = 0 },
            { component_id = 9, drawable = 0, texture = 0 },
            { component_id = 10, drawable = 0, texture = 0 },
            { component_id = 11, drawable = 10, texture = 0 }
        },
        ['crm-appearance'] = { {
            crm_texture = 0,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 0,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 1,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 3,
            crm_style = 4
            }, {
            crm_texture = 5,
            crm_id = 4,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 5,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 6,
            crm_style = 3
            }, {
            crm_texture = 0,
            crm_id = 7,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 8,
            crm_style = 15
            }, {
            crm_texture = 0,
            crm_id = 9,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 10,
            crm_style = 0
            }, {
            crm_texture = 0,
            crm_id = 11,
            crm_style = 12
            } },
        ['rcore_clothing'] = {
            components = {
                ["3"] = "nondlcgta5--3--0--0",
                ["8"] = "8_15_0",
                ["11"] = "nondlcgta5--11--9--14"
            },
            props = {}
        },
        ['skinchanger'] = {
            chain_2 = 0,
            mask_1 = 0,
            pants_2 = 1,
            torso_1 = 14,
            bproof_1 = 0,
            shoes_1 = 57,
            bproof_2 = 0,
            glasses_2 = 0,
            glasses_1 = 0,
            helmet_2 = 1,
            tshirt_1 = 15,
            bags_1 = 0,
            decals_1 = 0,
            mask_2 = 0,
            arms_2 = 0,
            tshirt_2 = 0,
            torso_2 = 7,
            bags_2 = 0,
            shoes_2 = 10,
            chain_1 = 0,
            pants_1 = 6,
            arms = 0,
            helmet_1 = 45,
            decals_2 = 0
        },
        ['illenium-appearance'] = {
            { component_id = 0, drawable = 0, texture = 0 },
            { component_id = 1, drawable = 10, texture = 0 },
            { component_id = 2, drawable = 0, texture = 0 },
            { component_id = 3, drawable = 0, texture = 0 },
            { component_id = 4, drawable = 0, texture = 0 },
            { component_id = 5, drawable = 0, texture = 0 },
            { component_id = 6, drawable = 0, texture = 0 },
            { component_id = 7, drawable = 0, texture = 0 },
            { component_id = 8, drawable = 0, texture = 0 },
            { component_id = 9, drawable = 0, texture = 0 },
            { component_id = 10, drawable = 0, texture = 0 },
            { component_id = 11, drawable = 10, texture = 0 }
        },
        ['fivem-appearance'] = {
            { component_id = 0, drawable = 0, texture = 0 },
            { component_id = 1, drawable = 10, texture = 0 },
            { component_id = 2, drawable = 0, texture = 0 },
            { component_id = 3, drawable = 0, texture = 0 },
            { component_id = 4, drawable = 0, texture = 0 },
            { component_id = 5, drawable = 0, texture = 0 },
            { component_id = 6, drawable = 0, texture = 0 },
            { component_id = 7, drawable = 0, texture = 0 },
            { component_id = 8, drawable = 0, texture = 0 },
            { component_id = 9, drawable = 0, texture = 0 },
            { component_id = 10, drawable = 0, texture = 0 },
            { component_id = 11, drawable = 10, texture = 0 }
        },
        ['17mov_CharacterSystem'] = { {
            component_id = 1,
            texture = 0,
            drawable = 0
            }, {
            component_id = 3,
            texture = 0,
            drawable = 0
            }, {
            component_id = 4,
            texture = 2,
            drawable = 15
            }, {
            component_id = 5,
            texture = 0,
            drawable = 0
            }, {
            component_id = 6,
            texture = 0,
            drawable = 114
            }, {
            component_id = 7,
            texture = 0,
            drawable = 0
            }, {
            component_id = 8,
            texture = 0,
            drawable = 15
            }, {
            component_id = 9,
            texture = 0,
            drawable = 0
            }, {
            component_id = 10,
            texture = 0,
            drawable = 0
            }, {
            component_id = 11,
            texture = 0,
            drawable = 36
        }},
    }
}
```

</details>

<details>

<summary>FurnituresConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- 🪑 FURNITURE SYSTEM CONFIGURATION
-- ──────────────────────────────────────────────────────────────────────────────
-- Description:
-- This configuration controls the furniture system used inside gang hideouts.
-- Players can place, manage, and sell furniture objects such as decor,
-- storage units, and functional objects (boss menu, storage, etc.).
-- ──────────────────────────────────────────────────────────────────────────────

-- 🔧 GENERAL SETTINGS
Config.EnableFurnitures = true -- Enable / Disable furniture system

Config.FurnituresCommand = "furnitures" 
-- Command used to open the furniture menu inside gang hideout

Config.FurnitureSellPercentage = 90 
-- Percentage of original price returned when selling furniture
-- Example: 500$ item → player gets 450$ (10% loss)

-- 🏠 SHELLS (INTERIORS)
-- Defines available interiors where furniture can be placed

-- Shells in this config (FREE): https://k4mb1maps.com/product/5015840

Config.Shells = {
    ['k4_house3_shell'] = {
        name = "K4 Small House",
        spawn = "k4_house3_shell", -- Shell model
        coords = vec3(-1035.2122, -851.6562, -12.7472), -- Interior coordinates
        entranceDoor = vec4(-1032.7672, -855.3149, -11.5169, 81.7287) -- Entrance position
    },
    ['k4_warehouse1_shell'] = {
        name = "K4 Warehouse",
        spawn = "k4_warehouse1_shell",
        coords = vec3(-1020.3682, -815.6011, -11.7018),
        entranceDoor = vec4(-1028.8514, -815.3627, -10.3859, 259.8542)
    }
}


-- 📂 FURNITURE CATEGORIES
-- Used to organize furniture in the UI
Config.FurnituresCategories = {
    {name = "Living Room"},
    {name = "Bedroom"},
    {name = "Kitchen"},
    {name = "Bathroom"},
    {name = "Decor"},

    {name = "Boss Office - Desks"},
    {name = "Boss Office - Electronics"},
    {name = "Boss Office - Seating"},

    {name = "Storage"},
    {name = "Warehouse"}
}


-- 🪑 FURNITURE LIST
-- Each furniture item includes:
-- model     -> GTA prop model
-- category  -> UI category
-- price     -> purchase price
-- label     -> display name
-- usable    -> (optional) interaction type
-- helpText  -> (optional) description shown to player

Config.Furnitures = {

    -- LIVING ROOM (8)
    ["apa_mp_h_stn_sofacorn_01"] = { model = "apa_mp_h_stn_sofacorn_01", category = "Living Room", price = 2500, label = "Corner Sofa" },
    ["apa_mp_h_stn_sofa2seat_02"] = { model = "apa_mp_h_stn_sofa2seat_02", category = "Living Room", price = 1800, label = "Two Seat Sofa" },
    ["apa_mp_h_yacht_coffee_table_01"] = { model = "apa_mp_h_yacht_coffee_table_01", category = "Living Room", price = 900, label = "Coffee Table" },
    ["apa_mp_h_yacht_side_table_01"] = { model = "apa_mp_h_yacht_side_table_01", category = "Living Room", price = 600, label = "Side Table" },
    ["apa_mp_h_str_avunitl_01_b"] = { model = "apa_mp_h_str_avunitl_01_b", category = "Living Room", price = 1200, label = "TV Cabinet" },
    ["apa_mp_h_str_avunits_04"] = { model = "apa_mp_h_str_avunits_04", category = "Living Room", price = 1500, label = "Modern TV Unit" },
    ["prop_tv_flat_01"] = { model = "prop_tv_flat_01", category = "Living Room", price = 1300, label = "Flat TV" },
    ["apa_mp_h_stn_sofacorn_05"] = { model = "apa_mp_h_stn_sofacorn_05", category = "Living Room", price = 2600, label = "Modern Corner Sofa" },
    ["apa_mp_h_stn_sofa_daybed_01"] = { model = "apa_mp_h_stn_sofa_daybed_01", category = "Living Room", price = 2200, label = "Daybed Sofa" },
    ["prop_t_coffe_table"] = { model = "prop_t_coffe_table", category = "Living Room", price = 700, label = "Wood Coffee Table" },
    ["prop_tv_flat_02"] = { model = "prop_tv_flat_02", category = "Living Room", price = 1400, label = "Large Flat TV" },
    ["prop_cs_remote_01"] = { model = "prop_cs_remote_01", category = "Living Room", price = 100, label = "TV Remote" },

    -- BEDROOM (8)
    ["apa_mp_h_bed_double_08"] = { model = "apa_mp_h_bed_double_08", category = "Bedroom", price = 3000, label = "Double Bed" },
    ["apa_mp_h_bed_with_table_02"] = { model = "apa_mp_h_bed_with_table_02", category = "Bedroom", price = 3200, label = "Luxury Bed" },
    ["apa_mp_h_din_chair_04"] = { model = "apa_mp_h_din_chair_04", category = "Bedroom", price = 400, label = "Bedroom Chair" },
    ["apa_mp_h_bed_chestdrawer_02"] = { model = "apa_mp_h_bed_chestdrawer_02", category = "Bedroom", price = 1400, label = "Chest Drawer", usable = {type = "locker"}, helpText = "Locker for clothing" },
    ["apa_mp_h_str_shelffloorm_02"] = { model = "apa_mp_h_str_shelffloorm_02", category = "Bedroom", price = 1100, label = "Shelf Unit" },
    ["apa_mp_h_bed_double_09"] = { model = "apa_mp_h_bed_double_09", category = "Bedroom", price = 3100, label = "Modern Bed" },
    ["prop_clothes_rail_01"] = { model = "prop_clothes_rail_01", category = "Bedroom", price = 800, label = "Clothes Rail" },

    -- KITCHEN (8)
    ["apa_mp_h_din_table_06"] = { model = "apa_mp_h_din_table_06", category = "Kitchen", price = 2000, label = "Dining Table" },
    ["apa_mp_h_din_chair_08"] = { model = "apa_mp_h_din_chair_08", category = "Kitchen", price = 450, label = "Dining Chair" },
    ["prop_kitch_juicer"] = { model = "prop_kitch_juicer", category = "Kitchen", price = 300, label = "Juicer" },
    ["prop_micro_01"] = { model = "prop_micro_01", category = "Kitchen", price = 500, label = "Microwave" },
    ["prop_fridge_01"] = { model = "prop_fridge_01", category = "Kitchen", price = 1500, label = "Fridge" },
    ["prop_coffee_mac_02"] = { model = "prop_coffee_mac_02", category = "Kitchen", price = 450, label = "Coffee Machine" },
    ["prop_washer_01"] = { model = "prop_washer_01", category = "Kitchen", price = 1400, label = "Washer" },
    ["prop_cooker_03"] = { model = "prop_cooker_03", category = "Kitchen", price = 1100, label = "Cooker" },

    -- BATHROOM (8)
    ["prop_toilet_01"] = { model = "prop_toilet_01", category = "Bathroom", price = 400, label = "Toilet" },
    ["prop_sink_02"] = { model = "prop_sink_02", category = "Bathroom", price = 350, label = "Sink" },
    ["prop_shower_rack_01"] = { model = "prop_shower_rack_01", category = "Bathroom", price = 300, label = "Shower Rack" },
    ["prop_towel_rail_01"] = { model = "prop_towel_rail_01", category = "Bathroom", price = 200, label = "Towel Rail" },
    ["prop_mirror_01"] = { model = "prop_mirror_01", category = "Bathroom", price = 250, label = "Mirror" },
    ["prop_bin_05a"] = { model = "prop_bin_05a", category = "Bathroom", price = 150, label = "Trash Bin" },
    ["prop_toilet_brush_01"] = { model = "prop_toilet_brush_01", category = "Bathroom", price = 100, label = "Toilet Brush" },
    ["prop_table_05"] = { model = "prop_table_05", category = "Boss Office - Desks", price = 1000, label = "Wide Table" },
    ["prop_fbi3_coffee_table"] = { model = "prop_fbi3_coffee_table", category = "Boss Office - Desks", price = 1200, label = "Office Coffee Table" },

    -- DECOR (8)
    ["apa_mp_h_acc_vase_01"] = { model = "apa_mp_h_acc_vase_01", category = "Decor", price = 300, label = "Vase" },
    ["apa_mp_h_acc_plant_palm_01"] = { model = "apa_mp_h_acc_plant_palm_01", category = "Decor", price = 700, label = "Palm Plant" },
    ["apa_mp_h_acc_artwalll_02"] = { model = "apa_mp_h_acc_artwalll_02", category = "Decor", price = 800, label = "Wall Art" },
    ["apa_mp_h_acc_rugwooll_03"] = { model = "apa_mp_h_acc_rugwooll_03", category = "Decor", price = 450, label = "Wool Rug" },
    ["prop_glass_stack_01"] = { model = "prop_glass_stack_01", category = "Decor", price = 150, label = "Glass Stack" },
    ["prop_pot_plant_01a"] = { model = "prop_pot_plant_01a", category = "Decor", price = 350, label = "Small Plant" },
    

    -- BOSS OFFICE - DESKS (8)
    ["apa_mp_h_office_desk_02"] = { model = "apa_mp_h_office_desk_02", category = "Boss Office - Desks", price = 3500, label = "Modern Desk" },
    ["apa_mp_h_yacht_table_01"] = { model = "apa_mp_h_yacht_table_01", category = "Boss Office - Desks", price = 2800, label = "Meeting Table" },
    ["prop_table_02"] = { model = "prop_table_02", category = "Boss Office - Desks", price = 900, label = "Small Table" },
    ["prop_office_desk_01"] = { model = "prop_office_desk_01", category = "Boss Office - Desks", price = 2000, label = "Office Desk" },
    ["prop_table_03"] = { model = "prop_table_03", category = "Boss Office - Desks", price = 850, label = "Wood Table" },
    ["prop_table_04"] = { model = "prop_table_04", category = "Boss Office - Desks", price = 950, label = "Metal Desk" },
    ["prop_office_desk_02"] = { model = "prop_office_desk_02", category = "Boss Office - Desks", price = 2200, label = "Office Desk Large" },
    ["prop_table_05"] = { model = "prop_table_05", category = "Boss Office - Desks", price = 1000, label = "Wide Table" },
    ["prop_fbi3_coffee_table"] = { model = "prop_fbi3_coffee_table", category = "Boss Office - Desks", price = 1200, label = "Office Coffee Table" },

    -- BOSS OFFICE - ELECTRONICS (8)
    ["prop_laptop_01a"] = { model = "prop_laptop_01a", category = "Boss Office - Electronics", price = 1500, label = "Laptop", usable = {type = "bossmenu"} },
    ["prop_monitor_01a"] = { model = "prop_monitor_01a", category = "Boss Office - Electronics", price = 800, label = "Monitor", usable = {type = "bossmenu"} },
    ["prop_pc_01a"] = { model = "prop_pc_01a", category = "Boss Office - Electronics", price = 1200, label = "PC Tower" },
    ["prop_printer_01"] = { model = "prop_printer_01", category = "Boss Office - Electronics", price = 700, label = "Printer" },
    ["prop_office_phone_tnt"] = { model = "prop_office_phone_tnt", category = "Boss Office - Electronics", price = 500, label = "Office Phone" },
    ["hei_prop_hei_bank_mon"] = { model = "hei_prop_hei_bank_mon", category = "Boss Office - Electronics", price = 2500, label = "Multi Monitor Setup" },
    ["prop_cctv_cam_01a"] = { model = "prop_cctv_cam_01a", category = "Boss Office - Electronics", price = 800, label = "CCTV Camera" },

    -- BOSS OFFICE - SEATING (8)
    ["prop_off_chair_01"] = { model = "prop_off_chair_01", category = "Boss Office - Seating", price = 700, label = "Desk Chair" },
    ["v_corp_offchair"] = { model = "v_corp_offchair", category = "Boss Office - Seating", price = 1000, label = "Corporate Chair" },
    ["prop_chair_01a"] = { model = "prop_chair_01a", category = "Boss Office - Seating", price = 300, label = "Basic Chair" },
    ["prop_armchair_01"] = { model = "prop_armchair_01", category = "Boss Office - Seating", price = 850, label = "Armchair" },
    ["prop_chair_04a"] = { model = "prop_chair_04a", category = "Boss Office - Seating", price = 350, label = "Meeting Chair" },
    ["prop_bar_stool_01"] = { model = "prop_bar_stool_01", category = "Boss Office - Seating", price = 250, label = "Bar Stool" },
    ["prop_chair_02"] = { model = "prop_chair_02", category = "Boss Office - Seating", price = 350, label = "Simple Chair" },
    ["prop_chair_06"] = { model = "prop_chair_06", category = "Boss Office - Seating", price = 400, label = "Plastic Chair" },

    -- STORAGE (8) 
    ["prop_boxpile_06b"] = { model = "prop_boxpile_06b", category = "Storage", price = 500, label = "Box Pile", usable = {type = "storage", capacity = 500000, slots = 50}, helpText = "This object allows you to store items up to 50kg capacity and 50 slots." },
    ["prop_box_wood02a_pu"] = { model = "prop_box_wood02a_pu", category = "Storage", price = 300, label = "Wood Box", usable = {type = "storage", capacity = 350000, slots = 30}, helpText = "This object allows you to store items up to 35kg capacity and 30 slots." },
    ["prop_crate_11e"] = { model = "prop_crate_11e", category = "Storage", price = 350, label = "Large Crate", usable = {type = "storage", capacity = 200000, slots = 20}, helpText = "This object allows you to store items up to 20kg capacity and 20 slots." },
    ["prop_ld_int_safe_01"] = { model = "prop_ld_int_safe_01", category = "Storage", price = 2500, label = "Safe", usable = {type = "storage", capacity = 5000, slots = 10}, helpText = "This object allows you to store items up to 5kg capacity and 10 slots." },
    ["prop_mil_crate_01"] = { model = "prop_mil_crate_01", category = "Storage", price = 600, label = "Military Crate", usable = {type = "storage", capacity = 20000, slots = 15}, helpText = "This object allows you to store items up to 20kg capacity and 15 slots." },
    ["prop_cabinet_02b"] = { model = "prop_cabinet_02b", category = "Storage", price = 900, label = "Storage Cabinet", usable = {type = "storage", capacity = 350000, slots = 50}, helpText = "This object allows you to store items up to 35kg capacity and 50 slots." },
    ["prop_boxpile_02c"] = { model = "prop_boxpile_02c", category = "Storage", price = 400, label = "Small Box Pile" },
    ["prop_crate_03a"] = { model = "prop_crate_03a", category = "Storage", price = 300, label = "Wood Crate" },
    ["prop_toolchest_01"] = { model = "prop_toolchest_01", category = "Storage", price = 800, label = "Tool Chest" },

    -- WAREHOUSE (8)
    ["prop_ind_mech_01c"] = { model = "prop_ind_mech_01c", category = "Warehouse", price = 3000, label = "Industrial Machine" },
    ["prop_generator_01a"] = { model = "prop_generator_01a", category = "Warehouse", price = 2800, label = "Generator" },
    ["prop_barrel_02a"] = { model = "prop_barrel_02a", category = "Warehouse", price = 250, label = "Barrel" },
    ["prop_container_05a"] = { model = "prop_container_05a", category = "Warehouse", price = 4000, label = "Shipping Container" },
    ["prop_gas_tank_01a"] = { model = "prop_gas_tank_01a", category = "Warehouse", price = 2200, label = "Gas Tank" },
    ["prop_worklight_03b"] = { model = "prop_worklight_03b", category = "Warehouse", price = 450, label = "Work Light" },
    ["prop_tool_bench02"] = { model = "prop_tool_bench02", category = "Warehouse", price = 1200, label = "Workbench" },
    ["prop_pallet_02a"] = { model = "prop_pallet_02a", category = "Warehouse", price = 300, label = "Pallet" },
    ["prop_barrel_03a"] = { model = "prop_barrel_03a", category = "Warehouse", price = 300, label = "Rusty Barrel" },

}

-- ⚙️ USABLE FURNITURE FUNCTIONS
-- Defines interactions for specific furniture types

Config.UsableFunctions = {
    ['storage'] = {
        label = "Open Storage",
        icon = "fa-solid fa-box", 
        onSelect = function(furnitureId, capacity, slots, label)
            openFurnitureStorage("furniture_storage_" .. furnitureId, capacity, slots, label)
        end,
    },
    ['bossmenu'] = {
        label = "Open Bossmenu",
        icon = "fa-solid fa-skull-crossbones",

        onSelect = function()
            openBossMenu(false, playerOrganisationData.jobId)
        end,
    },
    ['locker'] = {
        label = "Open Locker",
        icon = "fa-solid fa-shirt",

        onSelect = function()
            openCloakRoom()
        end,
    }
}
```

</details>

<details>

<summary>MarketConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- 🧩 CRIME TABLET - MARKET CONFIGURATION
-- ──────────────────────────────────────────────────────────────────────────────
-- Description:
-- This config controls the Market tab inside the Crime Tablet.
-- Players can list and purchase illegal items such as weapons, drugs,
-- and special equipment through a marketplace system.
-- ──────────────────────────────────────────────────────────────────────────────

-- ⚙️ GENERAL MARKET SETTINGS
Config.MarketMisc = {
    enable = true, -- Enable / Disable the Market tab
    requiredGangLevel = 1, -- Minimum gang level required to access the Market
    useDirtyMoney = false, -- If true, transactions use dirty money instead of regular cash
    advertiseFee = 5000, -- Cost to create a new market listing
    advertiseTime = 96, -- Listing duration (in hours)
}

-- 📦 ALLOWED MARKET ITEMS
-- Only items listed here can be sold through the Market

-- 🎨 ITEM CLASSES (itemclass)
-- blue   -> common items
-- purple -> uncommon 
-- red    -> illegal 
-- gold   -> rare 

-- THOSE ITEMS ARE EXAMPLES!
-- To display images properly place them inside: `web/build/items` with the same name as item and in .png extension.

Config.MarketItems = {
    ['spy_binoculars'] = {
        label = "Tactical Binoculars",
        itemclass = "purple",
    },
    ['spy_gps'] = {
        label = "GPS Tracker",
        itemclass = "purple",
    },
    ['spy_cam'] = {
        label = "Hidden Camera",
        itemclass = "red",
    },
    ['spy_motionsensor'] = {
        label = "Motion Sensor",
        itemclass = "blue",
    },
    ['spy_cam_terminal'] = {
        label = "Camera Terminal",
        itemclass = "red",
    },
    ['spy_detector'] = {
        label = "Signal Detector",
        itemclass = "purple",
    },
    ['WEAPON_VINTAGEPISTOL'] = {
        label = "Vintage Pistol",
        itemclass = "red",
    },
    ['WEAPON_SNSPISTOL_MK2'] = {
        label = "SNS Pistol MK2",
        itemclass = "red",
    },
    ['cocaine'] = {
        label = "Cocaine",
        itemclass = "purple",
    },
    ['meth'] = {
        label = "Meth",
        itemclass = "purple",
    },
    ['weed'] = {
        label = "Weed",
        itemclass = "purple",
    },
    ['rope'] = {
        label = "Rope",
        itemclass = "red",
    },
    ['spray_can'] = {
        label = "Spray Can",
        itemclass = "blue",
    },
    ['spray_remover'] = {
        label = "Spray Remover",
        itemclass = "purple",
    },

    ['ammo-9'] = {
        label = "AMMO 9MM",
        itemclass = "purple",
    },
}
```

</details>

<details>

<summary>RaidsConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- Police Raids Configuration
-- (Information) ► Configure Jobs that are allowed to raid gangs
-- ──────────────────────────────────────────────────────────────────────────────

Config.Raids = {

    -- Enable or disable the entire raid system
    enable = true,
    commandName = "startraid",

    -- Jobs that are allowed to start raids
    allowedJobs = {
        ['police'] = {
            minimumGradeToStart = 2, -- Minimum job grade required to start a raid
        },
    },

    -- Cooldown settings
    raidCooldownPerJob  = 2,   -- Cooldown (in hours) per job after starting a raid
    raidCooldownPerGang = 24,  -- Cooldown (in hours) before the same gang can be raided again

    -- Time window when raids are allowed
    raidTime = {

        -- WARNING: Make sure you configured correct Config.TimeZone in MainConfig.lua
        -- INFORMATION: Use 24 hours time format

        startTime = "00:00", -- Raids can start from this hour
        endTime   = "11:00", -- Raids can start until this hour
    },

    -- Display blips for raiding officers
    -- Set to false for more serious RP (no automatic gang location)
    displayBlips = true,

    -- Elements that can be seized during a raid
    raidableElements = {
        stash       = true, -- Gang stash
        money       = true, -- Clean money
        dirty_money = true, -- Dirty money
    },

    -- Admin approval mode
    -- When enabled, an admin must approve each raid manually
    adminMode = {
        enable = false,              -- Enable admin approval requirement
        commandToApprove = "approveraid", -- Command used by admins to approve a raid
    },

    -- Minimum Gang members online
    minimumGangPlayersOnline = 0,
    -- Minimum Job members online
    minimumJobPlayersOnline = 1,

    -- Raid duration
    raidDuration = 30, -- Duration of the raid in minutes

    -- Inform Online Gang Members about Raid.
    informGang = true
}
```

</details>

<details>

<summary>SpySystem.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- 🕵️ SPY SYSTEM CONFIGURATION
-- ──────────────────────────────────────────────────────────────────────────────
-- Description:
-- This configuration controls all spy-related items and mechanics.
-- It includes GPS trackers, motion sensors, spy cameras, binoculars,
-- and detection tools used for surveillance and tracking players.
-- ──────────────────────────────────────────────────────────────────────────────

Config.SpySystem = {
    -- 🚗 CAR GPS TRACKER
    -- Allows players to place a GPS tracker on vehicles
    CarGps = {
        enable = true, -- Enable / Disable this feature
        itemName = "spy_gps", -- Item required to place GPS
        refreshRate = 0.5, -- How often GPS position updates (in seconds)
        gpsMode = "exact", 
        -- "exact"  → shows exact vehicle position
        -- "radius" → shows approximate area (circle)
        blip = {
            radius = 20.0, -- Used only in "radius" mode
            blipId = 724, -- Blip sprite ID
            blipColor = 1, -- Blip color
            blipSize = 0.7 -- Blip scale
        }
    },
    -- 📡 MOTION SENSOR
    -- Detects movement in a specific area
    MotionSensor = {
        enable = true, -- Enable / Disable
        itemName = "spy_motionsensor", -- Required item
        radius = 15.0, -- Detection radius
        prop = {
            enable = true, -- Spawn prop in world
            propName = "prop_spycam" -- Prop model
        },
        blip = {
            blipId = 875,
            blipColor = 3,
            blipSize = 0.7  
        }
    },
    -- 📷 SPY CAMERA
    -- Placeable cameras with remote viewing
    SpyCam = {
        enable = true, -- Enable / Disable
        itemName = "spy_cam", -- Item to place camera
        maxDistance = 250.0, 
        -- Maximum viewing distance (OneSync limitation)
        prop = {
            enable = true, 
            propName = "prop_spycam"
        },
        blip = {
            blipId = 873,
            blipColor = 2,
            blipSize = 0.7  
        },
        terminalItemName = "spy_cam_terminal"
        -- Item used to access camera list and live feed
    },
    -- 🔭 SPY BINOCULARS
    -- Allows long-distance observation of players
    SpyBinoculars = {
        enable = true, -- Enable / Disable
        itemName = "spy_binoculars", -- Required item
        maxDistance = 50.0, -- Maximum usable distance
        enableVoice = true, 
        -- If enabled, you can hear players you are aiming at
    },
    -- 📡 SPY DETECTOR
    -- Detects nearby spy devices (GPS, cameras, sensors)
    SpyDetector = {
        enable = true, -- Enable / Disable
        itemName = "spy_detector", -- Required item
    }
}
```

</details>

<details>

<summary>ServerConfig.lua</summary>

```lua
-- ──────────────────────────────────────────────────────────────────────────────
-- Server-Side Configuration                                                   
-- (Information) ► Core server behaviour, external APIs, and integration options.
-- (Information) ► These settings affect backend operations such as logging, Steam avatar
--        fetching, and optional compatibility modes.
-- ──────────────────────────────────────────────────────────────────────────────
ServerConfig = {}

-- ──────────────────────────────────────────────────────────────────────────────
-- QB Gangs Integration                                                        
-- (Information) ► Enables compatibility mode for qb-gangs data structures.
-- (Information) ► Requires modified versions of qb-core or qbx_core.
-- (Information) ► Refer to documentation before enabling:
--        https://docs.otherplanet.dev/scripts/op-gangs/integrations/gangs-qb-core-qbox
-- ──────────────────────────────────────────────────────────────────────────────
ServerConfig.EnableQBgangsIntegrations = false

-- ──────────────────────────────────────────────────────────────────────────────
-- Steam API Key                                                              
-- (Information) ► Used to fetch player Steam avatars for UI and logs.
-- (Information) ► Optional — leave empty to disable avatar fetching.
-- ──────────────────────────────────────────────────────────────────────────────
ServerConfig.SteamApiKey = "" -- e.g. "YOUR_STEAM_API_KEY"

-- ──────────────────────────────────────────────────────────────────────────────
-- Discord Webhooks                                                            
-- (Information) ► Webhook URLs for sending server logs and admin actions.
-- (Information) ► Leave blank to disable Discord logging.
-- ──────────────────────────────────────────────────────────────────────────────
ServerConfig.DiscordWebHook = ''       -- General logs (boss menu actions, missions, etc.)
ServerConfig.DiscordWebHookAdmin = ''  -- Admin panel logs (bans, wipes, resets)
```

</details>
