> For the complete documentation index, see [llms.txt](https://andrew-grenade.gitbook.io/sheen-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://andrew-grenade.gitbook.io/sheen-scripts/paid-resources/sh-k9/configuration.md).

# Configuration

{% code title="config.lua" expandable="true" %}

```lua
-- ╔══════════════════════════════════════════════════════════════════════════╗
-- ║  K9  -  MAIN CONFIG                                                      ║
-- ╚══════════════════════════════════════════════════════════════════════════╝

return {

    -- ─── GENERAL ──────────────────────────────────────────────────────────

    -- Language file to load from the locales/ folder ('en' -> locales/en.lua).
    lang = 'en',

    -- How on-screen messages appear:  'ox' |  'native'
    -- or edit it to use your own notification system (see bridge/client/utils.lua).
    notify = 'ox',

    -- ─── DOG MANAGEMENT ───────────────────────────────────────────────────

    -- How many K9 units one player can own (register).
    max_dogs = 3,

    -- When dog gets deleted.
    delete_dog = {
        dog_dead   = false,  -- true = delete the dog when it dies 
        owner_dead = false,  -- true = delete the dog when its owner dies
    },

    -- ─── SPAWN AREAS ──────────────────────────────────────────────────────
    -- Restrict WHERE players can deploy their K9. When enabled, a dog can only be
    -- spawned inside one of the areas below (e.g. police stations).
    spawn_areas = {
        enable        = false,  -- false = dogs can be spawned anywhere
        require_house = false,  -- true = a dog house must be placed in the area first

        -- Each entry: a circle on the map.  radius = size (units), coords = center.
        areas = {
            { radius = 30.0, coords = vector3(432.3, -981.64, 30.71) }, -- Mission Row PD
            { radius = 30.0, coords = vector3(-448.5, 6014.1, 31.7) },  -- Paleto Bay PD
            { radius = 30.0, coords = vector3(1859.6, 3689.8, 34.2) },  -- Sandy Shores PD
        },
    },

    -- ─── STATUS: HEALTH / ARMOR / HUNGER / THIRST ─────────────────────────
    status = {
        maxArmor = 100,   -- the most armor a dog can have

        -- true = never save or restore HP/armor (the dog always spawns at full health).
        disable_hp_and_armor_saving = false,

        -- Healing / reviving the dog.
        heal = {
            revive_timer = 3,                      -- seconds the revive takes
            timer        = 3,                      -- seconds each heal tick takes
            amount       = { from = 10, to = 25 }, -- random HP restored per heal
        },

        -- Applying armor to the dog.
        armor = {
            timer  = 3,                            -- seconds the animation takes
            amount = { from = 10, to = 25 },       -- random armor added
        },

        -- Hunger & thirst drain, and feeding.
        feed = {
            thirst      = { from = 0.1, to = 1.0 }, -- random thirst drained per tick
            hunger      = { from = 0.1, to = 1.0 }, -- random hunger drained per tick
            warning     = 20,                       -- warn the owner once below this %
            get_damaged = true,                     -- true = dog loses HP when hunger/thirst reach 0%
        },
    },

    -- ─── COMBAT ───────────────────────────────────────────────────────────

    -- Damage a K9 bite deals, as a multiplier (affects ALL animals server-wide).
    -- Note: GTA one-shots any ped sitting at exactly 100 HP (or close). Dog default max HP is 200.
    damage_modifier = 1.0,   -- range 0.01 - 1.0 (default)

    -- true = instant kill.
    insta_headshot = true,

    -- Tackle: the dog can knock a target to the ground.
    -- If players health is close to 100HP, the dog will instakill
    tackle = {
        enable = true,
        chance = 50,   -- % chance to tackle (ignored when the level system is active)
        type   = 2,    -- 1 = play an animation  |  2 = ragdoll the target
    },

    -- Speed boost while the dog runs (BETA - may conflict with anti-cheat).
    speeding = {
        enable = false,
        value  = 1.5,   -- run-speed multiplier, range 1.0 - 2.0
    },

    -- ─── TRACKING ─────────────────────────────────────────────────────────
    -- The dog follows a scent trail to a target.
    tracking = {
        radius   = 75.0,  -- how far around the player a trail can be picked up (units)
        speed    = 2.0,   -- dog move-speed while tracking (ignored when the level system is active)
        cooldown = 3,     -- minutes before tracking can be used again (0 = no cooldown)
    },

    -- ─── SEARCH (DETECT ITEMS) ────────────────────────────────────────────
    -- The dog searches a player or vehicle for illegal items.
    search = {
        -- true = automatically flag every weapon_ item (needs inventory).
        all_weapons = true,

        -- Extra items to detect.  Format:  item_name = 'category'
        items = {
            thermite      = 'explosives',
            weed_brick    = 'drugs',
            cocaine_brick = 'drugs',
            weapon_pistol = 'weapons',
        },

        -- The message shown for each category when something is found.
        item_types = {
            explosives = 'Smells like explosives...',
            drugs      = 'Smells like drugs...',
            weapons    = 'Smells like a weapon...',
        },

        search_time = 3,       -- seconds a search takes
        onSuccess   = 'bark',  -- what the dog does on a find: 'bark' | 'sit' | 'laydown' | false

        -- Searching a player.
        player = {
            chance = 30,   -- % chance to find something (ignored when the level system is active)
        },

        -- Searching a vehicle.
        vehicle = {
            open_doors = false,  -- true = open the vehicle's door during the search
            chance     = 30,     -- % chance to find something (ignored when the level system is active)
        },
    },

    -- ─── VEHICLE ENTRY ────────────────────────────────────────────────────¨
    -- Switches animation when the dog enters vans (e.g. rumpo, speedo) vs regular cars. Add more van models
    -- Add more models as  [`modelname`] = true.
    van_vehicles = {
        [`rumpo`]   = true, [`rumpo2`]  = true,
        [`speedo`]  = true, [`speedo2`] = true,
        [`speedo3`] = true, [`policet`] = true,
    },

    -- ─── LEASH ───────────────────────────────────────────────────────────
    leash = {
        type       = 5,    -- rope style (do NOT use 0 - it crashes the game!)
        max_length = 5.0,  -- how far the dog can move from you while leashed (units)
    },

    -- ─── ITEM REQUIREMENTS ───────────────────────────────────────────────
    -- Require the player to carry an item to use each feature.
    --   false = no item needed   |   'item_name' = that item is required
    items = {
        ball    = false,
        frisbee = false,
        camera  = false,
        armor   = false,
        feed    = false,
        gps     = false,
        leash   = false,
        heal    = false,
        medkit  = false,
    },

    -- ─── PROPS (OBJECT MODELS) ───────────────────────────────────────────
    -- In-game object models used by certain features. Backticks `` = model hash.
    props = {
        food    = `v_res_mbowl`,      -- bowl placed when feeding
        ball    = `w_am_baseball`,    -- thrown ball
        frisbee = `p_ld_frisbee_01`,  -- thrown frisbee
        house   = `prop_doghouse_01`, -- placed dog house
    },

    -- ─── CONTROLS - K9 CAMERA ───────────────────────────────────────────
    -- Control IDs used while looking through the dog's mounted camera.
    -- Full list of IDs: https://docs.fivem.net/docs/game-references/controls/
    -- Arrow keys and mouse wheel keys are used
    camera_controls = {
        up       = 172,
        down     = 173,
        left     = 174,
        right    = 175,
        cancel   = 177,
        zoomUp   = 241,
        zoomDown = 242,
    },

    -- ─── CONTROLS - KEYBINDS ────────────────────────────────────────────
    -- key = '' registers an EMPTY bind: nothing is bound by default, but it shows
    -- up under Settings > Key Bindings > FiveM so each player can set their own.
    -- Put a letter (e.g. 'K') to give it a default key.
    binding_system = {
        enable = true,
        commands = {
            { name = 'main_menu',        key = '',  label = 'K9: Menu' },
            { name = 'target_mode',      key = '',  label = 'K9: Target Mode' },
            { name = 'follow',           key = '',  label = 'K9: Follow / Stop' },
            { name = 'vehicle',          key = '',  label = 'K9: Enter / Exit Vehicle' },
            { name = 'leash',            key = '',  label = 'K9: Leash' },
            { name = 'track',            key = '',  label = 'K9: Track' },
            { name = 'track_by_vehicle', key = '',  label = 'K9: Track by Vehicle' },
            { name = 'search_player',    key = '',  label = 'K9: Search Player' },
            { name = 'search_car',       key = '',  label = 'K9: Search Vehicle' },
            { name = 'carry',            key = '',  label = 'K9: Carry' },
            { name = 'settings',         key = '',  label = 'K9: Settings' },
            { name = 'player_mode',      key = '',  label = 'K9: Player Mode' },
        },
    },

    -- ─── CONTROLS - COMMAND NAMES ───────────────────────────────────────
    -- The chat command typed without the leading slash.  e.g. main_menu = 'k9' -> /k9
    commands = {

        -- Core
        register_dog = 'k9register',
        main_menu    = 'k9',
        save_dog     = 'k9save',
        player_mode  = 'k9player',
        settings     = 'k9settings',

        -- Orders
        follow           = 'k9follow',
        lead             = 'k9lead',
        vehicle          = 'k9vehicle',
        search_player    = 'k9searchped',
        search_car       = 'k9searchcar',
        leash            = 'k9leash',
        heal             = 'k9heal',
        armor            = 'k9armor',
        track            = 'k9trackall',
        track_by_vehicle = 'k9trackveh',
        target_mode      = 'k9target',

        -- Activities
        house       = 'k9house',
        enter_house = 'k9enterhouse',
        ball        = 'k9ball',
        frisbee     = 'k9frisbee',
        fetch       = 'k9fetch',
        gps         = 'k9gps',
        feed        = 'k9feed',
        carry       = 'k9carry',

        -- Camera
        toggle_camera = 'k9camera',
        mount_camera  = 'k9mount',

        -- Tricks / emotes
        sit      = 'k9sit',
        laydown  = 'k9lay',
        bark     = 'k9bark',
        indicate = 'k9indicate',
        sniff    = 'k9sniff',
        beg      = 'k9beg',
        paw      = 'k9paw',
        petting  = 'k9petting',
    },
}

```

{% endcode %}

{% code title="k9player.lua" expandable="true" %}

```lua
-- ╔══════════════════════════════════════════════════════════════════════════╗
-- ║  K9 PLAYER MODE  -  CONFIG                                               ║
-- ╚══════════════════════════════════════════════════════════════════════════╝

return {
    -- Allow players to transform into a dog. false = feature disabled entirely.
    enable = true,

    -- How the player's original look (model + clothes) is restored when they
    -- leave dog form. Pick ONE method:
    --   'clone'   -> standalone: copy the ped before transforming and restore it
    --               afterwards (no clothing resource needed - works everywhere)
    --   'auto'    -> detect a running appearance resource and use its reload.
    --               illenium-appearance / qb-clothing / fivem-appearance.
    --               Falls back to 'clone' if none is found.
    --   'command' -> run a console command:  ExecuteCommand(command)
    --   'event'   -> fire a client event:    TriggerEvent(event)
    --   'export'  -> call an export:          exports[export.resource][export.fn]()
    restore_skin = {
        method = 'clone',

        command = 'reloadskin',                 -- used when method = 'command'
        event   = 'client:LoadSkin',            -- used when method = 'event'
        export  = { resource = '', fn = '' },   -- used when method = 'export'
    },

    search = {
        chance      = 50,   -- % chance the dog reveals a real find (0 = never, 100 = always)
        search_time = 3,    -- seconds the sniff animation takes
    },

    -- Scent mode (follow glowing trails to nearby targets while in dog form).
    tracking = {
        radius          = 150.0, -- how far around you scents are picked up (units)
        max_trails      = 8,     -- max trails shown at once (closest targets first)
        reveal_distance = 14.0,  -- only the trail within this distance of you shows
    },

    -- Restrict WHERE players can turn into a dog (and turn back)
    area = {
        enable = false,  -- false = players can transform anywhere

        -- Each entry: a circle on the map.  radius = size (units), coords = center.
        areas = {
            { radius = 30.0, coords = vector3(432.3, -981.64, 30.71) }, -- Mission Row PD
            { radius = 30.0, coords = vector3(-448.5, 6014.1, 31.7) },  -- Paleto Bay PD
            { radius = 30.0, coords = vector3(1859.6, 3689.8, 34.2) },  -- Sandy Shores PD
        },
    },
}

```

{% endcode %}

{% code title="levels.lua" expandable="true" %}

```lua
return {
    -- Set to true to disable the level system entirely
    disable = false,

    --[[
        XP per action - configure which actions reward XP and how much.

        enabled  - set to false to disable XP for that action entirely
        from/to  - random XP range awarded on success
        chance   - % chance (0-100) to receive XP for this action
    ]]
    xp_actions = {
        command  = { enabled = true,  chance = 70, from = 3,  to = 10 }, -- follow, vehicle, leash, gps, ...
        attack   = { enabled = true,  chance = 80, from = 5,  to = 15 }, -- successful tackle
        search   = { enabled = true,  chance = 90, from = 8,  to = 20 }, -- found contraband/weapon
        tracking = { enabled = true,  chance = 90, from = 8,  to = 20 }, -- reached tracked target
        fetch    = { enabled = true,  chance = 80, from = 3,  to = 8  }, -- brought ball/frisbee back
        trick    = { enabled = true,  chance = 60, from = 1,  to = 5  }, -- sit, bark, beg, sniff, etc.
    },

    --[[
        Level definitions
        Each level unlocks better stats (tackle_chance, track_speed, fail).

        xp           - cumulative XP required to reach this level
        tackle_chance - % chance to tackle on attack
        track_speed  - movement speed while tracking (1.0 - 5.0)
        fail         - % chance the dog ignores a command (lower is better)
    ]]
    levels = {
        [1]  = { xp = 0,    tackle_chance = 10, track_speed = 1.0, fail = 50 },
        [2]  = { xp = 100,  tackle_chance = 15, track_speed = 1.2, fail = 40 },
        [3]  = { xp = 250,  tackle_chance = 20, track_speed = 1.4, fail = 30 },
        [4]  = { xp = 500,  tackle_chance = 25, track_speed = 1.6, fail = 25 },
        [5]  = { xp = 850,  tackle_chance = 30, track_speed = 1.8, fail = 20 },
        [6]  = { xp = 1300, tackle_chance = 35, track_speed = 2.0, fail = 15 },
        [7]  = { xp = 1900, tackle_chance = 40, track_speed = 2.3, fail = 11 },
        [8]  = { xp = 2700, tackle_chance = 45, track_speed = 2.6, fail = 7  },
        [9]  = { xp = 3700, tackle_chance = 50, track_speed = 3.0, fail = 4  },
        [10] = { xp = 5000, tackle_chance = 60, track_speed = 3.5, fail = 1  },
    },
}

```

{% endcode %}

{% code title="restrictions.lua" expandable="true" %}

```lua
-- ╔══════════════════════════════════════════════════════════════════════════╗
-- ║  K9 — RESTRICTIONS                                                       ║
-- ╚══════════════════════════════════════════════════════════════════════════╝

return {
    -- Use server ACE permissions instead of the jobs list below.
    --   add_ace k9 k9 allow
    --   add_principal identifier.license:XXXXXXXX k9
    use_ace_perms = false,

    -- Discord role check — set it up in config/discord.lua
    -- (there set Discord.enable = true to turn it on).

    -- Framework job + grade restrictions (ESX / QB / QBX / ND).
    -- Format:  ['jobname'] = { list of allowed grade numbers }
    jobs = {
        ['police'] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
        -- ['sheriff'] = {2, 3, 4},
    },
}

```

{% endcode %}

{% code title="dogs.lua" expandable="true" %}

```lua
-- Dog breeds and appearance configuration

return {
    -- ─── BREEDS ──────────────────────────────────────────────────────────────
    -- Each entry defines a spawnable K9 breed.  `model` = the GTA ped model name.
    --
    -- IMPORTANT: only use dog models that support attack animations. Most civilian
    -- dog models can't attack and will break the K9. The two base-game models
    -- below always work; others need their model resource installed first.

    [1] = { label = 'Rottweiler',      model = 'a_c_rottweiler' },
    [2] = { label = 'German Shepherd', model = 'a_c_shepherd' },

    -- Premium Belgian Malinois (needs the 'malinois' model resource installed).
    -- Purchase: https://moubys-dog-house.tebex.io/package/6260956
    -- Uncomment to enable:
    -- [3] = { label = 'Malinois', model = 'malinois' },

    -- ─── APPEARANCE ──────────────────────────────────────────────────────────
    --
    -- Keyed by model name (string).  Each model can have multiple named sections:
    --   'default'         -> always visible (no extra resource needed)
    --   'resource_name'   -> only visible when that FiveM resource is started
    --
    -- Each option:
    --   label      = display name shown in the menu
    --   component  = ped component slot (0-11)
    --   drawable   = drawable variation index
    --   textures   = array of valid texture indices  e.g. {0, 1, 2}
    --   tex_labels = optional per-texture display names (same length as textures).
    --                Placeholder numbers below - rename them to whatever you like.
    --
    -- HOW TO FIND VALUES:
    --   1. Spawn your K9 in-game
    --   2. Run command:  /k9devappearance
    --   3. Check client console (F8) for component/drawable/texture data
    --   4. Test combinations and add working ones here

    appearance = {

        -- ── ROTTWEILER ───────────────────────────────────────────────────────
        ['a_c_rottweiler'] = {
            default = {
                {
                    label     = 'Skin',
                    component = 4,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                    tex_labels = { 'Black', 'Brown', 'Mixed' },
                },
                {
                    label     = 'Collar Style',
                    component = 3,
                    drawable  = 0,
                    textures  = { 0, 1, 2, 3 },
                    tex_labels = { 'Green', 'Black', 'Brown', 'Blue' },
                },
                {
                    label     = 'No Collar',
                    component = 3,
                    drawable  = 1,
                    textures  = { 0 },
                },
            },
        },

        -- ── GERMAN SHEPHERD ──────────────────────────────────────────────────
        ['a_c_shepherd'] = {
            default = {
                {
                    label     = 'Skin',
                    component = 0,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
            },

            -- FREE add-on resource (folder must be named 'k9_model'):
            -- https://forum.cfx.re/t/how-to-german-shepherd-malinois-k9-dog-1-0-1/1065040
            k9_model = {
                {
                    label     = 'Skin',
                    component = 0,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
                {
                    label     = 'Vest Color',
                    component = 3,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
                {
                    label     = 'Vest Type',
                    component = 8,
                    drawable  = 0,
                    textures  = { 0, 1, 2, 3 },
                },
            },

            -- PREMIUM add-on resource (folder must be named 'riley'):
            -- https://moubys-dog-house.tebex.io/package/5176462
            riley = {
                {
                    label     = 'Skin',
                    component = 0,
                    drawable  = 0,
                    textures  = { 0, 1 },
                },
                {
                    label     = 'No Vest',
                    component = 3,
                    drawable  = 1,
                    textures  = { 0 },
                },
                {
                    label     = 'Vest Type',
                    component = 3,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
            },
        },

        -- ── BELGIAN MALINOIS (premium 'malinois' resource) ───────────────────
        -- Only shows when the 'malinois' resource is started. Enable the breed
        -- in the BREEDS list above to actually spawn it.
        ['malinois'] = {
            malinois = {
                {
                    label     = 'Skin',
                    component = 0,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
                {
                    label     = 'No Vest',
                    component = 3,
                    drawable  = 1,
                    textures  = { 0 },
                },
                {
                    label     = 'Vest Type',
                    component = 3,
                    drawable  = 0,
                    textures  = { 0, 1, 2 },
                },
            },
        },
    },
}

```

{% endcode %}
