DRS Prison
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
| Recurso | Obrigatório |
|---|---|
oxmysql | Sim |
| Qbox, QBCore ou ESX | Sim (deteção automática) |
qb-inventory ou ox_inventory | Sim (confiscar e devolver itens) |
drs_dispatch ou ps-dispatch | Não — alerta de fuga |
drs_mdt | Não — mandado de captura, lista de reclusos e registo prisional |
drs_policejob | Não — o menu F6 manda para a prisão |
#Instalação
- Desliga o
qb-prison. Odrs_prisontemprovide 'qb-prison'e trata o eventoprison:client:Enter, por isso oqb-ambulancejob, os MDTs antigos e outros scripts continuam a funcionar. As penas que já estavam nometadata.injailpassam para cá sozinhas. - Coloca
drs_prisonemresources. - Adiciona ao
server.cfg, depois dooxmysql, da framework e do inventário:
ensure oxmysql
ensure qb-core
ensure drs_prison- As tabelas
drs_prison(penas em curso) edrs_prison_log(histórico) são criadas sozinhas no arranque. - Ajusta o tempo por mês, os trabalhos, a loja e as fugas no
config.lua.
#Comandos
| Comando | Quem pode | O que faz |
|---|---|---|
/prender [id] [meses] [motivo] | Staff, ou polícia de serviço com o cargo de Config.PoliceJobs, a menos de Config.JailDistance metros | Manda para a prisão |
/libertar [id] | Staff (ACE drs.prison) | Liberta um preso |
/pena | O preso | Mostra o tempo que falta |
Os nomes dos comandos estão em Config.Commands. Para dares a ACE ao staff:
add_ace group.admin drs.prison allowTambé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
- O preso é levado para uma cela aleatória (
Config.Spawns) e veste a farda (Config.Outfit). - Com
Config.Items.Confiscate = true, os itens são guardados na base de dados — exceto os deConfig.Items.Keep(ex.: cartão de cidadão) — e recebe os itens deConfig.Items.Starter. - Aparece o HUD com o tempo que falta.
#A pena
- Cada mês de pena dura
Config.MinutesPerMonthminutos 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.
| Trabalho | Reduz | Créditos | Duração |
|---|---|---|---|
| Eletricista | 1 mês | 3 | 10 s |
| Limpeza | 1 mês | 2 | 12 s |
| Jardinagem | 1 mês | 2 | 12 s |
A pena nunca desce abaixo de Config.JobsMinimumLeft meses por causa dos trabalhos. Podes acrescentar trabalhos novos em Config.Jobs:
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, deConfig.Canteen.CooldownemConfig.Canteen.Cooldownsegundos.
#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ção | Por defeito | Descrição |
|---|---|---|
Config.Locale | 'pt' | Idioma: pt ou en |
Config.MinutesPerMonth | 1.0 | Minutos reais por mês de pena |
Config.MaxMonths | 300 | Pena máxima |
Config.OfflineCounts | false | O tempo passa offline |
Config.Items.Confiscate | true | Tira os itens à entrada |
Config.JobsMinimumLeft | 1 | Mínimo que fica depois dos trabalhos |
Config.Escape.Allowed | true | Permite fugas |
Config.Escape.Warrant | true | Mandado no MDT ao fugir |
Config.PoliceJobs | police = 1, sheriff = 1 | Quem pode usar /prender |
Config.Webhook | '' | Webhook do Discord (entradas, saídas, fugas) |
#Configuração completa
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ção | Para que serve |
|---|---|
Hooks.TakeItems / GiveItems | Confiscar e devolver os itens (ox_inventory, inventário do QBCore/Qbox e do ESX, incluindo as armas) |
Hooks.SetJailMeta / GetJailMeta | Guardar a pena no metadata.injail (compatibilidade) |
Hooks.OnEscape | Alerta e mandado quando alguém foge |
ClientHooks.SetOutfit / RestoreClothes | Farda da prisão e roupa civil |
ClientHooks.OnJailChanged | Corre quando o jogador entra (true) ou sai (false) da prisão — para ligares os teus scripts |
#Para programadores
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 prisionalCompatível com o qb-prison:
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).