DRS Prison

v1.9.4 drs_prison
Ver na loja

Prisão completa na Bolingbroke: penas contadas no servidor e guardadas na base de dados, trabalhos que reduzem a pena, loja paga com créditos, cantina grátis, pertences confiscados e devolvidos, e fugas com alerta à polícia e mandado de captura automático. Substitui o qb-prison e aceita os mesmos eventos. Funciona com Qbox, QBCore e ESX.

#Requisitos

RecursoObrigatório
oxmysqlSim
Qbox, QBCore ou ESXSim (deteção automática)
qb-inventory ou ox_inventorySim (confiscar e devolver itens)
drs_dispatch ou ps-dispatchNão — alerta de fuga
drs_mdtNão — mandado de captura, lista de reclusos e registo prisional
drs_policejobNão — o menu F6 manda para a prisão

#Instalação

  1. Desliga o qb-prison. O drs_prison tem provide 'qb-prison' e trata o evento prison:client:Enter, por isso o qb-ambulancejob, os MDTs antigos e outros scripts continuam a funcionar. As penas que já estavam no metadata.injail passam para cá sozinhas.
  2. Coloca drs_prison em resources.
  3. Adiciona ao server.cfg, depois do oxmysql, da framework e do inventário:
server.cfg
ensure oxmysql
ensure qb-core
ensure drs_prison
  1. As tabelas drs_prison (penas em curso) e drs_prison_log (histórico) são criadas sozinhas no arranque.
  2. Ajusta o tempo por mês, os trabalhos, a loja e as fugas no config.lua.

#Comandos

ComandoQuem podeO que faz
/prender [id] [meses] [motivo]Staff, ou polícia de serviço com o cargo de Config.PoliceJobs, a menos de Config.JailDistance metrosManda para a prisão
/libertar [id]Staff (ACE drs.prison)Liberta um preso
/penaO presoMostra o tempo que falta

Os nomes dos comandos estão em Config.Commands. Para dares a ACE ao staff:

server.cfg
add_ace group.admin drs.prison allow

Também podem mandar para a prisão: o menu F6 do drs_policejob, o botão "Aplicar pena" do drs_mdt, e qualquer script que use o evento do qb-prison.

#Como funciona

#Entrada

  1. O preso é levado para uma cela aleatória (Config.Spawns) e veste a farda (Config.Outfit).
  2. Com Config.Items.Confiscate = true, os itens são guardados na base de dados — exceto os de Config.Items.Keep (ex.: cartão de cidadão) — e recebe os itens de Config.Items.Starter.
  3. Aparece o HUD com o tempo que falta.

#A pena

  • Cada mês de pena dura Config.MinutesPerMonth minutos reais (por defeito, 1 mês = 1 minuto).
  • O tempo é contado no servidor. Se o preso sair do servidor, a pena fica guardada e continua quando voltar. Com Config.OfflineCounts = true, o tempo também passa offline.

#Trabalhos

No quadro (Config.Points.board) o preso vê o tempo, escolhe um trabalho e abre a loja. Cada tarefa aparece marcada no mapa e tem uma animação.

TrabalhoReduzCréditosDuração
Eletricista1 mês310 s
Limpeza1 mês212 s
Jardinagem1 mês212 s

A pena nunca desce abaixo de Config.JobsMinimumLeft meses por causa dos trabalhos. Podes acrescentar trabalhos novos em Config.Jobs:

config.lua
Config.Jobs = {
    kitchen = {
        label = 'Cozinha', icon = 'fas fa-utensils', reduce = 1, credits = 2, seconds = 12,
        scenario = 'PROP_HUMAN_BBQ',
        spots = { vector3(1781.0, 2563.0, 45.67) },
    },
}

reduce = meses tirados por tarefa, credits = créditos ganhos, seconds = duração. A animação pode ser anim = { dict, clip } ou scenario.

#Loja e cantina

  • Loja (Config.Shop): comprada com os créditos dos trabalhos.
  • Cantina (Config.Points.canteen): comida e água grátis, de Config.Canteen.Cooldown em Config.Canteen.Cooldown segundos.

#Saída

No fim da pena, o preso sai em Config.Release, volta a ter a roupa civil e recebe os itens de volta.

#Fugas

Sair do círculo Config.Area é fuga. Com Config.Escape.Allowed = true:

  • a polícia recebe um alerta no drs_dispatch (AlertPolice);
  • é criado um mandado de captura no drs_mdt (Warrant);
  • quem foge perde os itens guardados (a não ser que Config.Items.ReturnOnEscape = true).

Com Config.Escape.Allowed = false, quem sai do círculo volta para uma cela. Depois de entrar há GraceSeconds segundos sem verificação.

#Opções principais

OpçãoPor defeitoDescrição
Config.Locale'pt'Idioma: pt ou en
Config.MinutesPerMonth1.0Minutos reais por mês de pena
Config.MaxMonths300Pena máxima
Config.OfflineCountsfalseO tempo passa offline
Config.Items.ConfiscatetrueTira os itens à entrada
Config.JobsMinimumLeft1Mínimo que fica depois dos trabalhos
Config.Escape.AllowedtruePermite fugas
Config.Escape.WarranttrueMandado no MDT ao fugir
Config.PoliceJobspolice = 1, sheriff = 1Quem pode usar /prender
Config.Webhook''Webhook do Discord (entradas, saídas, fugas)

#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

-- ------------------------------------------------------------------ pena / sentence
-- Minutos reais por cada "mês" de pena / Real minutes for each sentence "month"
Config.MinutesPerMonth = 1.0
Config.MaxMonths = 300
-- O tempo passa com o jogador offline? / Does time pass while the player is offline?
Config.OfflineCounts = false

-- ------------------------------------------------------------------ prisão / prison (Bolingbroke)
-- Sair deste círculo = fuga / Leaving this circle = escape
Config.Area = { center = vector3(1693.0, 2560.0, 45.5), radius = 185.0 }

Config.Spawns = {
    vector4(1661.05, 2524.68, 45.56, 260.5),
    vector4(1650.81, 2540.58, 45.56, 230.4),
    vector4(1654.96, 2545.54, 45.56, 230.4),
    vector4(1697.11, 2525.56, 45.56, 187.2),
    vector4(1673.08, 2519.82, 45.56, 229.5),
    vector4(1666.03, 2511.37, 45.56, 233.9),
    vector4(1691.23, 2509.64, 45.56, 52.4),
    vector4(1770.59, 2536.06, 45.56, 258.1),
    vector4(1768.33, 2566.08, 45.56, 176.8),
}

-- Onde fica quem sai em liberdade / Where released players are placed
Config.Release = vector4(1848.13, 2586.05, 44.67, 269.5)

-- Pontos dentro da prisão / Points inside the prison
Config.Points = {
    board   = vector3(1760.0, 2518.9, 45.57),   -- quadro: tempo, trabalhos e loja / board: time, jobs and shop
    canteen = vector3(1781.1, 2560.5, 45.67),   -- cantina grátis / free canteen
}
Config.Marker = { type = 2, size = 0.3, color = { 245, 158, 11, 180 }, drawDistance = 12.0, useDistance = 1.6 }

-- ------------------------------------------------------------------ pertences / belongings
Config.Items = {
    Confiscate = true,               -- tira os itens à entrada e devolve à saída / take items on entry, return on release
    Keep = { 'id_card', 'driver_license' }, -- itens que o preso mantém / items the inmate keeps
    ReturnOnEscape = false,          -- quem foge perde os itens guardados / escapees lose their stored items
    -- Dados à entrada / Given on entry
    Starter = {
        { item = 'water_bottle', count = 2 },
        { item = 'sandwich', count = 2 },
    },
}

-- Cantina: comida grátis de X em X segundos / Canteen: free food every X seconds
Config.Canteen = {
    Cooldown = 300,
    Items = { { item = 'sandwich', count = 1 }, { item = 'water_bottle', count = 1 } },
}

-- Loja paga com créditos ganhos nos trabalhos / Shop paid with credits earned from jobs
Config.Shop = {
    { item = 'sandwich',     label = 'Sandes',        price = 2 },
    { item = 'water_bottle', label = 'Água',          price = 1 },
    { item = 'coffee',       label = 'Café',          price = 3 },
    { item = 'cigarette',    label = 'Cigarro',       price = 4 },
}

-- ------------------------------------------------------------------ trabalhos / jobs
-- reduce = meses tirados por tarefa | credits = créditos ganhos | seconds = tempo da tarefa
-- reduce = months removed per task | credits = credits earned | seconds = task duration
-- anim: { dict, clip } ou scenario = 'WORLD_HUMAN_...'
Config.Jobs = {
    electrician = {
        label = 'Eletricista', icon = 'fas fa-bolt', reduce = 1, credits = 3, seconds = 10,
        anim = { dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', clip = 'machinic_loop_mechandplayer' },
        spots = {
            vector3(1761.46, 2540.41, 45.56), vector3(1718.54, 2527.80, 45.56), vector3(1700.20, 2474.81, 45.56),
            vector3(1664.83, 2501.58, 45.56), vector3(1621.62, 2509.30, 45.56), vector3(1627.94, 2538.39, 45.56),
            vector3(1625.10, 2575.99, 45.56),
        },
    },
    cleaning = {
        label = 'Limpeza', icon = 'fas fa-broom', reduce = 1, credits = 2, seconds = 12,
        scenario = 'WORLD_HUMAN_JANITOR',
        spots = {
            vector3(1742.54, 2531.97, 45.56), vector3(1729.05, 2552.60, 45.56), vector3(1706.89, 2563.14, 45.56),
            vector3(1686.64, 2549.29, 45.56), vector3(1659.81, 2556.06, 45.56), vector3(1678.95, 2506.29, 45.56),
        },
    },
    gardening = {
        label = 'Jardinagem', icon = 'fas fa-seedling', reduce = 1, credits = 2, seconds = 12,
        scenario = 'WORLD_HUMAN_GARDENER_PLANT',
        spots = {
            vector3(1776.04, 2573.31, 45.73), vector3(1760.99, 2589.24, 45.73), vector3(1730.93, 2588.98, 45.73),
        },
    },
}
-- Pena mínima que fica depois dos trabalhos (em meses) / Minimum left after jobs (months)
Config.JobsMinimumLeft = 1

-- ------------------------------------------------------------------ fuga / escape
Config.Escape = {
    Allowed = true,                  -- false = quem sai do círculo volta para a cela / false = sent back to a cell
    AlertPolice = true,              -- alerta no drs_dispatch (ou ps-dispatch) / dispatch alert
    Warrant = true,                  -- mandado de captura no drs_mdt / warrant in drs_mdt
    GraceSeconds = 15,               -- tempo sem verificar depois de entrar / no check right after entering
}

-- ------------------------------------------------------------------ comandos / commands
Config.Commands = {
    jail = 'prender',                -- /prender [id] [meses] [motivo]
    unjail = 'libertar',             -- /libertar [id]
    time = 'pena',                   -- /pena (o próprio preso) / (the inmate)
}
-- Empregos que podem usar /prender (além do staff) e o cargo mínimo / Jobs allowed to use /jail and min grade
Config.PoliceJobs = { police = 1, sheriff = 1 }
-- Distância máxima entre o agente e o preso no /prender / Max distance officer-prisoner for /jail
Config.JailDistance = 10.0

-- ------------------------------------------------------------------ farda / uniform
-- Componentes: tshirt, torso, decals, arms, pants, shoes, mask, vest, chain, bag / Props: hat, glasses
Config.Outfit = {
    male = {
        tshirt = { item = 15, texture = 0 }, torso = { item = 345, texture = 0 }, arms = { item = 19, texture = 0 },
        pants = { item = 3, texture = 7 }, shoes = { item = 1, texture = 0 }, vest = { item = 0, texture = 0 },
        bag = { item = 0, texture = 0 }, hat = { item = -1, texture = 0 },
    },
    female = {
        tshirt = { item = 14, texture = 0 }, torso = { item = 370, texture = 0 }, arms = { item = 0, texture = 0 },
        pants = { item = 0, texture = 12 }, shoes = { item = 1, texture = 0 }, vest = { item = 0, texture = 0 },
        bag = { item = 0, texture = 0 }, hat = { item = -1, texture = 0 },
    },
}

Config.Blip = { label = 'Prisão de Bolingbroke', coords = vector3(1846.0, 2585.8, 45.67), sprite = 188, color = 1, scale = 0.8 }

-- Webhook do Discord (entradas, saídas, fugas) / Discord webhook (entries, releases, escapes)
Config.Webhook = ''

#Integrações (ficheiros abertos)

FunçãoPara que serve
Hooks.TakeItems / GiveItemsConfiscar e devolver os itens (ox_inventory, inventário do QBCore/Qbox e do ESX, incluindo as armas)
Hooks.SetJailMeta / GetJailMetaGuardar a pena no metadata.injail (compatibilidade)
Hooks.OnEscapeAlerta e mandado quando alguém foge
ClientHooks.SetOutfit / RestoreClothesFarda da prisão e roupa civil
ClientHooks.OnJailChangedCorre quando o jogador entra (true) ou sai (false) da prisão — para ligares os teus scripts

#Para programadores

server
exports.drs_prison:Jail(src, months, reason, officerSrc)
exports.drs_prison:Unjail(src)
exports.drs_prison:IsJailed(src)           -- true / false
exports.drs_prison:GetTimeLeft(src)        -- meses que faltam
exports.drs_prison:GetInmates()            -- lista de presos (usada pelo MDT)
exports.drs_prison:GetHistory(identifier)  -- registo prisional

Compatível com o qb-prison:

server
TriggerClientEvent('prison:client:Enter', playerId, months)

#Segurança

O tempo é contado no servidor e a fuga é verificada com a posição lida no servidor. As tarefas validam a distância e o tempo mínimo. Por compatibilidade com o qb-prison, um cliente pode pôr-se a si próprio na prisão — mas nunca a outra pessoa e nunca encurta uma pena que já exista.

#Resolução de problemas

O /prender diz que não tens permissão — o teu emprego e cargo têm de estar em Config.PoliceJobs, tens de estar de serviço e a menos de Config.JailDistance metros. O staff precisa da ACE drs.prison.

Os itens não voltam — o Hooks.TakeItems trata o ox_inventory e os inventários do QBCore/Qbox e do ESX. Se usas outro inventário, adapta essa função e a Hooks.GiveItems.

O qb-ambulancejob manda para a prisão antiga — confirma que o qb-prison está desligado; o drs_prison responde por ele.

Os presos saem pelas paredes — ajusta o centro e o raio de Config.Area para a tua prisão (se usas um MLO diferente).