# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.otherplanet.dev/scripts/op-gangs/config-files.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
