NR_MoneyWash
A multi-framework portable washing machine system (ESX, QBCore, QBX) with auto-detection, custom React tablet UI, lockpicking, police interactions, rank progression, package run missions, dispatch integration, and configurable themes.
Features
- Portable washing machines - Place anywhere in the world with advanced placement controls (rotate, height adjust, nudge, ground snap toggle)
- Custom React tablet UI - Full tablet interface with wash management, key management, rank display, and mission launching
- Rank & XP system - 10 ranks from Novice to Kingpin with increasing wash limits, XP rewards, and tax reductions per rank
- Package run missions - Collect suspicious packages from randomized locations across the map, deliver them to earn dirty money and XP for your washer
- Lockpick / break-in system - NUI lockpick minigame with configurable pins, speed, and sweet spot — steal finished washes from other players
- Police interactions - On-duty police can inspect washers, seize money, and confiscate washers as evidence
- Dispatch integration - Auto-detects 13+ dispatch resources (ps-dispatch, cd_dispatch, qs-dispatch, rcore_dispatch, and more) for mission police alerts
- Key management - Share access with other players (up to 10 keys per washer)
- Lock system - Secure your machine from unauthorized users
- Progress tracking - Real-time wash tracking with timestamps
- Pick up system - Retrieve your machine when done
- Configurable themes - Fully customizable UI colors via config.lua
- Multi-framework support - Auto-detects ESX, QBCore, or QBX
- Multi-inventory support - Supports ox_inventory, qs-inventory, codem-inventory, origen_inventory, core_inventory, tgiann-inventory, qb-inventory, ps-inventory, lj-inventory, mf-inventory, ak47 inventories, and more (auto-detected)
- Multi-target support - Supports ox_target and qb-target with auto-detection
- External UI support - Optional is_ui integration for progress bars and notifications
- Anti-cheat protection - Rate limiting, distance validation, cooldowns, timing checks, suspicious activity logging, and optional player drops
Dependencies
| Resource | Description | Required |
|---|---|---|
| es_extended / qb-core / qbx_core | Core framework (auto-detected) | One of these |
| ox_lib | Shared library | Yes |
| oxmysql | Database | Yes |
| Inventory system | ox_inventory, qs-inventory, codem-inventory, origen_inventory, core_inventory, tgiann-inventory, qb-inventory, ps-inventory, lj-inventory, mf-inventory, ak47 inventories, and more (auto-detected) | One of these |
| ox_target / qb-target | Target/interaction system (auto-detected) | One of these |
| Dispatch system | ps-dispatch, cd_dispatch, codem-dispatch, qs-dispatch, core_dispatch, origen_dispatch, rcore_dispatch, kartik-dispatch, linden_outlawalert, op-dispatch, aty_dispatch, emergencydispatch (auto-detected) | Optional |
Installation
Step 1: Download & Build
Download NR_MoneyWash from your Tebex purchase and install it into your server resources:
server/
└── resources/
└── [echo]/
└── NR_MoneyWash/
Step 2: Database Setup
The script automatically creates the required database table on first start. No manual SQL import needed.
Step 3: Add Inventory Items
Add the following items to your inventory system. Choose the format that matches your setup:
ox_inventory — Add to ox_inventory/data/items.lua:
['washing_machine'] = {
label = 'Portable Washing Machine',
weight = 25000,
stack = false,
close = true,
description = 'A portable washing machine used to clean dirty money.',
client = {
image = 'washing_machine.png',
},
server = {
export = 'NR_MoneyWash.washing_machine'
}
},
['black_money'] = {
label = 'Dirty Money',
weight = 0,
stack = true,
close = false,
description = 'Money that needs to be cleaned before it can be used.'
},
['advanced_lockpick'] = {
label = 'Advanced Lockpick',
weight = 200,
stack = true,
close = true,
description = 'A high-quality lockpick for bypassing advanced locks.'
},
['suspicious_package'] = {
label = 'Suspicious Package',
weight = 5000,
stack = true,
close = false,
description = 'A suspicious-looking package. Best not to ask questions.'
},
qb-core — Add to qb-core/shared/items.lua:
washing_machine = { name = 'washing_machine', label = 'Portable Washing Machine', weight = 25000, type = 'item', image = 'washing_machine.png', unique = true, useable = true, shouldClose = true, description = 'A portable washing machine used to clean dirty money.' },
black_money = { name = 'black_money', label = 'Dirty Money', weight = 0, type = 'item', image = 'black_money.png', unique = false, useable = false, shouldClose = false, description = 'Money that needs to be cleaned before it can be used.' },
advanced_lockpick = { name = 'advanced_lockpick', label = 'Advanced Lockpick', weight = 200, type = 'item', image = 'advanced_lockpick.png', unique = false, useable = false, shouldClose = true, description = 'A high-quality lockpick for bypassing advanced locks.' },
suspicious_package = { name = 'suspicious_package', label = 'Suspicious Package', weight = 5000, type = 'item', image = 'suspicious_package.png', unique = false, useable = false, shouldClose = false, description = 'A suspicious-looking package. Best not to ask questions.' },
qs-inventory — Add to your items configuration:
['washing_machine'] = {
name = 'washing_machine',
label = 'Portable Washing Machine',
weight = 25000,
type = 'item',
image = 'washing_machine.png',
unique = true,
useable = true,
shouldClose = true,
description = 'A portable washing machine used to clean dirty money.'
},
['black_money'] = {
name = 'black_money',
label = 'Dirty Money',
weight = 0,
type = 'item',
image = 'black_money.png',
unique = false,
useable = false,
shouldClose = false,
description = 'Money that needs to be cleaned before it can be used.'
},
['advanced_lockpick'] = {
name = 'advanced_lockpick',
label = 'Advanced Lockpick',
weight = 200,
type = 'item',
image = 'advanced_lockpick.png',
unique = false,
useable = false,
shouldClose = true,
description = 'A high-quality lockpick for bypassing advanced locks.'
},
['suspicious_package'] = {
name = 'suspicious_package',
label = 'Suspicious Package',
weight = 5000,
type = 'item',
image = 'suspicious_package.png',
unique = false,
useable = false,
shouldClose = false,
description = 'A suspicious-looking package. Best not to ask questions.'
},
ESX (es_extended) — Add items via database SQL:
INSERT INTO `items` (`name`, `label`, `weight`) VALUES
('washing_machine', 'Portable Washing Machine', 25),
('black_money', 'Dirty Money', 0),
('advanced_lockpick', 'Advanced Lockpick', 1),
('suspicious_package', 'Suspicious Package', 5);
The advanced_lockpick item is only needed if lockpicking is enabled in config. The suspicious_package item is only needed if the mission system is being used. Both item names are configurable in config.lua.
Step 4: Add Item Image
Copy install/washing_machine.png from the resource folder to your inventory's image folder (e.g. ox_inventory/web/images/, qs-inventory/html/images/, or qb-inventory/html/images/).
Step 5: server.cfg
Add the resource to your server configuration:
ensure NR_MoneyWash
Step 6: Restart
Restart both resources to apply changes:
restart NR_MoneyWash
restart ox_inventory
Make sure your framework (es_extended, qb-core, or qbx_core), ox_lib, your inventory system, your target system, and oxmysql are all started before NR_MoneyWash in your server.cfg.
Configuration
All settings are in Open/config.lua.
General Settings
ExternalUI = false, -- Use is_ui for progress/notifications (falls back to built-in NUI)
dropCheaters = false, -- Kick players attempting exploits
dirtyMoneyItem = 'black_money', -- Item name for dirty money
moneyItem = 'money', -- Item name for clean money
useSlider = true, -- Use slider for wash amount input
sliderStep = 10, -- Slider increment amount
loadTime = 3, -- Animation duration in seconds
progressCircle = false, -- Use circle instead of bar progress
Theme Colors
Customize the UI theme colors:
theme = {
primary = '#00FFFF', -- Main accent color
text = '#ffffff', -- Main text color
textSecondary = '#a0a0a0', -- Secondary text color
success = '#00ff88', -- Success notifications
error = '#ff4757', -- Error notifications
warning = '#ffa502', -- Warning notifications
},
Popular theme colors:
| Color | Hex Code |
|---|---|
| Cyan (default) | #00FFFF |
| Purple | #9b59b6 |
| Green | #2ecc71 |
| Red | #e74c3c |
| Orange | #f39c12 |
| Blue | #3498db |
Washing Machine Settings
washingMachines = {
['washing_machine'] = {
model = `m23_2_prop_m32_prtmachine_dryer_op`,
label = 'Washing Machine',
msecPer = 100, -- Milliseconds per $1 washed ($10,000 = ~17 minutes)
washTax = 0.35, -- 35% base tax rate (reduced by rank)
},
}
Target Settings
target = {
radius = vec3(2, 2, 2), -- Target zone size
icon = 'fas fa-soap', -- Target icon
distance = 3.0, -- Interaction distance
},
Lockpick Settings
Controls the NUI lockpick minigame that allows non-owners to break into locked washers.
lockpick = {
enabled = true, -- Enable/disable lockpicking
item = 'advanced_lockpick', -- Required item (consumed on use)
pinCount = 5, -- Number of pins to pick
baseSpeed = 0.8, -- Pin rotation speed
speedMultiplier = 1.04, -- Speed increase per pin
baseSweetSpotSize = 0.25, -- Sweet spot size (0-1)
sweetSpotShrink = 0.025, -- Sweet spot shrinks per pin
timePerPin = 5000, -- Time limit per pin (ms)
notifyOwner = true, -- Notify washer owner of break-in attempts
},
Police Settings
police = {
job = 'police', -- Police job name
type = 'leo', -- Police job type (alternative match)
requiredPoliceCount = 0, -- Minimum police online for missions
},
Mission Settings
Missions are "Package Run" jobs where players collect suspicious packages from around the map and deliver them for dirty money and XP rewards.
missions = {
pedModel = 's_m_y_dealer_01', -- NPC ped model at pickup/delivery
chaseVehicle = 'sultan', -- Vehicle model for chase encounters
chaseWeapon = `WEAPON_MICROSMG`, -- Weapon used by chasers
suspiciousPackageItem = 'suspicious_package', -- Item given during pickups
locations = {
vec4(783.35, -1811.54, 30.87, 257.13), -- 34 locations across the map
-- ...
},
},
Rank & XP Settings
Washers have their own XP and rank that affects tax rates, wash limits, mission rewards, and mission danger.
ranks = {
taxReductionPerRank = 0.035, -- Tax reduction multiplier per rank level
levels = {
-- name | xp needed | police% | danger% | pickups | max wash | xp | money
{ name = 'Novice', xp = 0, policeChance = 0.20, dangerChance = 0.20, pickups = 2, maxWash = 10000, xpReward = 20, moneyReward = 500 },
{ name = 'Amateur', xp = 100, policeChance = 0.24, dangerChance = 0.24, pickups = 2, maxWash = 25000, xpReward = 40, moneyReward = 1000 },
{ name = 'Apprentice', xp = 310, policeChance = 0.28, dangerChance = 0.28, pickups = 3, maxWash = 50000, xpReward = 60, moneyReward = 1500 },
{ name = 'Skilled', xp = 630, policeChance = 0.32, dangerChance = 0.32, pickups = 3, maxWash = 100000, xpReward = 80, moneyReward = 2000 },
{ name = 'Expert', xp = 1035, policeChance = 0.36, dangerChance = 0.36, pickups = 4, maxWash = 200000, xpReward = 100, moneyReward = 2500 },
{ name = 'Veteran', xp = 1535, policeChance = 0.40, dangerChance = 0.40, pickups = 4, maxWash = 350000, xpReward = 120, moneyReward = 3500 },
{ name = 'Master', xp = 2235, policeChance = 0.45, dangerChance = 0.45, pickups = 5, maxWash = 500000, xpReward = 140, moneyReward = 4500 },
{ name = 'Grandmaster', xp = 3035, policeChance = 0.50, dangerChance = 0.50, pickups = 5, maxWash = 700000, xpReward = 160, moneyReward = 5500 },
{ name = 'Elite', xp = 4035, policeChance = 0.55, dangerChance = 0.55, pickups = 6, maxWash = 850000, xpReward = 180, moneyReward = 6500 },
{ name = 'Kingpin', xp = 5535, policeChance = 0.60, dangerChance = 0.60, pickups = 6, maxWash = 1000000, xpReward = 200, moneyReward = 7500 },
},
}
| Column | Description |
|---|---|
xp |
Cumulative XP required to reach this rank |
policeChance |
Chance of alerting police per mission pickup |
dangerChance |
Chance of a chase vehicle spawning per pickup |
pickups |
Number of packages to collect per mission |
maxWash |
Maximum amount of dirty money per wash cycle |
xpReward |
XP earned per completed mission |
moneyReward |
Dirty money earned per completed mission |
Usage
1. Placing a Machine
Use the washing_machine item from your inventory. A placement preview will appear at your crosshair.
- Scroll Up/Down - Rotate the washer
- Shift + Scroll - Adjust height
- Arrow Keys - Nudge position (relative to camera direction)
- X - Toggle ground snap on/off
- E - Confirm placement
- Backspace - Cancel placement
2. Managing Your Washer
Target the placed machine with your target system (ox_target or qb-target) and select "Manage Washing Machine". This opens the tablet UI where you can:
- Start a wash - Select an amount of dirty money to wash (limited by your washer's rank)
- Cancel a wash - Cancel an active wash and get your dirty money refunded
- Unload clean money - Collect finished washes (minus tax)
- Lock/Unlock - Secure your machine from other players
- Add/Remove keys - Grant or revoke access to nearby players (up to 10 keys)
- Start a mission - Launch a package run to earn XP and dirty money
- View rank - See your washer's current rank, XP progress, and stats
- Pick up washer - Owner only — retrieves the washer back to inventory
3. Tax & Rank System
Each washer tracks its own XP and rank. The base tax rate is 35% and is reduced by 3.5% per rank level. Higher ranks also unlock higher wash limits and better mission rewards. Earn XP by completing package run missions.
4. Package Run Missions
Start a mission from the tablet UI to earn XP and dirty money for your washer. The flow is:
- Launch a mission from the tablet (requires minimum police online if configured)
- Travel to marked locations and collect suspicious packages from NPCs
- Higher ranks have more pickup stops, but also higher police alert and chase vehicle chances
- After all pickups, deliver the packages to a final location
- Earn dirty money and XP rewards based on your washer's rank
Missions are cancelled if you die. A HUD overlay tracks your progress during the mission.
5. Lockpicking & Break-ins
If a washer is locked and you don't have access, you can attempt to lockpick it (requires an advanced_lockpick item). A NUI minigame will appear where you must pick each pin within the time limit. On success:
- A break-in view opens showing the washer's current wash status
- If a wash is finished, you can steal the clean money
- The washer owner is notified of break-in attempts (if enabled)
6. Police Actions
On-duty police officers see an "Inspect" option when targeting a washer. From the police view, they can:
- Inspect - View washer details (owner, wash status, amounts)
- Seize money - Confiscate any money currently in the washer
- Seize washer - Confiscate the entire washer as evidence (permanently removes it)
During missions, police receive dispatch alerts and blips when players trigger police chance events at pickup locations.
Troubleshooting
UI Not Showing
- Verify
web/build/index.htmlexists in the resource folder - Restart the resource with
restart NR_MoneyWash - If using
ExternalUI = true, make sureis_uiis started
Theme Colors Not Working
- Verify the hex codes in your
themeconfig are valid (e.g.#00FFFF) - Restart the resource after changing config
Item Not Working
- Verify the item exists in your inventory system (e.g.
ox_inventory/data/items.luaorqb-core/shared/items.lua) - For ox_inventory, make sure the
server.exportpath matches your resource folder name (e.g.NR_MoneyWash.washing_machine) - Restart your inventory system after adding items
Lockpick Not Appearing
- Make sure
lockpick.enabled = truein config - The lockpick option only appears on locked washers you don't have access to
- The player must have the
advanced_lockpickitem in their inventory - On-duty police do not see the lockpick option (they see "Inspect" instead)
Missions Not Starting
- Check if
police.requiredPoliceCountis set — enough police must be online - You must have access to the washer (owner or key holder)
- The washer cannot have an active wash cycle running
- There is a 30-second cooldown between missions
Migrating from v1.x
If you're upgrading from an older version:
- Backup your current installation
- The database is compatible — the script automatically adds any new columns (e.g.
heading) on startup - Replace the resource files and restart
- Add the new items (
advanced_lockpick,suspicious_package) to your inventory if you want lockpicking and missions - Review the new config sections (lockpick, police, missions, ranks) and adjust to your server's balance
Support
For paid script support, open a ticket in our Discord server for priority assistance.