Laundromat Heist Configuration Reference

6 min read

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
KeyDefaultPurpose
crewSize1Requirement to start and the hard cap on who joins at prep
prepBankHours24Resume a finished-but-not-started prep within this many hours
prepTimeLimit1200Seconds to finish prep (0 / nil = unlimited)
mapResourcewxmaps_laundromatHeist 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.