DRS K9

v1.7.1 drs_k9
Ver na loja

Unidade cinotécnica da polícia: o agente levanta um cão no canil da esquadra, escolhe a raça e o nome, e dá-lhe ordens por um menu — seguir, sentar, deitar, entrar no carro, farejar pessoas e viaturas, e atacar. O cão tem fome e precisa de ração. A deteção é feita pelo servidor, que lê o inventário completo. Funciona com Qbox, QBCore e ESX.

#Requisitos

RecursoObrigatório
oxmysqlSim
Qbox, QBCore ou ESXSim (deteção automática)
ox_inventory ou qb-inventory (nova ou antiga)Sim (farejar e ração)
drs_policejobNão — dá a ração grátis no armeiro e o estado das algemas

#Instalação

  1. Coloca drs_k9 em resources.
  2. Adiciona ao server.cfg, depois do oxmysql, da framework e do inventário:
server.cfg
ensure oxmysql
ensure qb-core
ensure drs_k9
  1. Cria o item dog_food (ver abaixo) e copia a imagem install/images/dog_food.png para o teu inventário.
  2. Em Config.Jobs defines os empregos e o cargo mínimo, em Config.Kennels os canis e em Config.Sniff.Categories o que o cão deteta.

#Item da ração

QBCore — dentro de qb-core/shared/items.lua:

items_qb-core.lua
-- drs_k9: cola dentro de qb-core/shared/items.lua (Qbox: ox_inventory/data/items.lua, ver o outro ficheiro)
-- Imagens: copia install/images/*.png para qb-inventory/html/images/

    dog_food = { name = 'dog_food', label = 'Ração para cão', weight = 500, type = 'item', image = 'dog_food.png', unique = false, useable = false, shouldClose = true, combinable = nil, description = 'Ração para os cães K9 da polícia' },

ox_inventory / Qbox — dentro de ox_inventory/data/items.lua:

items_ox_inventory.lua
-- drs_k9: cola dentro de ox_inventory/data/items.lua
-- Imagens: copia install/images/*.png para ox_inventory/web/images/

    ['dog_food'] = { label = 'Ração para cão', weight = 500, stack = true, close = true, description = 'Ração para os cães K9 da polícia', client = { image = 'dog_food.png' } },

ESX — importa na base de dados:

items_esx.sql
-- drs_k9: executa na base de dados (ESX com a tabela items)
INSERT IGNORE INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES ('dog_food', 'Ração para cão', 1, 0, 1);

Se usas o drs_policejob, a ração já está grátis no armeiro da polícia.

#Como funciona

#Canil

O cão levanta-se e entrega-se no canil da esquadra (marcador azul no estacionamento, Config.Kennels). Aí escolhes a raça (Config.Breeds: Pastor Alemão, Rottweiler, Husky, Retriever) e o nome. Só pode ter cão quem tiver o emprego e o cargo de Config.Jobs e estiver de serviço.

/k9 (ou a tecla de Config.Key) abre o menu com:

OrdemO que faz
SeguirO cão segue o agente
Sentar / DeitarFica parado nessa posição
PararCancela a ordem atual
Farejar pessoaFareja o jogador mais perto
Farejar veículoFareja a viatura mais perto (mala, porta-luvas e ocupantes)
Abrir porta — entrarPõe o cão no carro
Dar raçãoAlimenta o cão
AtacarManda o cão atacar um alvo

#Entrar e sair do carro

  1. Fica junto à porta do pendura ou de uma porta de trás e escolhe "Abrir porta — entrar".
  2. A porta abre, o cão entra e senta-se nesse banco, e a porta fecha-se.
  3. Para sair, abre a porta do banco onde ele está.

A relação porta → banco está em Config.Vehicle.Doors.

#Farejar

O servidor lê o inventário todo — da pessoa, ou da mala, do porta-luvas e dos ocupantes da viatura — e compara com as categorias de Config.Sniff.Categories:

CategoriaExemplos
drugsjoint, meth, weed_*, tudo o que tenha coke, heroin, xtc…
chemicalsacetone, ephedrine, *_acid…
weaponsweapon_*, *_ammo, c4, thermite
moneymarkedbills, black_money, dirtymoney

Cada categoria tem items (nomes exatos) e patterns (padrões Lua no nome: '^weed_' = começa por weed_, 'xtc' = contém xtc). A lista Ignore nunca conta (lanterna, bastão, kits de limpeza, nomes parecidos). Com ShowCategory = true, o agente vê o que o cão sentiu. Há um tempo de espera entre farejadelas (Cooldown).

Para acrescentar um item teu:

config.lua
drugs = {
    enabled = true,
    items = { 'joint', 'meth', 'o_teu_item' },
    patterns = { '^weed_', 'coke' },
},

#Atacar

Escolhe Atacar no menu, aponta com o botão direito do rato para o alvo e carrega em E. O cão ataca até Config.Attack.MaxDistance metros e nunca ataca pessoas algemadas. Com OnlyPlayers = true, não ataca NPCs.

#Fome

Com Config.Hunger.Enabled, Minutes minutos depois de o levantares (ou de lhe dares ração), o cão fica com fome: não fareja nem ataca até comer dog_food ou até o trocares no canil. Recebes um aviso WarnBefore minutos antes.

#Opções principais

OpçãoPor defeitoDescrição
Config.Locale'pt'Idioma: pt ou en
Config.Jobspolice = 1, sheriff = 1Empregos e cargo mínimo
Config.RequireDutytrueSó de serviço
Config.Command'k9'Comando do menu
Config.Key''Tecla do menu (vazio = só comando)
Config.Hunger.Minutes10Minutos até ter fome
Config.Sniff.Distance3.0Distância para farejar
Config.Sniff.ShowCategorytrueMostra o que o cão sentiu
Config.Attack.EnabledtruePermite atacar
Config.Attack.MaxDistance40.0Distância máxima do ataque

#Configuração completa

config.lua
Config = {}

-- Idioma / Language: 'pt' ou 'en'
Config.Locale = 'pt'
Config.Framework = 'auto'
Config.UseOxNotify = false
Config.StaffGroups = { 'god', 'admin', 'superadmin' }
Config.Debug = false

-- Quem pode ter cão: emprego = cargo mínimo / Who can have a dog: job = minimum grade
Config.Jobs = { police = 1, sheriff = 1 }
Config.RequireDuty = true

-- Abrir o menu do cão / Open the dog menu
Config.Command = 'k9'
Config.Key = ''                 -- ex.: 'F9' ('' = só o comando) / e.g. 'F9' ('' = command only)

-- Raças (o agente escolhe no canil) / Breeds (picked at the kennel)
Config.Breeds = {
    { model = 'a_c_shepherd',   label = 'Pastor Alemão' },
    { model = 'a_c_rottweiler', label = 'Rottweiler' },
    { model = 'a_c_husky',      label = 'Husky' },
    { model = 'a_c_retriever',  label = 'Retriever' },
}
Config.DefaultName = 'Rex'

-- ------------------------------------------------------------------ canil / kennel
-- O cão levanta-se e entrega-se aqui (estacionamento das esquadras)
-- The dog is picked up and returned here (station parking lots)
Config.Kennels = {
    { label = 'Canil — Mission Row', coords = vector3(457.20, -1017.60, 28.40) },
    { label = 'Canil — Paleto Bay',  coords = vector3(-454.80, 6008.80, 31.34) },
}
Config.KennelDistance = 2.0
Config.KennelBlip = { sprite = 442, color = 3, scale = 0.6 }
Config.Marker = { type = 2, size = 0.3, color = { 59, 130, 246, 180 }, drawDistance = 12.0 }

-- ------------------------------------------------------------------ fome / hunger
-- O cão tem de comer de X em X minutos (ou ser trocado no canil). Com fome não fareja nem ataca.
-- The dog must eat every X minutes (or be swapped at the kennel). Hungry dogs don't sniff or attack.
Config.Hunger = {
    Enabled = true,
    Minutes = 10,
    WarnBefore = 2,             -- aviso X minutos antes / warning X minutes before
    Item = 'dog_food',          -- item para o alimentar (grátis no armeiro da polícia) / feeding item
    FeedDistance = 3.0,
}

-- ------------------------------------------------------------------ viatura / vehicle
-- O agente abre a porta e o cão entra no banco dessa porta. Portas: 1 = pendura, 2 = trás esquerda, 3 = trás direita
-- The officer opens the door and the dog gets in that seat. Doors: 1 = front passenger, 2 = rear left, 3 = rear right
Config.Vehicle = {
    DoorDistance = 1.8,         -- distância do agente à porta / officer distance to the door
    Doors = { [1] = 0, [2] = 1, [3] = 2 }, -- porta = banco / door = seat
}

-- ------------------------------------------------------------------ farejar / sniff
Config.Sniff = {
    Distance = 3.0,             -- distância à pessoa ou ao veículo / distance to the person or vehicle
    Seconds = 6,
    Cooldown = 20,              -- segundos entre farejadelas / seconds between sniffs
    -- Diz ao agente o que o cão sentiu (drogas, químicos...) / Tell the officer what the dog smelled
    ShowCategory = true,

    -- O servidor lê o inventário todo e compara com estas categorias.
    -- items = nomes exatos | patterns = padrões Lua no nome (ex.: '^weed_' = começa por weed_, 'xtc' = contém xtc)
    -- The server reads the whole inventory and matches these categories.
    -- items = exact names | patterns = Lua patterns on the name (e.g. '^weed_' = starts with weed_, 'xtc' = contains xtc)
    Categories = {
        drugs = {
            enabled = true,
            items = { 'joint', 'oxy', 'meth', 'methbags', 'shrooms', 'coca_leaf', 'poppyresin', 'drycannabis', 'wetcannabis',
                'grindedweed', 'leanblunts', 'leanbluntwrap', 'leancup', 'cupoflean', 'mdlean', 'crackrock' },
            patterns = { '^weed_', 'coke', 'crack', 'heroin', 'xtc', 'lsd', 'baggy', 'meth', 'cannabis', 'cocaine', 'ecstasy', 'opium', 'codeine' },
        },
        chemicals = {
            enabled = true,
            items = { 'acetone', 'ephedrine', 'lysergic_acid', 'sulfur', 'saltpeter', 'gunpowder', 'ammonia', 'lithium',
                'methylamine', 'hydrochloric_acid', 'sodium_hydroxide', 'iodine', 'red_phosphorus', 'toluene', 'pseudoephedrine' },
            patterns = { 'chemical', '_acid$', 'phosphor' },
        },
        weapons = {
            enabled = true,
            items = { 'thermite', 'c4', 'explosive', 'pipe_bomb' },
            patterns = { '^weapon_', '_ammo$' },
        },
        money = {
            enabled = true,
            items = { 'markedbills', 'dirtymoney', 'black_money', 'dirty_money' },
            patterns = {},
        },
    },

    -- Nunca contam (ferramentas, objetos da polícia, coisas com nomes parecidos)
    -- Never count (tools, police gear, look-alike names)
    Ignore = {
        'gatecrack', 'weedgrinder', 'weed_nutrition', 'empty_weed_bag', 'cleaning_kit', 'cleaningkit',
        'weapon_flashlight', 'weapon_nightstick', 'weapon_stungun', 'weapon_fireextinguisher', 'weapon_petrolcan',
        'weapon_flare', 'weapon_ball', 'weapon_snowball', 'weapon_parachute', 'weapon_unarmed',
    },
}

-- ------------------------------------------------------------------ ataque / attack
Config.Attack = {
    Enabled = true,
    MaxDistance = 40.0,
    -- Só ataca jogadores algemados? Nunca. Só ataca quem não está algemado / Never attacks cuffed players
    OnlyPlayers = false,        -- true = só jogadores (não NPCs) / players only
}

#Integrações (ficheiro aberto)

O server/editable.lua não é encriptado:

FunçãoPara que serve
Hooks.OnDutySaber se o agente está de serviço
Hooks.IsCuffedSaber se o alvo está algemado (o cão não ataca)
Hooks.PlayerItemsLer o inventário de uma pessoa
Hooks.VehicleItemsLer a mala e o porta-luvas de uma viatura

Se usas um inventário que não seja o ox_inventory ou o qb-inventory, adapta o PlayerItems e o VehicleItems.

#Resolução de problemas

Não aparece o canil — o marcador só aparece a quem tem o emprego e cargo de Config.Jobs e está de serviço.

O cão não fareja nem ataca — está com fome. Dá-lhe dog_food pelo menu ou troca-o no canil.

O cão não encontra nada — confirma que o nome do item está em items ou bate com um pattern da categoria, e que não está na lista Ignore. Se usas outro inventário, adapta o server/editable.lua.

O cão não entra no carro — tens de estar a menos de Config.Vehicle.DoorDistance metros da porta do pendura ou de uma porta de trás.