Configuration Reference
Configuration is split across two files:
config.lua— server-owner settings: admin access, framework interop, language, dev flags. Loaded afterdefault.lua.default.lua— factory defaults for every gameplay feature. These are the values the admin dashboard starts from. Edit here only for baselines the dashboard can't reach (keybinds, animation clips, world locations, asset names). For live gameplay tuning use/mbtsling.
To hard-override any default.lua value, re-declare it in config.lua.
General
-- config.lua
MBT.Debug = false -- dev logging (not exposed in dashboard)
MBT.Language = 'en' -- 'en' | 'it' | 'fr' (read-only in dashboard)
-- default.lua
MBT.EnableSling = true -- master switch for visible weapon prop
MBT.EnableFlashlight = true -- sync flashlight state to slung prop metadata
MBT.DropWeaponOnDeath = true -- triggers WeaponDrop module on player death
MBT.ReduceMotion = false -- freeze all NUI animations (accessibility)
MBT.Relog = false -- set true for esx_multicharacter relog supportUI Position
MBT.UI = {
Position = "bottom-center" -- "bottom-center" | "top-center" | "bottom-right"
}Admin Dashboard
MBT.Admin = {
Command = 'mbtsling', -- chat command to open the dashboard
Key = '', -- optional keybind (e.g. 'F10'; '' = unbound)
Permission = nil, -- nil = defaults to ACE 'command.mbtsling'
}QB-Weapons Interop
Only relevant on QBCore servers running qb-weapons.
MBT.QBWeapons = {
SidearmDrawMode = 'native', -- 'native' | 'malisling'
DrawAnimation = true,
}| Mode | Description |
|---|---|
native | qb-weapons handles sidearm draw animation. No double animation, no extra setup. |
malisling | malisling runs the holster modal and custom draw animation for sidearms. Requires removing your sidearms from qb-weapons Config.WeapDraw.weapons to avoid double animation. |
Holster Sounds
MBT.Sounds = {
Enabled = true,
MaxDistance = 8.0, -- metres
Volume = 0.3, -- 0.0–1.0
Holster = { default = 'holster', ['side'] = 'holster_pistol', ['back'] = 'holster_rifle', ... },
Unholster = { default = 'unholster', ['side'] = 'unholster_pistol', ... },
}Sound files live in web/dist/sounds/ (.ogg). Override per slot type or set default for all.
Weapon Slot Positions
Prop attachment positions are defined in MBT.PropInfo per slot type. Available types:
| Type | Description |
|---|---|
side | Hip / pistol holster |
back | Rifle, shotgun, SMG on back |
back2 | Heavy weapons and launchers |
melee | Primary melee slot |
melee2 | Secondary melee (knife / blade) |
melee3 | Tertiary melee |
extinguisher | Fire extinguisher back-carry |
Each entry has Bone, Pos (male/female), Rot (male/female), and HolsterAnim.
Use the in-game Positions Editor (/mbtsling → Positions) to tune values live and save them to oxmysql. Copy the output back to default.lua if you want them as permanent defaults.
Per-job position overrides
MBT.CustomPropPosition = {
['police'] = {
['side'] = {
Bone = 24816,
Pos = { male = { x = -0.15, y = 0.0, z = -0.23 }, female = { ... } },
Rot = { male = { x = 90.0, y = 20.0, z = 180.0 }, female = { ... } },
},
},
}Job name must match what your framework returns. Weapon type key must match the type defined in data/weapons.lua.
Smart Vehicle Hiding
MBT.VehicleHiding = {
Enabled = true, -- true = smart (visible on roofless); false = legacy (always hidden)
KeepVisibleClasses = { [8] = true, [13] = true }, -- 8 = Motorcycles, 13 = Cycles
UseRoofCheck = true, -- keep visible on buggies/quads/open convertibles
}When Enabled = true, the weapon stays visible on motorcycles and roofless vehicles and is hidden only inside enclosed cars. When false, legacy behaviour hides the prop on any vehicle.
Weapon Drop
MBT.WeaponDrop = {
WeaponModelProp = true, -- render the weapon's real model on the ground
OxTargetPickup = true, -- add ox_target pickup option
Despawn = {
Enabled = true,
Seconds = 300, -- prop lifetime on the ground (seconds)
BlinkLastSec = 10, -- blink during final N seconds as a warning
},
Logging = {
Enabled = true,
Webhook = '', -- Discord webhook URL
BotName = 'MBT Malisling',
},
}Weapon Jamming
MBT.Jamming = {
Enabled = true,
Cooldown = 5, -- seconds between possible jams (same weapon)
Animation = { Dict = '...', Anim = '...' },
Chance = { -- jam probability (%) per durability threshold (%)
[50] = 10,
[40] = 15,
[30] = 20,
[20] = 25,
[10] = 30,
},
Unjam = {
Control = 45, -- FiveM control ID (45 = R / INPUT_RELOAD)
Display = "R", -- label shown in the HUD
Presses = 5, -- key presses required to unjam
},
}Weapon Throw
MBT.Throw = {
Enabled = true,
Command = 'throwWeapon',
Key = 'K',
Animation = { Dict = '...', Anim = '...' },
Groups = {
[`GROUP_PISTOL`] = { Allowed = true, Multipliers = { X = 20.0, Y = 20.0, Z = 15.0 } },
[`GROUP_RIFLE`] = { Allowed = true, Multipliers = { X = 10.0, Y = 10.0, Z = 5.0 } },
[`GROUP_SNIPER`] = { Allowed = false, Multipliers = { ... } },
-- ...
},
}Multipliers control the physical throw force (X/Y = horizontal, Z = arc height).
Suppressor Heat
MBT.SuppressorHeat = {
Enabled = true,
MaxHeat = 100,
HeatPerShot = 5, -- heat gained per shot
DecayRate = 16, -- heat lost per second (cooling)
DecayDelayMs = 600, -- delay after last shot before cooling starts
WarmThreshold = 35, -- heat at which glow appears (orange)
HotThreshold = 75, -- heat at which glow turns red (throbbing)
Mode = 'glow', -- 'glow' | 'light' | 'particle'
GlowSphere = { Radius = 0.06, Intensity = 8.0 },
Light = { Range = 0.4, Intensity = 10.0 },
Particle = { Dict = '...', Name = '...', Scale = 0.1 },
}Weapon Inspect
MBT.Inspect = {
Enabled = true,
Key = 'I',
MaxDistance = 20.0, -- metres; nearby players who see the animation
Animation = { Dict = '...', Anim = '...', Flag = 48 },
Show = { Serial = true, Condition = true, Name = true, Ammo = true },
AmmoMode = 'exact', -- 'exact' | 'vague' (Full/Half/Low/Empty)
ConditionTiers = {
{ Min = 85, Key = 'cond_pristine' },
{ Min = 60, Key = 'cond_good' },
{ Min = 35, Key = 'cond_worn' },
{ Min = 10, Key = 'cond_poor' },
{ Min = 0, Key = 'cond_damaged' },
},
}Weapon Safety
MBT.Safety = {
Enabled = true,
Key = 'END',
Command = 'mbtSafety',
DefaultOn = false, -- weapon starts ready (safety OFF) when drawn
PerWeapon = true, -- remember safety state per weapon by serial
Sound = { Enabled = true, Mode = 'native', ... },
HudIndicator = true, -- show SAFE/FIRE pill while firearm is in hand
Animation = { Enabled = true, ... },
}Weapon Name
MBT.WeaponName = {
Enabled = true,
Command = 'weaponname',
Key = '', -- '' = command only
MaxLength = 24,
Permission = 'everyone', -- 'everyone' | 'job' | 'ace'
Jobs = { ['weapon'] = true, ['gunsmith'] = true },
AcePermission = 'mbt.weaponname',
OncePerWeapon = false, -- true = block renaming after first name is set
}Weapon Weight
MBT.WeaponWeight = {
Enabled = true,
Mode = 'light', -- 'off' | 'light' | 'medium' | 'heavy' | 'custom'
Presets = {
light = { Threshold = 2, PerWeapon = 0.03, MaxPenalty = 0.18 }, -- down to 82% speed
medium = { Threshold = 2, PerWeapon = 0.06, MaxPenalty = 0.30 }, -- down to 70%
heavy = { Threshold = 1, PerWeapon = 0.10, MaxPenalty = 0.45 }, -- down to 55%
},
-- Used only when Mode = 'custom':
Threshold = 2, -- weapons below this count carry no penalty
PerWeapon = 0.03,
MaxPenalty = 0.18,
RefreshMs = 5000,
CountGroups = {
[`GROUP_RIFLE`] = true, [`GROUP_SMG`] = true,
[`GROUP_MG`] = true, [`GROUP_SHOTGUN`] = true,
-- pistols and melee excluded by default
},
}Charge Weapon
MBT.ChargeWeapon = {
Enabled = true,
Key = 'INSERT',
Command = 'mbtcharge',
MaxDistance = 20.0, -- nearby players who see and hear the rack
Cooldown = 1500, -- ms between racks (anti-spam)
Animation = { ... },
Sound = { Enabled = true, Mode = 'native', ... },
Groups = { [`GROUP_PISTOL`] = true, [`GROUP_RIFLE`] = true, ... },
}Showcase Poses
MBT.ShowcasePoses = {
Enabled = true,
Sync = true, -- show pose to nearby players via statebag
Command = 'pose',
Key = '',
Poses = {
{ label = 'Crossed arms', dict = '...', anim = 'idle_a', flag = 1 },
{ label = 'Lean back', dict = '...', anim = 'idle_a', flag = 1 },
-- ...
},
}Vehicle Trunk Rack
MBT.VehicleTrunkRack = {
Enabled = true,
AllowedTypes = { ['back'] = true, ['back2'] = true },
Capacity = 2, -- weapons per vehicle (per plate)
InteractionDistance = 2.5,
EquipOnRetrieve = false, -- true = weapon goes straight into hand
Animation = { ... },
PropOffset = {
Default = { Pos = { x = 0.0, y = -0.10, z = -0.30 }, Rot = { ... } },
ByModel = { -- ['sultan'] = { ... } -- per-model fine-tune
},
ByClass = { -- [12] = { ... } -- per vehicle class
},
},
}Use /mbt_trunktune to tune offsets in-game. Press ENTER to save the current model's offset.
Requires oxmysql for persistence across restarts. Without it the module still works but contents reset on restart.
Weapon Rack
MBT.WeaponRack = {
Enabled = true,
Capacity = 4,
InteractionDistance = 2.0,
EquipOnRetrieve = false,
AllowedTypes = { ['back'] = true, ['back2'] = true, ['side'] = true },
DefaultProp = `xm_prop_xm_gunlocker_01a`,
Offsets = { ['back'] = { Pos = {...}, Rot = {...} }, ... },
Blip = { Enabled = false, Sprite = 110, Color = 1, Scale = 0.8, Label = 'Armory' },
Logging = { Enabled = true, Webhook = '', BotName = 'MBT Armory' },
Placement = {
Enabled = true,
Item = 'mbt_gunrack', -- inventory item name
MaxPerPlayer = 2,
AllowPickup = true,
Access = 'everyone', -- 'everyone' | 'owner'
},
RequireCert = false, -- requires mbt_shooting companion for enforcement
Locations = {
-- { id = 'mrpd_armory', coords = vec4(452.6, -980.0, 30.7, 90.0),
-- prop = `xm_prop_xm_gunlocker_01a`, job = 'police', label = 'MRPD Armory' },
},
}Add the mbt_gunrack item to your inventory's item list to enable player-placed racks. See the commented example in default.lua for the item definition.
Concealed Carry
MBT.ConcealedCarry = {
Enabled = true,
Key = 'U',
ConcealableTypes = { ['side'] = true },
ToggleCooldownMs = 1200,
Tell = {
Enabled = true,
RollSeconds = 25, -- seconds between tell rolls
ChanceGood = 0.15, -- chance per roll with good cover (jacket)
ChancePoor = 0.45, -- chance per roll with poor cover (light top)
MoveBoost = 2.0, -- multiplier while sprinting / jumping
},
Clothing = {
BareTorsoMale = { [15] = true }, -- drawable IDs → cannot conceal
LightTopsMale = { [5] = true, [16] = true }, -- → poor concealment
OverridesMale = {}, -- [drawableId] = 'good'|'poor'|'none'
},
}Use /mbt_concealdebug in-game to read your outfit's drawable IDs and extend the lists per your clothing pack.
Pat Down
MBT.PatDown = {
Enabled = true,
Key = 'Y',
Jobs = { ['police'] = true, ['sheriff'] = true, ['bcso'] = true },
MaxDistance = 2.0,
RequireConsent = true, -- target must accept the frisk
CuffedBypass = true, -- skip consent when cuffed
RequestTimeoutMs = 8000,
SearchMsPoor = 600, -- time to detect poorly-hidden weapon (ms)
SearchMsGood = 2600, -- time to detect well-hidden weapon (ms)
ShowAmmo = false, -- include ammo count in result
Logging = { Enabled = true, Webhook = '', BotName = 'MBT Pat-Down' },
}Weapon Serials
MBT.Serials = {
EnsureGeneration = true,
Format = 'marked', -- 'marked' (MBT-XXXXXXXX) | 'oxlike'
SweepOnLoad = true, -- scan player weapons on join
}Weapon Handoff
MBT.Handoff = {
Enabled = true,
Key = 'G',
MaxDistance = 2.5,
RequestTimeoutMs = 8000,
EquipOnAccept = false,
Animation = { GiveDict = '...', GiveAnim = '...', GiveMs = 900, ... },
}Ammo Sharing
MBT.AmmoSharing = {
Enabled = true,
Key = 'H',
ShareAmount = 30, -- default rounds pre-selected in amount picker
Step = 5, -- ←/→ adjusts by this amount; SHIFT = ×3
MaxDistance = 2.5,
RequestTimeoutMs = 8000,
Animation = { ... },
}Shell Casings
MBT.ShellCasings = {
Enabled = true,
Chance = 0.5, -- 0–1 probability a shot leaves a casing
MinIntervalMs = 1200, -- per-player throttle (burst-proof)
ExpireMinutes = 30,
MaxCasings = 150, -- global cap (oldest removed first)
GlintRange = 12.0, -- metres to draw the ground glint
InteractRange = 1.2, -- examine/collect reach
SerialReveal = 'partial', -- 'partial' | 'full' | 'none'
ExamineJobs = false, -- false = everyone; or { ['police'] = true }
AllowCollect = true,
Prop = nil, -- optional streamed prop model (nil = glint only)
ExcludeTypes = { ['melee'] = true, ['melee2'] = true, ... },
}Chain of Custody
MBT.ChainOfCustody = {
Enabled = true,
MaxEntries = 10, -- oldest entry dropped when cap is reached
ShowInInspect = true, -- show chain in the Inspect overlay
}No-Draw Zones
MBT.NoDrawZones = {
Enabled = true,
AllowMelee = true, -- melee weapons still allowed inside zones
NotifyCooldown = 3000,
HudIndicator = true,
Zones = {
{ label = 'Pillbox Hospital', type = 'sphere', coords = vec3(307.7, -1433.4, 29.9), radius = 45.0 },
{ label = 'Mission Row PD', type = 'sphere', coords = vec3(441.0, -982.0, 30.7), radius = 40.0 },
-- box: { type = 'box', coords = vec4(x, y, z, heading), size = vec3(w, h, d) }
-- poly: { type = 'poly', points = { vec3(...), ... }, thickness = 4.0 }
},
}Low Ready
MBT.LowReady = {
Enabled = true,
Key = 'HOME',
Command = 'mbtLowReady',
Types = { ['back'] = true, ['back2'] = true },
Position = {
['back'] = { Bone = 24818, Pos = { x = 0.060, y = 0.196, z = -0.004 }, Rot = { x = 180.0, y = 142.0, z = -5.0 } },
},
Transition = { Enabled = true, ... },
}Tactical Sling
MBT.TacticalSling = {
Enabled = false, -- disabled until you add a sling prop to stream/
DefaultVariant = 'normal',
Variants = {
{ id = 'normal', model = 'mbt_belt_prop_a', label = 'Belt — Normal' },
{ id = 'camo', model = 'mbt_belt_prop_b', label = 'Belt — Camo' },
},
JobVariants = {}, -- { ['police'] = 'camo' }
Types = { ['back'] = true, ['back2'] = true },
}To enable: add your sling .ydr prop to stream/, set the model fields above, then flip Enabled = true. Tune the attach position with the NUI Positions editor (type sling).
Notification Override
Replace the default ox_lib notification with your own:
MBT.Notification = function(data)
-- data.title, data.description, data.type ('success'|'error'|'info'), data.icon
lib.notify(data)
end