Laundromat Heist Configuration Reference
Everything tunable lives in config/config.lua (kept editable via escrow_ignore). World placement (guard routes, camera positions, safe/vent/washer spots, drop-off points) is in config/locations.lua, and the RC arm rig is in config/arm_config.lua. A normal server owner only needs config.lua.
Each block below lists the key, its default, and what it does. Defaults are the shipped values. Turn whole features on/off at their top-level enabled flag.
Core switches
Config.Enabled = true -- master switch for the whole resource
Config.Debug = false -- console prints + debug notifies (set false in production)
Config.DevMode = false -- registers the ACE authoring/test commands (set false in production)
Config.RequireDatabase = true -- refuse to start a heist if the economy DB is down (anti-bypass)
Config.Framework = 'auto' -- 'auto' | 'qbox' | 'qbcore' | 'esx' | 'standalone'
Config.Target = 'auto' -- 'auto' | 'ox_target' | 'qb-target' | 'qtarget'
Config.Inventory = 'auto' -- 'auto' | 'ox_inventory' | 'qb-inventory'
Crew & timing
Config.Heist.crewSize = 1 -- EXACT players to start AND the prep join cap (4 = production)
Config.Heist.crewRadius = 10.0 -- how close crew must be at start
Config.Heist.prepBankHours = 24 -- hours a finished prep is banked (0 disables)
Config.Heist.prepTimeLimit = 1200 -- max seconds to complete prep (0/nil = no limit)
Config.Heist.mapResource = 'wxmaps_laundromat' -- the resource holding the laundromat ymaps
Config.Heist.schedule = { minutes = 1 } -- real minutes after the boss appointment before auto-start
| Key | Default | Purpose |
|---|---|---|
crewSize | 1 | Requirement to start and the hard cap on who joins at prep |
prepBankHours | 24 | Resume a finished-but-not-started prep within this many hours |
prepTimeLimit | 1200 | Seconds to finish prep (0 / nil = unlimited) |
mapResource | wxmaps_laundromat | Heist locations only run where this map's ymaps are present |
Prep objectives (toggle each)
Config.Heist.prep.scout.enabled = true -- microcamera scouting
Config.Heist.prep.gunVan.enabled = true -- weapon truck
Config.Heist.prep.cameras.enabled = true -- disable-cameras (cable-cut) objective
Config.Heist.prep.craft.enabled = true -- RC Bandito crafting
The gun van weapon list, prices, and charge account:
Config.Heist.prep.gunVan.account = 'money' -- 'money' (cash) or 'bank'
Config.Heist.prep.gunVan.weapons = {
{ name = 'WEAPON_KNIFE', label = 'Knife', price = 750 },
{ name = 'WEAPON_PISTOL', label = 'Pistol', price = 2500 },
{ name = 'WEAPON_PUMPSHOTGUN', label = 'Pump Shotgun', price = 6000 },
{ name = 'WEAPON_CROWBAR', label = 'Crowbar', price = 500 },
}
The disable-cameras cable minigame + fail alarm:
Config.Heist.prep.cameras.cable = { pairs = 8, cycleLength = 4, timeLimit = 0 }
Config.Heist.prep.cameras.hackFailAlarm = { enabled = true, attempts = 3, delaySeconds = 10 }
Guard & stealth
Config.Guard.enabled = true
Config.Guard.model = `s_m_m_armoured_01`
Config.Guard.invincible = false -- killable; it NEVER shoots, it radios you in instead
Config.Pass.stealth.vision = {
range = 12.0, -- how far ahead the guard can spot (m)
angle = 45.0, -- half-angle of the cone (deg) => 90° total FOV
requireLos = true, -- walls block line of sight
}
The only safe approach to the guard is crouched. Standing too close, or being in its cone while armed, raises suspicion; if the bar fills, the guard radios it in (prep = job blown, heist = alarm raised once).
Safe (loot)
Config.Safe.enabled = true
Config.Safe.reward = { cashMin = 50000, cashMax = 90000, item = 'money' } -- cash placed in the stash (grabbed, not auto-credited)
Config.Safe.code = { enabled = true, slots = 4, dialMax = 100 } -- 4 two-digit turns => an 8-char code
Config.Safe.stash = { id = 'vs_laundro_safe', label = 'Office Safe', slots = 10, maxWeight = 100000 }
Config.Safe.loot = { --[[ optional filler valuables, must exist in your inventory ]] }
Washing machines
Config.WashingMachines.enabled = true
Config.WashingMachines.reward = { cashMin = 500, cashMax = 1500, account = 'money' } -- per machine
Config.WashingMachines.maxHeistPayout = { min = 6000, max = 8000 } -- TOTAL wash cash, rolled once per heist (0/nil = uncapped)
Config.WashingMachines.minigame = { hits = 3 } -- clean hits to break a lock (breach-force)
Config.WashingMachines.maxAttempts = 2 -- failed attempts before a lock snaps for good
Config.WashingMachines.overloadDurabilityLoss = 40 -- durability knocked off the tool on OVERLOAD (ox only; 0 disables)
Contract: package, delivery & debt
Config.Contract.enabled = true
Config.Contract.requests = {
{ item = 'jewels', label = 'the jewels', count = 1 },
{ item = 'documents', label = 'the documents', count = 1 },
{ item = 'coke_small_brick', label = 'the coke', count = 1 },
} -- one is picked at random per heist; the item MUST exist in your inventory
Config.Contract.deliver = {
windowOpen = 5, -- minutes after start before the boss will take it
windowClose = 15, -- minutes after start the window shuts (miss it = debt)
bonusMin = 25000,
bonusMax = 40000,
}
Config.Contract.debt = {
amount = 30000, -- cash owed by the crew leader on a failed delivery
account = 'cash',
transferOnLeaderCrash = true, -- new leader inherits the debt if the leader disconnects
}
Config.Contract.payout = {
type = 'cash', -- 'cash' (wallet) | 'dirty' (a launderable item)
cashAccount = 'money', -- 'money'/'cash' = wallet, 'bank' = bank
dirtyItem = 'black_money', -- type='dirty': the item name (must exist)
}
Set Config.Contract.payout.type = 'dirty' to pay cash rewards as a launderable item (dirtyItem) instead of wallet cash, a natural tie-in with a money-laundering loop. The item must be a registered item in your inventory or the payout is lost.
Reputation & bosses
Config.Boss.clan = 'the_firm' -- shared org id; reputation is tracked per clan, across scripts
Config.BossRotation.enabled = true -- rotating clan contacts
Config.BossRotation.inGameDayMinutes = 48
Config.Reputation.enabled = true
Config.Reputation.perDelivery = 1 -- rep per on-time delivery (a clan tier may override)
Four clans ship with their own tier ladders and perks. Full breakdown on the Bosses & reputation page.
Police alert (dispatch)
Config.PoliceAlert.enabled = true
Config.PoliceAlert.jobs = 'police' -- a single job, or a list: { 'police', 'sheriff', 'bcso' }
Config.PoliceAlert.title = 'Silent Alarm: 10-31'
Config.PoliceAlert.message = 'Break-in in progress at a laundromat.'
Config.PoliceAlert.triggers = {
onSafeOpened = { enabled = true }, -- alert the instant the safe is first opened
onWashers = { enabled = true, count = 5 }, -- alert after N washers robbed
afterTime = { enabled = true, minutes = 5 }, -- alert N minutes after the heist begins
}
Point jobs at your server's police job(s) to plug into your dispatch/CAD.
Audit logging
Two independent, off-by-default sinks record money-moving events:
Config.Audit.db = false -- MySQL table vs_laundro_audit
Config.Audit.discord = {
enabled = false,
webhook = '', -- use a PRIVATE staff channel: embeds include citizenid + amount
name = 'Laundromat',
color = 3447003,
}
The Discord audit embeds include citizenid + amounts. Only ever point the webhook at a private staff channel.
Localization
All player-facing text goes through ox_lib locales. Add locales/<lang>.json and set the language with the convar:
setr ox:locale en
Every string is a locale('key', ...) lookup, so translating is a matter of dropping in a language file. See ox_lib locales.