DRS Crafting
Bancadas de fabrico com interface moderna, níveis por skill, probabilidade de sucesso, ferramentas que não se gastam e fabrico em lote.
Bancadas de fabrico com níveis por skill, probabilidade de sucesso, ferramentas que não se gastam, fabrico em lote e uma interface moderna com pesquisa e categorias. Cada fabrico é validado no servidor do princípio ao fim.
#Requisitos
| Framework | QBCore, Qbox ou ESX (deteção automática) |
| Inventário | ox_inventory, qb-inventory, ps-inventory, lj-inventory ou qs-inventory |
| Base de dados | oxmysql |
| Interação | ox_target, qb-target ou tecla E |
#Instalação
- Coloca a pasta
drs_craftingemresourcese adiciona aoserver.cfg, depois dooxmysql, do framework e do inventário:
ensure drs_crafting- A tabela
drs_crafting_xpé criada sozinha. - Define as bancadas (
Config.Stations) e as receitas (Config.Recipes). As receitas de exemplo usam itens base do QBCore (metalscrap,plastic,steel…).
#Bancadas
{
id = 'workbench',
label = 'Bancada de trabalho',
skill = 'general', -- cada skill tem o seu nível
coords = vector4(1175.4, 2640.1, 37.75, 0.0),
prop = 'prop_tool_bench02', -- nil = usa um objeto que já existe no mapa
blip = { sprite = 566, color = 47, scale = 0.7 },
jobs = nil, -- ex.: { mechanic = 0 } (emprego = cargo mínimo)
gangs = nil,
recipes = { 'lockpick', 'repairkit', 'radio' },
},#Receitas
advancedlockpick = {
item = 'advancedlockpick', amount = 1, time = 12, chance = 85, level = 5, xp = 25, category = 'tools',
ingredients = { { item = 'metalscrap', amount = 12 }, { item = 'steel', amount = 4 } },
tools = { { item = 'screwdriverset' } }, -- precisas de a ter, não se gasta
},| Campo | Descrição |
|---|---|
item / amount | O que se recebe e quantos por vez |
time | Segundos por unidade (validado no servidor) |
chance | Probabilidade de sucesso (%) |
level / xp | Nível mínimo da skill e XP por unidade |
ingredients | Materiais gastos |
tools | Ferramentas/planos que não se gastam |
category, label, description, image | Opcionais, para a interface |
Se o fabrico falhar, Config.OnFail decide: lose (perde os materiais), keep ou half. O jogador ganha Config.XPOnFail do XP mesmo a falhar.
#Níveis
Cada skill (ex.: general, weapons) sobe em separado. O XP de um nível para o seguinte é Config.Levels.base × growth^(nível-1).
#Comandos
| Comando | Quem | O que faz |
|---|---|---|
/craftxp [id] [skill] [quantidade] | staff | Dá ou tira XP numa skill |
#Configuração completa
Config = {}
-- Idioma / Language: 'pt' ou 'en'
Config.Locale = 'pt'
-- Framework: 'auto' deteta Qbox/QBCore/ESX (ou 'qbx' | 'qb' | 'esx')
Config.Framework = 'auto'
-- Como se abre a bancada / How a bench is opened
-- 'auto' (ox_target > qb-target > tecla) | 'ox_target' | 'qb-target' | 'key'
Config.Interaction = 'auto'
Config.InteractKey = 38 -- E (só no modo 'key' / only in 'key' mode)
Config.InteractKeyLabel = 'E'
Config.InteractDistance = 2.0 -- também validado no servidor / also checked on the server
-- Imagens dos itens. 'auto' usa a pasta do inventário que estiver a correr.
-- Item images. 'auto' uses the folder of the running inventory.
-- Ou / Or: 'nui://o-meu-inventario/html/images/%s.png'
Config.ImagePath = 'auto'
-- ------------------------------------------------------------------ níveis / levels
Config.Levels = {
enabled = true,
max = 50,
base = 100, -- XP do nível 1 para o 2 / XP from level 1 to 2
growth = 1.25, -- cada nível pede mais 25% / each level needs 25% more
}
-- Se falhar: 'lose' perde os ingredientes, 'keep' fica com eles, 'half' perde metade
-- On failure: 'lose' loses the ingredients, 'keep' keeps them, 'half' loses half
Config.OnFail = 'lose'
Config.XPOnFail = 0.5 -- fração do XP que ganha mesmo quando falha / share of XP given on failure
Config.MaxQuantity = 10 -- máximo por vez / max per batch
Config.Animation = { dict = 'mini@repair', clip = 'fixing_a_ped' }
-- ------------------------------------------------------------------ bancadas / benches
-- skill: cada skill tem o seu nível (ex.: 'weapons' e 'general' sobem em separado)
-- skill: each skill has its own level (e.g. 'weapons' and 'general' level up separately)
-- jobs / gangs: quem pode usar (nil = todos). Exemplo: jobs = { mechanic = 0 } (emprego = cargo mínimo)
-- jobs / gangs: who can use it (nil = everyone). Example: jobs = { mechanic = 0 } (job = minimum grade)
-- prop: objeto criado no sítio (nil = usa o que já existe no mapa) / object spawned there (nil = use what the map has)
Config.Stations = {
{
id = 'workbench',
label = 'Bancada de trabalho',
skill = 'general',
coords = vector4(1175.4, 2640.1, 37.75, 0.0),
prop = 'prop_tool_bench02',
blip = { sprite = 566, color = 47, scale = 0.7 },
recipes = { 'lockpick', 'advancedlockpick', 'repairkit', 'advancedrepairkit', 'radio', 'screwdriverset', 'electronickit', 'drill' },
},
{
id = 'armory',
label = 'Bancada de armas',
skill = 'weapons',
coords = vector4(2195.64, 5594.35, 53.77, 254.0),
prop = 'gr_prop_gr_bench_04a',
blip = false,
gangs = nil,
recipes = { 'armor', 'weapon_pistol' },
},
}
-- ------------------------------------------------------------------ receitas / recipes
-- item: o que se recebe / what you get · amount: quantos por vez / how many each time
-- time: segundos por unidade / seconds per unit · chance: % de sucesso / success %
-- level: nível mínimo da skill / minimum skill level · xp: XP por unidade / XP per unit
-- ingredients: gastos / consumed · tools: precisas de os ter, não são gastos (plantas, ferramentas) / needed, not consumed
-- category: separador na interface / tab in the UI · label/description: opcionais (senão usa o nome do item)
Config.Recipes = {
lockpick = {
item = 'lockpick', amount = 1, time = 6, chance = 100, level = 1, xp = 10, category = 'tools',
ingredients = { { item = 'metalscrap', amount = 8 }, { item = 'plastic', amount = 4 } },
},
advancedlockpick = {
item = 'advancedlockpick', amount = 1, time = 12, chance = 85, level = 5, xp = 25, category = 'tools',
ingredients = { { item = 'metalscrap', amount = 12 }, { item = 'steel', amount = 4 }, { item = 'plastic', amount = 6 } },
tools = { { item = 'screwdriverset' } },
},
screwdriverset = {
item = 'screwdriverset', amount = 1, time = 10, chance = 100, level = 2, xp = 15, category = 'tools',
ingredients = { { item = 'steel', amount = 6 }, { item = 'plastic', amount = 6 }, { item = 'rubber', amount = 2 } },
},
drill = {
item = 'drill', amount = 1, time = 25, chance = 80, level = 12, xp = 60, category = 'tools',
ingredients = { { item = 'steel', amount = 15 }, { item = 'copper', amount = 10 }, { item = 'electronickit', amount = 1 }, { item = 'rubber', amount = 6 } },
},
repairkit = {
item = 'repairkit', amount = 1, time = 10, chance = 100, level = 1, xp = 12, category = 'vehicles',
ingredients = { { item = 'metalscrap', amount = 10 }, { item = 'steel', amount = 4 }, { item = 'rubber', amount = 4 } },
},
advancedrepairkit = {
item = 'advancedrepairkit', amount = 1, time = 18, chance = 90, level = 8, xp = 35, category = 'vehicles',
ingredients = { { item = 'metalscrap', amount = 18 }, { item = 'steel', amount = 10 }, { item = 'aluminum', amount = 8 }, { item = 'rubber', amount = 8 } },
tools = { { item = 'screwdriverset' } },
},
radio = {
item = 'radio', amount = 1, time = 12, chance = 95, level = 3, xp = 20, category = 'electronics',
ingredients = { { item = 'plastic', amount = 10 }, { item = 'copper', amount = 6 }, { item = 'glass', amount = 2 } },
},
electronickit = {
item = 'electronickit', amount = 1, time = 15, chance = 90, level = 6, xp = 30, category = 'electronics',
ingredients = { { item = 'copper', amount = 12 }, { item = 'plastic', amount = 8 }, { item = 'aluminum', amount = 4 } },
tools = { { item = 'screwdriverset' } },
},
armor = {
item = 'armor', amount = 1, time = 20, chance = 90, level = 4, xp = 30, category = 'protection',
ingredients = { { item = 'steel', amount = 12 }, { item = 'rubber', amount = 8 }, { item = 'aluminum', amount = 6 } },
},
weapon_pistol = {
item = 'weapon_pistol', amount = 1, time = 45, chance = 75, level = 10, xp = 80, category = 'weapons',
ingredients = { { item = 'steel', amount = 25 }, { item = 'metalscrap', amount = 30 }, { item = 'rubber', amount = 6 }, { item = 'aluminum', amount = 10 } },
tools = { { item = 'screwdriverset' } },
},
}
-- Nomes das categorias / Category names
Config.Categories = {
pt = { tools = 'Ferramentas', vehicles = 'Veículos', electronics = 'Eletrónica', protection = 'Proteção', weapons = 'Armas' },
en = { tools = 'Tools', vehicles = 'Vehicles', electronics = 'Electronics', protection = 'Protection', weapons = 'Weapons' },
}
-- Comando de staff para dar/tirar XP: /craftxp [id] [skill] [quantidade]
-- Staff command to give/take XP: /craftxp [id] [skill] [amount]
Config.AdminCommand = 'craftxp'
Config.StaffGroups = { 'god', 'admin', 'superadmin' }
-- Webhook do Discord (vazio = desligado) / Discord webhook (empty = off)
Config.Webhook = ''
-- Notificações com ox_lib quando estiver a correr / Use ox_lib notifications when it is running
Config.UseOxNotify = false#Para programadores
exports.drs_crafting:AddXP(src, 'weapons', 50)
exports.drs_crafting:GetLevel(src, 'weapons')
exports.drs_crafting:GetXP(src, 'general')#Segurança
- Ao começar, o servidor confirma a distância à bancada, o acesso, o nível, os materiais e as ferramentas.
- Ao acabar, confirma o tempo, a distância e os materiais outra vez — e só então tira e entrega.
- Se o inventário estiver cheio, os materiais das unidades que não couberam são devolvidos.
#Resolução de problemas
As imagens dos itens não aparecem — o script usa a pasta do inventário que estiver a correr. Se usas outro, define Config.ImagePath (ex.: nui://o-meu-inventario/html/images/%s.png).
"Não tens acesso a esta bancada." — vê jobs/gangs da bancada e da receita.
O objeto da bancada está no ar ou enterrado — ajusta as coords; o objeto é colocado no chão sozinho, mas precisa de um ponto livre.