# Configuration > Configuration reference for ML Turret Category: TURRET · Source: https://miciomods.it/docs/ml-turret-configuration · Last updated: 2026-07-09 ## Overview - `shared/config.lua`: turret blueprints, calibres, AI, zones, placement UI, ownership, destruction behaviour - `server/config_server.lua`: Discord webhooks and admin ACE permission Two kinds of turrets exist: **placeable** (spawned by players from kit items, count toward a per-player quota) and **fixed** (admin-defined in `Config.FixedTurrets`, always present at the declared coords). ## General **shared/config.lua** ```lua Config.Debug = false Config.Locale = 'en' Config.Theme = 'military' Config.MaxTurretsPerPlayer = 3 Config.InteractionDistance = 3.0 Config.PlacementDistance = 5.0 Config.DeleteOld = 10 ``` - `Debug`: enables `/turret_compose`, `/turret_muzzles`, `/turret_camera`, `/turret_firetest`, `/turret_inspect`, `/turret_aim_viz` and verbose logs. Leave `false` in production. - `Locale`: must match a file in `locales/` (e.g. `en` → `locales/en.lua`) - `Theme`: UI theme. One of: `military`, `wasteland`, `cyberpunk`, `noir`, `fantasy` - `MaxTurretsPerPlayer`: quota for placeable turrets. Destroyed-but-rebuildable turrets still occupy a slot; permanently destroyed ones do not - `InteractionDistance`: metres within which the target option appears on a placed turret - `PlacementDistance`: max metres from the player where a new turret can be ghost-previewed - `DeleteOld`: days of inactivity before an unused turret is auto-deleted by the nightly sweep. Set `false` to disable **shared/config.lua** ```lua Config.DeleteOptions = { DeleteOnlyIfEmpty = true, DeleteOnlyIfBroken = false, DeleteOnlyIfUnfueled = false, } ``` - `DeleteOnlyIfEmpty`: must have 0 loaded ammo to be eligible - `DeleteOnlyIfBroken`: must have 0 HP - `DeleteOnlyIfUnfueled`: must have 0 fuel. A turret needs to match ALL enabled flags to be deleted ## Placement **shared/config.lua** ```lua Config.PlacementHintPosition = 'right-center' Config.PlacementProgress = { duration = 5000, labelKey = 'placement_installing', canCancel = true, disable = { car = true, combat = true, sprint = true, move = true }, anim = { dict = 'amb@world_human_hammering@male@base', clip = 'base' }, } ``` - `PlacementHintPosition`: ox_lib textUI anchor. Accepted: `top-center`, `top-right`, `top-left`, `right-center`, `left-center`, `bottom-center`, `bottom-right`, `bottom-left` - `PlacementProgress.duration`: progress bar length in ms while the ghost is locked in place - `PlacementProgress.labelKey`: locale key shown on the bar (falls back to raw key if missing) - `PlacementProgress.canCancel`: when `true`, the player can abort with SHIFT/ESC - `PlacementProgress.disable`: ox_lib control-disable flags active during the bar - `PlacementProgress.anim`: animation played on the player (dict + clip) ## No-place Zones **shared/config.lua** ```lua Config.NoPlaceZones = { -- { type = 'sphere', coords = vec3(298.6, -584.8, 43.3), radius = 80.0 }, -- { type = 'box', coords = vec3(195.0, -933.0, 30.0), size = vec3(100.0, 100.0, 30.0) }, -- { type = 'poly', points = { vec3(), vec3(), ... }, thickness = 60.0 }, } ``` Shapes where placement is forbidden. The ghost turns red inside these zones and cannot be confirmed. - `sphere`: simple radius around a point - `box`: axis-aligned bounding box, rotation is ignored - `poly`: 2D XY polygon with optional Z thickness anchored on the first point Leave the table empty to allow placement anywhere. ## AI **shared/config.lua** ```lua Config.AI = { enabled = true, defaultScanRate = 1500, defaultScanRangeMax = 35.0, defaultScanRangeMin = 0.0, defaultSwitchCooldown = 800, } ``` - `enabled`: master kill switch. When `false`, every turret becomes manual-only - `defaultScanRate`: ms between target scans per turret (type can override) - `defaultScanRangeMax`: engagement radius in metres - `defaultScanRangeMin`: dead-zone radius, targets closer are ignored - `defaultSwitchCooldown`: min ms between two target swaps, prevents servo flip-flop ## Fuel **shared/config.lua** ```lua Config.Fuel = { enabled = true, drainWhenIdle = false, idleDrainRate = 0.01, activeDrainRate = 0.10, shutdownOnEmpty = true, } ``` - `enabled`: global master. Disables fuel for every turret when `false` - `drainWhenIdle`: if `true`, fuel drains even without an engaged target - `idleDrainRate` / `activeDrainRate`: fuel/second in each state - `shutdownOnEmpty`: turret goes offline when fuel reaches 0 Individual turret types opt in via `requiresFuel = true`. Types with `requiresFuel = false` ignore this block entirely. ## Ownership and Invites **shared/config.lua** ```lua Config.Ownership = { maxGroupSize = 5, nearbyPlayerRange = 10.0, showRealName = true, playerNameFormat = 'rp_full', inviteTimeoutSeconds = 30, } ``` - `maxGroupSize`: max members the owner can invite. Members share panel access, reload, repair and refuel rights. They cannot invite further members, transfer ownership or dismantle - `nearbyPlayerRange`: radius (m) used to list nearby players in the invite picker - `showRealName`: show RP name instead of raw FiveM username where supported - `playerNameFormat`: one of: - `'fivem'`: FiveM username as seen in the player list - `'rp_first'`: RP first name only (`charinfo.firstname`) - `'rp_full'`: first + last name - `inviteTimeoutSeconds`: how long a pending invite stays valid before auto-expiring ## Destruction **shared/config.lua** ```lua Config.Destruction = { canBeRepairedAfterDestruction = true, destructionRepairItem = 'turret_rebuild_kit', rubbleDespawnTime = false, } ``` - `canBeRepairedAfterDestruction`: global default. Individual turret types can override with their own `canBeRepairedAfterDestruction` - `destructionRepairItem`: inventory item consumed to rebuild a destroyed turret from its rubble - `rubbleDespawnTime`: seconds after which an unrepaired rubble disappears and its DB row is wiped. Set `false` to keep rubble indefinitely ## Ammo **shared/config.lua** ```lua Config.Ammo = { ['9mm'] = { label = 'ammo_9mm_label', item = 'ammo_9mm', weaponHash = `WEAPON_COMBATPISTOL`, damage = 8.0, amountPerItem = 30, reloadTime = 2000, }, -- ... } ``` Each entry is a calibre catalogue key referenced by turret types through `acceptedCalibers`. - `label`: locale key for the display name in the panel - `item`: inventory item consumed to reload. Must exist in your inventory definition - `weaponHash`: GTA weapon that drives ballistics, muzzle FX and native sound - `damage`: damage per bullet against targeted entities - `amountPerItem`: rounds yielded per consumed item (e.g. 1× `ammo_762` = 30 rounds) - `reloadTime`: panel progress bar duration in ms Defaults include: `9mm`, `556x45`, `762x39`, `50cal`, `minigun`. Copy an entry into `open/shared.lua` to add new calibres without touching the main config. ## Turret Types **shared/config.lua** ```lua Config.Turrets['bazq_heavy'] = { label = 'bazq_heavy_label', item = 'bazq_heavy_kit', manualControl = true, exitTime = 3000, modelSetup = { models = { base = 'bazq-turret1b_base', gunner = 'bazq-turret1b_gunner', barrel = 'bazq-turret1b_barrel', }, aiming = { yawPropKey = 'gunner', pitchPropKey = 'barrel', }, }, offsets = { attachGunner = vec3(-0.102, 0.0, 1.790), attachBarrel = vec3(0.876, 0.0, 1.220), camera = vec3(1.360, 0.0, 0.060), muzzles = { vec3(4.0, 0.222, 0.235), --[[...]] }, rotationOffset = 90.0, }, barrelForward = vec3(1.0, 0.0, 0.0), aimCorrection = vec3(0.4, 0.0, 0.0), } ``` - `label`: locale key shown on the HUD and panel header - `item`: placement kit item. Set to `nil` to make this type fixed-only - `manualControl`: allows the player to take the gunner seat - `exitTime`: ms shutdown animation before leaving manual control (anti-abuse) - `modelSetup.models`: prop chain: `base` always, `gunner` optional, `barrel` optional - `modelSetup.aiming.yawPropKey` / `pitchPropKey`: which prop rotates on which axis - `offsets.attachGunner` / `attachBarrel`: local attachment offsets - `offsets.camera`: local camera position when in manual control (relative to barrel) - `offsets.muzzles`: muzzle flash origins in local space. Iterated round-robin on fire - `offsets.rotationOffset`: compensates the prop's forward axis (Bazq forward is +X so needs 90°) - `barrelForward`: forward direction vector in local coords (matches the muzzle layout) - `aimCorrection`: micro-correction for the impact point in camera space **shared/config.lua** ```lua rotation = { yawLimits = nil, pitchLimits = { min = -25, max = 55 }, yawSpeed = 120.0, pitchSpeed = 60.0, snapThreshold = 0.5, accelTime = 0.35, decelZone = 18.0, minVelFrac = 0.06, settleEps = 0.08, aimDeadZone = 1.2, } ``` Servo model for target tracking. Gives the turret a mechanical feel instead of teleporting onto the target. - `yawLimits`: `nil` for unlimited 360° rotation, or `{ min, max }` in degrees relative to base heading - `pitchLimits`: vertical arc in degrees - `yawSpeed` / `pitchSpeed`: max deg/sec - `snapThreshold`: alignment tolerance for the fire gate - `accelTime`: seconds to reach max speed from rest (lower = snappier) - `decelZone`: degrees from target where braking starts - `minVelFrac`: floor velocity as a fraction of max (prevents total stall) - `settleEps`: below this angular error the servo holds position (no hunting) - `aimDeadZone`: horizontal distance (m) below which the turret stops tracking (targets directly under it) **shared/config.lua** ```lua targeting = { switchCooldown = 800, targetPlayers = true, targetHumans = false, targetZombies = true, } ``` - `switchCooldown`: min ms between two target swaps. Overrides `Config.AI.defaultSwitchCooldown` - `targetPlayers`: engage online players in range - `targetHumans`: engage non-zombie NPCs - `targetZombies`: engage peds flagged via `Config.HRS` **shared/config.lua** ```lua health = 1000.0, fireRate = 100, overheat = { enabled = true, maxHeat = 100.0, perShot = 2.2, coolPerSecond = 8.0, cooldownSeconds = 5, } ``` - `health`: hull HP - `fireRate`: ms between shots - `overheat.enabled`: toggle the heat subsystem - `overheat.maxHeat` / `perShot` / `coolPerSecond`: heat accumulation model - `overheat.cooldownSeconds`: lockout duration once the cap is hit **shared/config.lua** ```lua acceptedCalibers = { '762x39', '50cal', 'minigun' }, defaultCaliber = '762x39', maxAmmoCapacity = 500, requiresFuel = true, fuelCapacity = 100, fuelItems = { ['diesel'] = 10, ['jerrycan_large'] = 100 }, canBeRepaired = true, repairItems = { ['repair_kit'] = { addHealth = 300.0 }, ['welding_torch'] = { addHealth = 150.0 }, } ``` - `acceptedCalibers`: array of keys from `Config.Ammo`. The panel only lets the player load these - `defaultCaliber`: preloaded at spawn (used by fixed turrets mostly) - `maxAmmoCapacity`: magazine size - `requiresFuel`: when `false`, fuel UI is hidden and the turret never runs out - `fuelCapacity`: tank size - `fuelItems`: map of inventory item → units of fuel added per item - `canBeRepaired`: shows/hides the Repair tab - `repairItems`: map of inventory item → `{ addHealth = N }` (HP restored per consumed item) **shared/config.lua** ```lua permissions = { canBeStolen = false, canBeUsedByAll = false, canBeDamagedByAll = true, canBeRefueledByAll = false, } ``` - `canBeStolen`: non-owner can dismantle the rubble for materials - `canBeUsedByAll`: non-owner can open the panel, reload, take manual control - `canBeDamagedByAll`: non-owner weapons can damage the hull - `canBeRefueledByAll`: non-owner can pour fuel in Fixed turrets can additionally set `canBeUsedByJob = { 'police', 'sheriff' }` to gate access by job name. **shared/config.lua** ```lua weaponDamage = { [`WEAPON_PISTOL`] = 5, [`WEAPON_ASSAULTRIFLE`] = 20, [`WEAPON_SNIPERRIFLE`] = 40, [`WEAPON_HEAVYSNIPER`] = 80, [`WEAPON_RPG`] = 500, [`WEAPON_UNARMED`] = 0, } ``` Absolute HP damage per hit per weapon. Whitelist, a weapon NOT in this table cannot damage the turret (anti-forge exploit). `0` means explicit immunity. Backticks convert the weapon name to its hash at load time. **shared/config.lua** ```lua destroyedProp = 'prop_rub_scrap_02', canBeDismantled = true, dismantleReturn = { { item = 'steel_scrap', min = 3, max = 6 }, { item = 'electronics', min = 1, max = 2 }, }, dismantleTime = 8000, ``` - `destroyedProp`: rubble prop spawned when the turret dies. Set `nil` for no rubble (cinders + explosion only) - `canBeDismantled`: shows the Dismantle option on the rubble - `dismantleReturn`: array of `{ item, min, max }`. Each entry rolls a random quantity and gives it to the dismantler - `dismantleTime`: progress bar duration in ms ## Invulnerability Flags Optional type-wide flags. Fixed turrets can override per-instance. **shared/config.lua** ```lua -- Config.Turrets[type] -- infiniteHealth = true, -- infiniteAmmo = true, -- infiniteFuel = true, ``` - `infiniteHealth`: turret never takes damage. Short-circuits the damage pipeline server-side. Makes `canBeRepairedAfterDestruction`, `permanentDestruction`, `stayDestroyed` and `destroyedProp` irrelevant for this type - `infiniteAmmo`: ammo never depletes - `infiniteFuel`: fuel never depletes ## Post-destruction Behaviour **shared/config.lua** ```lua -- Config.Turrets[type] -- canBeRepairedAfterDestruction = false, -- permanentDestruction = true, ``` Per-type overrides for the destruction flow. - `canBeRepairedAfterDestruction`: overrides the global `Config.Destruction.canBeRepairedAfterDestruction`: - `true`: rubble can be rebuilt in place with `destructionRepairItem` (restores 50% HP) - `false`: rubble still spawns but the Repair option is hidden (dismantle-only) - `nil`: inherit the global value - `permanentDestruction`: overrides everything else: - `true`: death = game over. No rubble, no repair option. DB row deleted instantly, player quota frees up right away. On fixed turrets, persists `is_destroyed=1` so the turret stays gone across restarts ## Fixed Turrets **shared/config.lua** ```lua Config.FixedTurrets = { { id = 'paleto_police_roof', type = 'bazq_heavy', coords = vec3(-443.06, 6034.73, 30.34), heading = 270.0, infiniteHealth = true, infiniteAmmo = false, infiniteFuel = false, refillOnRestart = true, stayDestroyed = false, defaultCaliber = '50cal', permissions = { canBeUsedByAll = true }, targeting = { targetPlayers = false, targetZombies = true }, activationZone = { type = 'sphere', radius = 70.0 }, ai = { enabled = true, toggleableBy = { jobs = { 'police' } } }, }, } ``` Admin-defined permanent turrets. Each entry spawns on every server start. - `id`: unique string used as `fixed_config_id` in the DB. Required - `type`: must match a `Config.Turrets[type]` key - `coords` / `heading`: spawn transform - `infiniteHealth` / `infiniteAmmo` / `infiniteFuel`: per-instance overrides of the type-level flags - `refillOnRestart`: wipes the DB row at boot, so health/ammo/fuel reset to max every restart - `stayDestroyed`: if `true` and the turret was destroyed last session (`is_destroyed=1` in DB), skip spawn on restart. Admin must run `/turret_revive ` to bring it back. Takes precedence over `refillOnRestart` - `defaultCaliber`: calibre loaded at spawn - `permissions`: per-instance override of the type's permission block (e.g. make this specific turret public) - `targeting`: per-instance override of `targetPlayers` / `targetHumans` / `targetZombies` - `activationZone`: boundary (sphere/box/poly) where the AI will engage. Independent from scan range - `ai.enabled`: AI master switch for this instance - `ai.toggleableBy`: ACE or job policy for who can toggle the AI from the panel ## Discord Webhooks **server/config_server.lua** ```lua Config.Server.webhooks = { placed = '', destroyed = '', dismantled = '', repaired = '', ammoLoaded = '', fueled = '', aiToggle = '', exploits = '', } ``` - `placed`: fires on `turret_placed` (new turret spawned from a kit) - `destroyed`: fires on `turret_destroyed` (HP reached 0) - `dismantled`: fires on `turret_dismantled` (rubble smashed for parts) - `repaired`: fires on `repair_applied` (HP restored via repair item) - `ammoLoaded`: fires on `ammo_loaded` (rounds loaded from the panel) - `fueled`: fires on `fuel_added` (fuel poured in) - `aiToggle`: fires on `ai_toggle` (AI turned on/off) - `exploits`: fires on `exploit_attempt` (security flag threshold reached) Set any webhook to `false` to disable that log entirely. ## Admin Override **server/config_server.lua** ```lua Config.Server.admin = { acePermission = 'group.admin', fallbackIdentifiers = {}, -- { 'license:abc123...' } } ``` - `acePermission`: ACE permission that enables debug commands (`/turret_compose`, `/turret_muzzles`, `/turret_revive`, ...) even when `Config.Debug = false` - `fallbackIdentifiers`: identifier whitelist checked when ACE is not available (e.g. `license:abc...`, `discord:...`)