Configuration
Every option in money laundering's config.lua with its default value, plus the text prompt setting, the Discord logs in logs.lua and the text in strings.lua.
All settings live in config.lua at the root of the resource. It ships unescrowed, along with strings.lua (every line of text), logs.lua (Discord webhooks), the framework bridge and the two functions.lua files. The sections below follow the file from top to bottom.
config.lua is read when the resource starts, so restart lation_laundering after a change. Times are written with the file's own Seconds, Minutes and Hours (1000, 60000 and 3600000 milliseconds).
Debug and update check
| Option | Default | What it does |
|---|---|---|
Config.Debug | false | Prints the server's step-by-step log lines in the console, and outlines the target zones on qb-target and qtarget. Leave it off on a live server. |
Config.VersionCheck | true | Checks for a newer release on start and prints a notice in the server console when there is one. |
Interfaces
| Option | Default | What it does |
|---|---|---|
Config.Menu | 'ox_lib' | The menus: 'lation_ui', 'ox_lib', 'esx' (ESX's context menu) or 'qb' (qb-menu). |
Config.Target | 'none' | How players interact: 'ox_target', 'qb-target', 'qtarget', 'custom' or 'none' for text prompts. With lation interact, use 'ox_target'. 'custom' is written in client/functions.lua; see developers. |
Config.Progress | 'ox_lib' | The progress bars: 'lation_ui', 'ox_lib', 'qbcore' or 'custom'. A custom one must play the animation and attach the prop it's given. |
Config.Notify | 'ox_lib' | The notifications: 'lation_ui', 'ox_lib', 'esx', 'qb', 'okok' (okokNotify), 'sd-notify', 'wasabi_notify' or 'custom'. Where the system shows a title, it's Money Laundering. |
Config.InteractKey | 38 | The key for text prompts, as a control id (38 is E). Only used with Config.Target = 'none'. The prompts say "E" in their text, so change Strings.TextUI with it. |
With Config.Menu = 'esx', the menu's Warehouse row does nothing, so players can't buy the warehouse key from it. Use another menu if players need the warehouse.
The alerts (a buyer turning a player down, the key purchase confirm, a finished wash) and the amount dialogs at the washer and the counters always use ox_lib.
Text prompts
The system that draws the text prompts isn't in config.lua. It's the first setting in client/functions.lua:
-- Options: 'lation_ui', 'ox_lib', 'jg-textui', 'okokTextUI', 'qbcore' & 'custom'
local textui = 'lation_ui'The default needs lation_ui running. Without it, set 'ox_lib'. A prompt shows when the player is on foot within 2 m of the launderer, a buyer, the warehouse door, the washing machine or a money counter.
Phone
| Option | Default | What it does |
|---|---|---|
Config.Phone | 'none' | Where the player hears that a wash is done: 'qb-phone', 'npwd', 'qs-smartphone', 'qs-smartphonepro', 'lb-phone', 'gksphone', 'yseries' or 'custom'. 'none' shows an alert on screen. |
Most phones get a mail from Warehouse, subject Money Status: "Your money is now done & ready to be picked up." npwd gets a text and gksphone a message. The text is Strings.Phone.
Start
The launderer, where players open the menu.
Config.Start = {
spawnPed = true,
randomizeSpawn = false,
require = false,
item = { name = 'water', quantity = 1, remove = false },
render = 75,
model = 'g_m_importexport_01',
locations = {
vec4(138.6853, 270.6841, 109.9740, 73.0269),
}
}| Option | Default | What it does |
|---|---|---|
spawnPed | true | Spawns a launderer at the locations. Set false to have none and open the menu your own way with the OpenMenu export. |
randomizeSpawn | false | Puts one launderer at a location picked at random each time the resource starts, instead of one at every location. |
require | false | Requires an item to open the menu. Without it, the player is told "I don't think you're ready..". |
item.name | 'water' | The required item. |
item.quantity | 1 | How many they must carry. |
item.remove | false | Takes one of the item each time the menu opens. |
render | 75 | Meters from a location at which its launderer appears. |
model | 'g_m_importexport_01' | The launderer's ped model. |
locations | one location | Where launderers stand, as vec4. |
The server checks that a player is within 15 m of one of these locations before it takes the car deposit, refunds it or sells the warehouse key. If you open the menu elsewhere with the export, add those places here too.
Police
Config.Police = {
jobs = { 'police', 'sheriff' },
require = false,
count = 3,
warehouseAccess = true,
enableDispatch = false,
dispatchSystem = 'none'
}| Option | Default | What it does |
|---|---|---|
jobs | { 'police', 'sheriff' } | The police jobs: counted for require, let into the warehouse, and, for the dispatch systems that take a job list, sent the calls. |
require | false | Requires police in the city to start each contract. Doesn't apply to the warehouse. |
count | 3 | How many. On QBCore and Qbox only players on duty count; on ESX, every player with one of the jobs. |
warehouseAccess | true | Lets police into the warehouse without a key or the level. They still need the level to wash and count while Config.Warehouse.requireLvl is on. |
enableDispatch | false | Sends a dispatch call when a buyer turns a player down. Needs Config.Reject.enable. |
dispatchSystem | 'none' | 'cd_dispatch', 'ps-dispatch', 'qs-dispatch', 'core_dispatch', 'rcore_dispatch', 'aty_dispatch', 'linden_outlawalert' or 'custom'. |
The call is "10-911 Suspicious Activity" at the player's position and street. A 'custom' dispatch is written in PoliceDispatch in client/functions.lua.
Items
Config.Items = {
key = 'warehouse_key',
uncountedMoney = 'uncounted_money'
}| Option | Default | What it does |
|---|---|---|
key | 'warehouse_key' | The item that opens the warehouse. |
uncountedMoney | 'uncounted_money' | The item a finished wash gives, counted into cash at a money counter. |
The dirty money isn't set here: each level names its own in dirtyMoney.
QBCore dirty money
How markedbills and cashrolls are read on QBCore and Qbox. Other items, and every item on ESX, count as $1 each.
Config.QBCore = {
metadata = true,
countTotal = true,
takeAll = false,
hardValues = false,
items = {
['markedbills'] = 500,
}
}| Option | Default | What it does |
|---|---|---|
metadata | true | Counts each bag at the worth stored on it, as QBCore's markedbills carry. false counts each as $1. On Qbox, set false if your dirty money is markedbills. |
countTotal | true | Adds up every bag the player carries. false counts only the first one found, so players wash one bag at a time. |
takeAll | false | With metadata on, a buyer offers to take everything the player carries instead of an amount in the level's range. |
hardValues | false | Ignores any stored worth and counts each item at the value in items. |
items | { ['markedbills'] = 500 } | The value of each item for hardValues. |
With metadata on, a bag worth more than a deal is swapped for one holding the rest. With hardValues, whole items are taken until the deal is covered, and nothing comes back.
The server refuses a contract whose clean payout is over the level's top amount raised by its negotiate multiplier. With takeAll, a large bag goes over that and the deal pays nothing.
Contract car
Config.Vehicle = {
spawn = true,
teleport = true,
fuel = 85.0,
models = { 'baller3', 'fugitive' },
random = true,
requireDeposit = true,
depositPrice = 500,
returnDeposit = true,
depositReturn = 250,
account = 'cash',
locations = {
vec4(125.9180, 278.1013, 109.9004, 249.8953),
}
}| Option | Default | What it does |
|---|---|---|
spawn | true | Gives players a car when they start a run and have none out. |
teleport | true | Puts the player in its driver's seat. |
fuel | 85.0 | Its fuel, through LegacyFuel, cdn-fuel, ps-fuel, lj-fuel, okokGasStation or nd_fuel when running, and its fuel state bag. Keep the .0. |
models | { 'baller3', 'fugitive' } | The car models. |
random | true | Picks a model at random. false always uses the first. |
requireDeposit | true | Charges a deposit for the car. |
depositPrice | 500 | The deposit. |
returnDeposit | true | Refunds part of it when the player picks Return Vehicle at the launderer. |
depositReturn | 250 | The refund. |
account | 'cash' | The account for the deposit and refund: 'cash' or 'bank'. |
locations | one location | Where cars spawn, as vec4. The one nearest the player is used, so give each launderer location one. |
Keys are given through wasabi_carlock, okokGarage, qb-vehiclekeys, qs-vehiclekeys, cd_garage, vehicles_keys, t1ger_keys or Renewed-Vehiclekeys, whichever runs. Others go in GiveKeys in client/functions.lua.
Rejections
Config.Reject = {
enable = true,
continue = true
}| Option | Default | What it does |
|---|---|---|
enable | true | Lets buyers turn players down, by each level's rejectChance. |
continue | true | Marks the next buyer after a rejection or a lost negotiation. false ends the run. |
Warehouse
Config.Warehouse = {
unlockAt = 5,
allowContracts = false,
requireLvl = true,
requirePurchase = true,
price = 2500,
account = 'cash',
showBlip = true,
enterAt = vec4(1142.6859, -986.6674, 45.9059, 96.6889),
exitAt = vec4(1138.0872, -3199.1570, -39.6657, 181.2139),
rotate = 180,
isMLO = false,
duration = 1 * Hours + 25 * Minutes + 30 * Seconds,
-- washer, counters, limits: below
disable = { 200, 36 },
convertTo = 'cash'
}| Option | Default | What it does |
|---|---|---|
unlockAt | 5 | The level that opens the warehouse: the key in the menu, the blip, and by default entry and use. Its level's dirtyMoney is what the washer takes. |
allowContracts | false | Lets players keep running contracts once they reach unlockAt. Off, buyers refuse them and the menu drops New Contract. |
requireLvl | true | Requires unlockAt to enter, wash, pick up and count. false lets anyone with a key in, though only players who have reached unlockAt can buy keys. |
requirePurchase | true | Charges for the key. false gives it free from the menu. |
price | 2500 | The key's price. |
account | 'cash' | The account it's paid from: 'cash' or 'bank'. |
showBlip | true | Marks the door with the warehouse blip, for players at unlockAt and anyone who buys a key. |
enterAt | vec4(1142.6859, -986.6674, 45.9059, 96.6889) | The door outside, where players enter and come back out. |
exitAt | vec4(1138.0872, -3199.1570, -39.6657, 181.2139) | Where players arrive inside, and the way out. |
rotate | 180 | Degrees added to the heading when a player arrives on either side, so they face the right way. |
isMLO | false | Set true when the warehouse is an MLO players walk into: the door and way out points are dropped. |
duration | 1 * Hours + 25 * Minutes + 30 * Seconds | How long a wash takes. It counts while the player is on the server and is saved when they leave or the server restarts. |
disable | { 200, 36 } | Controls turned off while counting, as control ids: 200 is Esc, 36 is Left Ctrl. |
convertTo | 'cash' | Where counted money goes: 'cash' or 'bank'. |
The default warehouse is the counterfeit cash factory interior, which bob74_ipl fills with its machines. To use another place, move enterAt, exitAt, the washer and the counters.
Washer and counters
washer = {
coords = vec3(1122.4, -3193.5, -40.35),
size = vec3(1.7, 4.35, 2.1),
rotation = 0,
debug = false,
},
counters = {
[1] = {
coords = vec3(1116.0024, -3194.9362, -40.5910),
size = vec3(3.2, 1.0, 1.8),
rotation = 0,
radius = 0.35,
offset = vec3(0.6327, 0.0385, -0.8101),
heading = 88.88,
debug = false
},
[2] = {
coords = vec3(1116.0164, -3196.2717, -40.5917),
size = vec3(3.2, 1.0, 1.8),
rotation = 0,
radius = 0.35,
offset = vec3(0.5997, 0.0329, -0.8074),
heading = 88.88,
debug = false
},
},| Option | Default | What it does |
|---|---|---|
washer.coords | vec3(1122.4, -3193.5, -40.35) | The washing machine players use. |
washer.size | vec3(1.7, 4.35, 2.1) | The zone around it, for text prompts. |
washer.rotation | 0 | The zone's rotation, for text prompts. |
washer.debug | false | Draws the zone, for text prompts. |
counters | two counters | The money counters, one entry each. Add more in the same shape; this makes counters in the interior usable and doesn't place any. |
coords | The money counter. | |
size, rotation, debug | Its zone, for text prompts. | |
radius | 0.35 | Its target zone's radius. |
offset | Where the chair goes and the player sits, from coords. | |
heading | 88.88 | The way the player faces while counting. |
Limits
limits = {
washing = { min = 500, max = 25000 },
counting = { min = 0, max = 15000, interval = 2500 }
},| Option | Default | What it does |
|---|---|---|
limits.washing.min | 500 | The least dirty money one wash takes. |
limits.washing.max | 25000 | The most. Contract amounts are set per level instead. |
limits.counting.min | 0 | The least a player can count at a sitting. |
limits.counting.max | 15000 | The most. |
limits.counting.interval | 2500 | Money per counting animation, about 18 seconds each: $10,000 plays it 4 times. |
Levels
Config.Levels = {
[1] = { dirtyMoney = 'markedbills', taxRate = 25, clean = { min = 500, max = 1000 }, addXP = 1000, negotiateChance = 60, multiplier = 25, rejectChance = 20 },
[2] = { dirtyMoney = 'markedbills', taxRate = 20, clean = { min = 750, max = 1500 }, addXP = 500, negotiateChance = 70, multiplier = 50, rejectChance = 15 },
[3] = { dirtyMoney = 'markedbills', taxRate = 15, clean = { min = 1000, max = 2000 }, addXP = 250, negotiateChance = 80, multiplier = 75, rejectChance = 10 },
[4] = { dirtyMoney = 'markedbills', taxRate = 10, clean = { min = 1500, max = 3000 }, addXP = 125, negotiateChance = 90, multiplier = 100, rejectChance = 5 },
[5] = { dirtyMoney = 'markedbills', taxRate = 5, clean = { min = 2000, max = 10000 }, addXP = 1, negotiateChance = 95, multiplier = 125, rejectChance = 0 },
}
Config.LevelUp = 100000
Config.AllowNegotiations = trueThe file spreads each level over several lines with notes; the values are these.
| Field | What it does |
|---|---|
dirtyMoney | The dirty money buyers take at this level: an item such as markedbills, or on ESX the black_money account. |
taxRate | The percent kept from every deal and wash. |
clean.min, clean.max | The range a buyer's offer is drawn from, in dirty money. |
addXP | XP for each contract and each warehouse wash. |
negotiateChance | Percent chance a buyer agrees to a higher offer. |
multiplier | Percent a successful negotiation adds to the offer. |
rejectChance | Percent chance a buyer turns the player down. Needs Config.Reject.enable. |
Levels are numbered from 1 with no gaps; add or remove them freely. The last one is the top: it earns no more XP. A level's clean, negotiateChance, multiplier and rejectChance matter only while it can run contracts, so not at unlockAt and above unless allowContracts is on.
| Option | Default | What it does |
|---|---|---|
Config.LevelUp | 100000 | XP from one level to the next. The leftover carries over. To speed up or slow down a level, change its addXP. |
Config.AllowNegotiations | true | Shows the Negotiate menu when a player carries more than the offer. |
Blips
Config.Blips = {
start = { enabled = true, sprite = 47, color = 0, scale = 0.8, label = 'Money Laundering' },
contracts = { sprite = 500, color = 2, scale = 0.8, label = 'Money Contract' },
warehouse = { sprite = 473, color = 17, scale = 0.8, label = 'Warehouse' }
}| Option | Default | What it does |
|---|---|---|
start.enabled | true | Marks each launderer. |
contracts | sprite 500, color 2 | The buyer's blip, shown for every contract. |
warehouse | sprite 473, color 17 | The door's blip; turn it off with Config.Warehouse.showBlip. |
sprite, color, scale, label | The blip's icon, color, size and name. |
Animations
Config.Animations = {
accept = {
label = 'Making deal..',
duration = 5000,
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { move = true, car = true, combat = true },
anim = { dict = 'missfam4', clip = 'base' },
prop = { model = `p_amb_clipboard_01`, bone = 36029, pos = vec3(0.160, 0.080, 0.100), rot = vec3(-130.00, -50.00, 0.00) }
},
negotiate = {
label = 'Negotiating..',
duration = 6000,
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { move = true, car = true, combat = true },
anim = { dict = 'misscarsteal4@actor', clip = 'actor_berating_loop' },
prop = { }
},
wash = {
duration = 1500,
anim = { dict = 'missfbi_s4mop', clip = 'put_down_bucket' }
},
count = {
anim = { dict = 'anim@amb@business@cfm@cfm_counting_notes@', clip = 'note_counting_counter' },
props = {
chair = 'v_corp_cd_chair',
briefcase = 'prop_cash_case_02',
cash = 'bkr_prop_money_sorted_01',
cashWrapped = 'bkr_prop_money_wrapped_01'
}
}
}| Option | What it does |
|---|---|
accept | The progress bar for making a deal: label, duration in milliseconds, position (ox_lib only), useWhileDead, canCancel, the controls it disables, the anim and the prop in hand. |
negotiate | The progress bar for negotiating, in the same shape. |
wash | The animation at the washing machine and how long it plays. |
count | The counting animation and its props: the chair and briefcase placed at the counter, and the loose and wrapped cash in hand. |
Buyer locations and models
| Option | Default | What it does |
|---|---|---|
Config.Locations | 77 locations | Where buyers wait, as vec4, across Los Santos. Each contract picks one at random. The deal is refused more than 15 m from it. |
Config.Models | 84 ped models | The buyers' ped models, picked at random for each contract. |
Logs
Discord webhooks, in logs.lua. The file is loaded on the server only, so players never receive your webhook URLs.
Logs.Name = 'Laundering Logs'
Logs.Image = 'https://i.imgur.com/ILTkWBh.png'
Logs.Footer = 'https://i.imgur.com/ILTkWBh.png'
Logs.Types = {
levelUp = { enabled = false, webhook = '' },
contracts = { enabled = false, webhook = '' },
warehouse = { enabled = false, webhook = '' },
counting = { enabled = false, webhook = '' },
negotiate = { enabled = false, webhook = '' },
rejected = { enabled = false, webhook = '' },
warehouseKey = { enabled = false, webhook = '' }
}| Option | What it does |
|---|---|
Logs.Name, Logs.Image, Logs.Footer | The webhook's name, its avatar, and the icon by the footer's date. |
levelUp | A player reaching a new level. |
contracts | A finished contract: dirty money in and clean cash out. |
warehouse | A wash picked up: dirty money in and uncounted money out. |
counting | Money counted into cash. |
negotiate | A negotiation, from and to, and whether the buyer agreed. |
rejected | A buyer turning a player down. |
warehouseKey | A warehouse key bought, and its price. |
Each log names the player, their server id and their identifier. Set enabled = true and paste the webhook URL to turn one on. The levelUp log currently posts whenever it has a webhook, enabled or not.
Text
Every line players read is in strings.lua, in English, grouped by where it shows. Edit it to reword or translate.
| Table | Holds |
|---|---|
Strings.Notify | Notifications, including the time left on a wash |
Strings.Targets | Target option names, labels, icons and distances |
Strings.TextUI | Text prompt labels and icons |
Strings.Alert | The buyers' refusals and the key purchase confirm |
Strings.Inputs | The washing and counting amount dialogs |
Strings.Menu | The main, negotiate and final offer menus, and the experience bar's colors |
Strings.Phone | The message sent when a wash is done |
Strings.Logs | Discord log titles, colors and lines |
Still stuck? Ask in our Discord: the people who write the scripts answer.
Last updated
Contracts and the warehouse
How players open the money laundering menu, take contracts to buyers around the city, negotiate, level up, and wash and count money at the warehouse, with the default numbers.
Developers
The money laundering client and server exports, its notification event, the hooks in its open files and the integrations you can edit, with signatures and Lua examples.