# Configuration

Three files in `config/` cover everything you can tune:

* **`config.lua`** — gameplay numbers, items, channels, leveling, anti-exploit limits
* **`locations.lua`** — every map coordinate (bosses, pickups, truck spawns, crate spots, guards)
* **`locales.lua`** — every UI string in 4 languages

These three are the only Lua files you can edit. `client/`, `server/`, `shared/`, and `bridge/` are escrowed.

## Global config keys (`TL.Config`)

| Key                   | Default            | Purpose                                                                        |
| --------------------- | ------------------ | ------------------------------------------------------------------------------ |
| `locale`              | `'en'`             | UI / notification language. `en` `es` `fr` `ar`.                               |
| `dirtyMoneyItem`      | `'cash'`           | Item consumed when a job starts.                                               |
| `tabletItem`          | `'launder_tablet'` | Item that opens the tablet on use.                                             |
| `cleanCashItem`       | `'cash'`           | Payout item when the standalone fallback is active.                            |
| `requireTabletItem`   | `false`            | If `true`, `/launder` also requires the tablet item in inventory.              |
| `openCommand`         | `'launder'`        | Chat command that opens the tablet.                                            |
| `maxActiveJobs`       | `3`                | Per-player concurrent washes.                                                  |
| `minAmountPerJob`     | `500`              | Minimum dirty $ per single drop.                                               |
| `maxAmountPerJob`     | `250000`           | Hard ceiling per single drop.                                                  |
| `handoffCooldownMs`   | `4000`             | Spam guard on collect (ms).                                                    |
| `jobCreateCooldownMs` | `2500`             | Spam guard on drop (ms).                                                       |
| `maxInteractDistance` | `3.0`              | Server-side distance check for every interaction (meters).                     |
| `abandonedJobExpiryS` | `259200` (3 days)  | Auto-expires jobs older than this.                                             |
| `autoInstallSchema`   | `true`             | Run `sql/install.sql` + migrations automatically.                              |
| `showBlips`           | `false`            | Always-on map blips on handler peds. Off so they're discovered via the tablet. |
| `blipSprite`          | `500`              | Sprite id used when `showBlips = true`.                                        |
| `blipColor`           | `2`                | Blip color when `showBlips = true`.                                            |
| `notifySystem`        | `'ox_lib'`         | `'ox_lib'` `'esx'` `'qb'` `'native'`.                                          |
| `debug`               | `false`            | Verbose logging in client + server consoles.                                   |

## Leveling

XP is granted per completed job. The formula is a single Lua function:

```lua
levelCurve = function(level) return level * level * 100 end,
```

So level 2 needs 400 XP total, level 5 needs 2 500, level 10 needs 10 000, level 20 needs 40 000. Replace the function to flatten or steepen the curve.

Per-channel XP is awarded by:

* `xpPerJob` — flat XP awarded on completion
* `xpPerThousand` — extra XP per $1 000 of **clean** payout (so theft reduces XP, big amounts amplify it)

Defaults:

| Channel      | xpPerJob | xpPerThousand |
| ------------ | -------- | ------------- |
| Civilians    | 50       | 1             |
| Gas Stations | 200      | 2             |
| Shipments    | 500      | 3             |

## Per-channel config

Each entry in `TL.Config.Channels` looks like this (Civilians shown):

```lua
{
    id              = TL.Const.ChannelKind.CIVILIAN,
    kind            = TL.Const.ChannelKind.CIVILIAN,
    label           = 'Civilians',
    description     = 'Slow but reliable. Low fee, low heat.',
    washRate        = 0.85,
    fee             = 0,
    minTimeS        = 600,
    maxTimeS        = 900,
    capacityPerSlot = 50000,
    cooldownS       = 300,
    theftChance     = 0.20,
    theftMin        = 0.05,
    theftMax        = 0.15,

    -- Leveling
    levelRequired   = 1,
    xpPerJob        = 50,
    xpPerThousand   = 1,

    bosses = {
        { id = 'civ_marco_vinewood', label = 'Marco — Vinewood',       model = 'a_m_m_business_01' },
        { id = 'civ_yuki_vespucci',  label = 'Yuki — Vespucci Canals', model = 'a_f_y_business_02' },
    },
},
```

| Key                          | Purpose                                                                                                                               |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `id`, `kind`                 | Stable keys used in the DB and the netcode. Don't change ids after launch — existing jobs will orphan.                                |
| `label`, `description`       | Tablet UI copy.                                                                                                                       |
| `washRate`                   | Fraction of dirty $ paid out (0–1).                                                                                                   |
| `fee`                        | Flat $ subtracted from `amount_dirty` before the wash.                                                                                |
| `minTimeS` / `maxTimeS`      | Wash duration window — the server picks a random value in range.                                                                      |
| `capacityPerSlot`            | Hard cap per single drop.                                                                                                             |
| `cooldownS`                  | Per-player lockout after a full pickup completes.                                                                                     |
| `theftChance`                | Probability of a theft roll per pickup (0–1).                                                                                         |
| `theftMin` / `theftMax`      | Fraction of that pickup's payout stolen on a bad roll.                                                                                |
| `levelRequired`              | Minimum player level to unlock the channel.                                                                                           |
| `xpPerJob` / `xpPerThousand` | XP grants on completion.                                                                                                              |
| `workflow`                   | `nil` = simple handoff (Civilians). `'truck_delivery'` = drop + drive (Gas Stations). `'shipment_run'` = crates + guards (Shipments). |

### Truck-delivery options (Gas Stations)

```lua
truck = {
    model             = 'mule3',
    deliveryRadius    = 8.0,     -- meters from delivery coords = "dropped off"
    falseCheckPenalty = 0.01,    -- fraction of clean amount lost on fake-finish
},
```

`vehicleType` defaults to `'automobile'`. Override to `'boat'` / `'heli'` / `'plane'` / `'bike'` / `'trailer'` if you swap the model.

### Shipment-run options (Shipments)

```lua
truck = {
    model             = 'mule',
    deliveryRadius    = 8.0,
    falseCheckPenalty = 0.03,
},
crate = {
    prop          = 'hei_prop_heist_box',
    carryAnimDict = 'anim@heists@box_carry@',
    carryAnim     = 'idle',
},
guards = {
    model    = 's_m_y_blackops_01',
    weapon   = 'WEAPON_PISTOL',
    accuracy = 35,
    armor    = 100,
    health   = 200,
},
```

### Bosses

Each channel has one or more bosses (handlers). The shipped defaults:

| Channel      | Boss id              | Label                   | Model               |
| ------------ | -------------------- | ----------------------- | ------------------- |
| Civilians    | `civ_marco_vinewood` | Marco — Vinewood        | `a_m_m_business_01` |
| Civilians    | `civ_yuki_vespucci`  | Yuki — Vespucci Canals  | `a_f_y_business_02` |
| Shipments    | `ship_dockmaster`    | Dockmaster — Port of LS | `s_m_m_dockwork_01` |
| Gas Stations | `gas_operator`       | Wholesale Gas Operator  | `a_m_m_farmer_01`   |

The `id` is the database key — never change it once a player has interacted with that boss. The label and model are cosmetic and safe to edit.

## Locations (`config/locations.lua`)

All coordinates live in `locations.lua`, keyed by `boss_id`. Edit only what you need:

| Field           | Used for                       | Notes                                                                           |
| --------------- | ------------------------------ | ------------------------------------------------------------------------------- |
| `coords`        | Boss spawn / meet spot         | `vector4(x, y, z, heading)`                                                     |
| `pickupCoords`  | Clean-cash pickup locations    | Array of `vector4`. Civilians/Gas use 3 pickups by default; Shipments has more. |
| `truckSpawn`    | Where the truck appears        | Truck workflows only.                                                           |
| `truckDelivery` | Where the truck is dropped off | Truck workflows only.                                                           |
| `crates`        | Crate prop spots               | `shipment_run` only. Array of `vector3`.                                        |
| `guards`        | Guard spawn points             | `shipment_run` only. Array of `{ coords = vector4 }`.                           |

## Locales (`config/locales.lua`)

4 languages ship with the script. Set `TL.Config.locale` to one of:

* `en` — English
* `es` — Español
* `fr` — Français
* `ar` — العربية

Missing keys fall back to English automatically. To add a language, copy any locale table, translate the values, and add the new key.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://6ly-scripts.gitbook.io/product-docs/scripts/money-launder/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
