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

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);
Note

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
⚠️ Important

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.

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:

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:

  1. Launch a mission from the tablet (requires minimum police online if configured)
  2. Travel to marked locations and collect suspicious packages from NPCs
  3. Higher ranks have more pickup stops, but also higher police alert and chase vehicle chances
  4. After all pickups, deliver the packages to a final location
  5. 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:

6. Police Actions

On-duty police officers see an "Inspect" option when targeting a washer. From the police view, they can:

During missions, police receive dispatch alerts and blips when players trigger police chance events at pickup locations.

Troubleshooting

UI Not Showing

Theme Colors Not Working

Item Not Working

Lockpick Not Appearing

Missions Not Starting

Migrating from v1.x

If you're upgrading from an older version:

Support

For paid script support, open a ticket in our Discord server for priority assistance.