> For the complete documentation index, see [llms.txt](https://docs.tworst.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tworst.com/scripts/builder-job/configuration.md).

# Configuration

Everything is configured from the `config/` folder. The files are **open** (not escrow-locked), so you can edit them freely.

| File                            | What it holds                                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `config/config.lua`             | The main file — framework, locale, economy multipliers, prompts, commands, admins, clothing, notifications |
| `config/data/regions.lua`       | Region rewards, region definitions, XP curve, job NPC, blips, daily missions                               |
| `config/data/notifications.lua` | Notification type per message key (text itself lives in `locales/`)                                        |
| `config/economy.lua`            | Optional money/XP model derived from work volume                                                           |
| `config/keybinds.lua`           | Machine control keys (crane, pump, tower crane)                                                            |
| `config/coordinate.lua`         | Shared coordinates                                                                                         |
| `config/jobs/*.lua`             | Per-region job settings                                                                                    |
| `config/systems/*.lua`          | Feature systems (tutorial, rental, leaderboard, crane, pump...)                                            |
| `config/secrets/discord.lua`    | **Server-only** — your Discord webhook URLs and bot token                                                  |
| `config/bridges/*.lua`          | Framework bridges — nothing to configure                                                                   |
| `config/gate/*.lua`             | Internals: auto-detection and command gating — **nothing to configure**                                    |

{% hint style="info" %}
`config/gate/auto_detect.lua` and `config/blueprint_loader.lua` are marked *"nothing to configure here"* in the source. They resolve the `auto` values and load blueprints. Leave them alone.
{% endhint %}

***

## Core Settings

```lua
-- Framework: auto | qb | oldqb | qbox | esx | oldesx | vrp | vrp2 | standalone
-- 'auto' detects it from the running resources; a value set by hand always wins.
-- 'qbox' uses the 'qb' bridge (qbx_core compat layer).
Config.Framework          = 'auto'

-- Inventory: auto | qb_inventory | esx_inventory | ox_inventory
--            | codem-inventory | qs_inventory | tgiann-inventory
Config.Inventory          = "auto"

-- Path for craft/reward item icons. 'auto' = derived from the selected inventory.
Config.InventoryImagePath = "auto"

Config.SQL                = "oxmysql"

-- Server default only — players pick their own language in the menu.
Config.Locale             = 'en'

Config.MoneyType          = "$"       -- cash account
Config.MoneyType2         = "bank"    -- bank account

Config.ServerName         = "TWORST"
Config.ExampleProfilePicture = "https://.../LogoNEW.png"
```

{% hint style="success" %}
**Auto-detection:** leave `Framework`, `Inventory` and `InventoryImagePath` on `auto` and the script reads whatever is actually running on your server. A value you type by hand always wins. `qbox` uses the same bridge as `qb`.
{% endhint %}

The detection order is fixed in `config/gate/auto_detect.lua`: `qbx_core` → `qb-core` → `es_extended` → `vrp` → standalone for frameworks, and third-party inventories (`ox_inventory`, `qs-inventory`, `codem-inventory`, `tgiann-inventory`) before `qb-inventory`, because qb-inventory is often installed next to the one actually in use. Each detection prints what it picked to the console.

***

## Economy Multipliers

Two global dials, both at the top of `config.lua`:

```lua
-- Scales money + XP + bonuses of EVERY region.
Config.RewardMultiplier   = 1.0

-- Scales every rental deposit. 0 = no deposits at all.
Config.DepositMultiplier  = 1.0
```

| Setting                    | Effect                                                                                                                        |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `Config.RewardMultiplier`  | Multiplies `money`, `xp`, `bonusExtraMoney` and `bonusExtraXP` for every region at load time. `1.5` = 50% richer server-wide. |
| `Config.DepositMultiplier` | Multiplies every rental deposit in `config/systems/vehicle_rental.lua`. Set `0` to switch deposits off entirely.              |

{% hint style="success" %}
**This is the easiest way to balance the job for your server.** You do not need to touch a single per-region number — change one multiplier and every region scales with it.
{% endhint %}

***

## Interaction Prompt

{% hint style="success" %}
**One setting decides everything about the \[E] prompt.** Earlier versions used two keys; they are now derived automatically and must not be set by hand.
{% endhint %}

```lua
-- config/config.lua
Config.InteractionStyle = 'badge'
```

| Value         | What players see                                                                      |
| ------------- | ------------------------------------------------------------------------------------- |
| `'badge'`     | Our world-space badge with an icon — **default**                                      |
| `'text'`      | Plain 3D text, no badge                                                               |
| `'oxlib'`     | `ox_lib` TextUI in the screen corner — matches the rest of your server                |
| `'ox-target'` | Hands interaction over to **ox\_target**                                              |
| `'qb-target'` | Hands interaction over to **qb-target**                                               |
| `'auto'`      | Uses ox\_target / qb-target if either is installed, otherwise falls back to `'badge'` |

{% hint style="info" %}
For the three built-in styles (`badge`, `text`, `oxlib`) focus, distance and the **E** key behave **identically** — the only thing that changes is where the prompt is drawn. Pick on looks alone.
{% endhint %}

{% hint style="warning" %}
`Config.InteractionHandler` and `Config.Interaction.style` are **derived** from `Config.InteractionStyle` inside `config/systems/interaction.lua`. Do not set them by hand — your value will be overwritten.
{% endhint %}

### Tuning

The rest of `config/systems/interaction.lua` is fine-tuning — geometry, fonts and cadence — and rarely needs touching:

```lua
Config.Interaction.assets = {
    badge = 'html/assets/tw_badge_blank.png',
    pill  = 'html/assets/tw_pill.png',
    dot   = 'html/assets/tw_dot.png',
}

Config.Interaction.defaultKey    = 'genel.interact'  -- keybind used for the prompt
Config.Interaction.scanMs        = 100               -- how often nearby targets are scanned
Config.Interaction.cellSize      = 8.0               -- spatial grid cell size
Config.Interaction.screenBias    = 0.7               -- how much aiming at a target matters
Config.Interaction.distanceNorm  = 10.0              -- distance normalisation for focus scoring
Config.Interaction.eCooldownMs   = 400               -- debounce between two E presses
Config.Interaction.disabledAware = true              -- respect disabled-control states
```

`Config.Interaction.badge`, `.pin`, `.label`, `.anim`, `.scale` and `.machine` control the size, offset and animation of the badge itself.

{% hint style="info" %}
`label.asciiFold = 'tr'` folds the Turkish letters GTA's in-game font cannot render (ı İ ğ Ğ ş Ş) down to ASCII. The NUI is a browser and is unaffected.
{% endhint %}

***

## Release Profile

{% hint style="danger" %}
**Set this before you go live.** While debug mode is on, \~250 debug commands register, roughly 20 server-side validation bypasses stay live, and regions play at trimmed test size.
{% endhint %}

```lua
Config.ReleaseBuild = true
```

When `true`, these are force-disabled no matter what they say elsewhere: `Debug`, `DebugCommands`, `DebugZoneDraw`, `DebugZones`, `DebugTowerScenery`, `RopeProbe`, `Profiler`, `FastTest`, `SoloTest` — and the per-region test trims are zeroed, so every region plays at full size.

| Setting                | What it does                                                                                    |
| ---------------------- | ----------------------------------------------------------------------------------------------- |
| `Config.Debug`         | Diagnostic logs + per-frame measurement loops (animcontrols, rental). `false` on a live server. |
| `Config.DebugCommands` | Registers the debug command set. **Release blocker.**                                           |
| `Config.DebugZoneDraw` | Draws zone polygons — \~75 µs/frame. Only to check a boundary.                                  |
| `Config.SoloTest`      | Relaxes crew/vehicle caps so one person can test.                                               |
| `Config.FastTest`      | Auto-spawns vehicles and skips the whole rental flow. Dev only.                                 |
| `Config.Profiler`      | Event/network profiler, writes `profiler_logs/*.json`.                                          |

{% hint style="warning" %}
The individual flags ship as `Config.Debug = true` and `Config.DebugCommands = true`. That is fine — `Config.ReleaseBuild = true` sits below them and forces them off. **Read the value of `ReleaseBuild`, not the flags above it.**
{% endhint %}

***

## Lobby & Crew

```lua
Config.LetOwnerSplitRewards  = true   -- owner assigns each member's share
Config.JobCooldownEnabled    = false
Config.jobCoolDownHours      = 0
Config.MaxHistoryEntries     = 50

-- Menu/interaction keys. Machine keys are separate: config/keybinds.lua
Config.Keys = {
    inviteAccept  = 246,
    inviteDecline = 306,
}
```

{% hint style="warning" %}
**Lobby size is fixed at 4 and is deliberately not a config option.** `Config.MaxPlayersInLobby` lives in `config/gate/auto_detect.lua` because crew size feeds reward splitting, slot quotas and the coop sync budget, and all three were balanced around 4.

A region may allow **fewer** through its own `maxPlayers` in `config/jobs/*.lua` — the smaller of the two always wins.
{% endhint %}

### Commands

```lua
Config.Command = {
    jobReset = "builderjobreset",       -- reset your own job
    jobLeave = "builderjobleave",       -- leave the crew
    settings = "builderjobsettings",    -- visual detail / sync quality panel
    keys     = "keys",                  -- key binding panel
}
```

Rename these freely. Debug commands never go through this table.

### Reward Split by Rank

```lua
Config.ScoreRankBonus = {
    enabled = true,
    table = {
        [1] = { 0 },
        [2] = { 8, 0 },
        [3] = { 10, 5, 0 },
        [4] = { 12, 8, 5, 0 },
    },
    applyToXP = true,
}
```

Extra percentage for the highest-scoring crew members, by crew size. Applied to money and XP **after** the job split and damage deductions.

### Reconnection

```lua
Config.Reconnection = {
    enabled                   = true,
    gracePeriodSeconds        = 0,
    maxReconnectAttempts      = 3,
    resetAttemptsAfterSeconds = 300,
    autoCleanupExpired        = true,
    ownerTransfer = {
        enabled             = true,
        allowRejoinAsMember = true,
        prioritizeByScore   = true,
    },
}
```

A disconnected player gets their lobby seat, task progress and reward share back within the window. If the **owner** drops, ownership transfers to another member.

***

## Regions & Rewards

{% hint style="info" %}
Regions moved out of `config.lua` — they now live in **`config/data/regions.lua`**.
{% endhint %}

### Rewards — the single source

All money and XP live in one table, keyed by `regionID`:

```lua
Config.RegionAwards = {
    [1] = { money = 5000, xp = 1000, onlineJobExtraAwards = 1, bonusExtraMoney = 500, bonusExtraXP = 200 },
    [2] = { money = 6500, xp = 1500, onlineJobExtraAwards = 1, bonusExtraMoney = 1000, bonusExtraXP = 300 },
    -- ... through [12]
}
```

| Key                                | Meaning                                |
| ---------------------------------- | -------------------------------------- |
| `money`                            | Paid to the crew that finishes the job |
| `xp`                               | Experience earned                      |
| `onlineJobExtraAwards`             | `1` = apply the bonuses below          |
| `bonusExtraMoney` / `bonusExtraXP` | Added per crew member                  |

`Config.RewardMultiplier` is applied to this whole table as it loads, and `config/economy.lua` can overwrite it entirely when enabled.

### Region Definitions

```lua
Config.Job.regionData = {
    {
        regionID   = 1,
        regionInfo = {
            regionName         = TL('regionName_plank', 'El Burro Heights'),
            regionNameKey      = 'regionName_plank',
            regionJobTask      = TL('regionJobTaskPlank', '...'),
            regionImage        = "region.png",
            regionMinimumLevel = 0,
            jobType            = 'plank',
        },
        regionAwards = Config.RegionAwards[1],
        missioncompletedItems = {
            giveItemPlayer = false,
            dropMode       = "weightedPool",
            itemList = {
                { item = "sandwich", count = 1, chance = 50 },
                { item = "water",    count = 1, chance = 30 },
            },
        },
    },
}
```

{% hint style="warning" %}
Setting `enabled = false` on a region removes the record from `regionData` **entirely** — it is not just hidden in the selector, so a modified client cannot send the `regionID` either.
{% endhint %}

{% hint style="info" %}
`TL()` resolves a locale key at load time with a fallback. Set **both** `regionName` and `regionNameKey` when you add a region: the resolved name freezes to the server's language, while the key is what each player's client resolves in **their** language.
{% endhint %}

***

## Levels

```lua
Config.RequiredXP = {
    [1] = 1000,
    [2] = 1500,
    -- ... up to level 70
}
Config.jobLevelCheck = false   -- gate regions by level
```

70 levels are defined in `config/data/regions.lua`. Each region can require a minimum level via `regionMinimumLevel`.

***

## Job NPC & Blips

In `config/data/regions.lua`:

```lua
Config.Job = {
    pedInteractionDistance = 3.0,
    coords = {
        intreactionCoords = vector3(1535.54, 1736.45, 110.31),
        ped               = true,
        pedCoords         = vector3(1535.54, 1736.45, 110.31),
        pedHeading        = 85.68,
        pedHash           = 0xC5FEFADE,
    },
    job  = 'all',
    blip = {
        show = true, blipName = TL('jobName'),
        blipType = 317, blipColor = 17, blipScale = 0.70,
    },
    missionBlips = {
        -- one entry per task marker, plus a vehicleBlips entry for rentals
    },
}
```

Set `job` to a framework job name to restrict the script to that job, or leave `'all'`. `missionBlips` styles the in-job task markers, and `missionBlips.vehicleBlips` styles the rental vehicle marker.

***

## Languages

**12 languages ship with the script:**

|                  |               |                |                   |
| ---------------- | ------------- | -------------- | ----------------- |
| English (`en`)   | Türkçe (`tr`) | Deutsch (`de`) | Español (`es`)    |
| Français (`fr`)  | Magyar (`hu`) | 日本語 (`ja`)     | Nederlands (`nl`) |
| Português (`pt`) | Română (`ro`) | Русский (`ru`) | Svenska (`sv`)    |

`Config.Locale` sets the **server default** only — every player picks their own from the menu.

### Adding your own language

{% hint style="success" %}
**The menu is built from the `locales/` folder.** Drop a new `<code>.lua` in there and it appears in the language menu by itself — no code change needed.
{% endhint %}

1. Copy `locales/en.lua` to `locales/<code>.lua`
2. Translate the values (leave the keys alone)
3. Optionally add a display name so the menu shows it properly:

```lua
Config.LanguageNames = {
    en = 'English',
    tr = 'Türkçe',
    -- ...
    xx = 'Your Language',
}
```

A code with no entry in `Config.LanguageNames` is simply shown uppercased.

***

## Notifications

### Text and type

The wording lives in `locales/*.lua`. `config/data/notifications.lua` only maps each key to a **type**:

```lua
Config.NotificationText = {
    ['wrongjob']      = { text = TL('wrongjob'),      type = "error" },
    ['jobcooldown']   = { text = TL('jobcooldown'),   type = "error" },
    ['playerfaraway'] = { text = TL('playerfaraway'), type = "info"  },
}
```

{% hint style="info" %}
**Edit wording in the locale files, not here.** This file is only for changing whether a message shows as info, success or error.
{% endhint %}

### Burst filter

One player action often fires several notifications at once. Two rules keep the screen readable:

```lua
Config.NotifyBurst = {
    enabled      = true,
    repeatMs     = 6000, -- the same text is not shown again within this window
    infoWindowMs = 2500, -- window for the 'info' cap below
    infoMax      = 1,    -- max 'info' notifications per window
}
```

`error` and `success` always pass. Keyed notifications (progress counters, which update in place) skip the filter entirely. Set `enabled = false` to turn the whole thing off.

`Config.NotifyFilter` is the function implementing this — replace it if you want different rules.

### Sending through your own notification script

```lua
Config.sendNotification = function(messageData) end
```

Point this at your own notify export to route every message through your server's notification system.

***

## Changing Room

New in the HQ: players change into work clothes inside a marked room rather than instantly on job start.

```lua
Config.ChangingRoom = {
    enabled  = true,
    required = true,          -- must change before starting

    points   = {              -- polygon corners of the room
        vector3(1559.97, 1735.78, 110.96),
        vector3(1565.75, 1735.77, 110.85),
        vector3(1565.78, 1726.16, 110.95),
        vector3(1559.84, 1725.78, 110.95),
    },
    zMin     = 109.0,
    zMax     = 114.0,
    anchor   = vector3(1562.84, 1730.87, 110.93),

    blip     = { enabled = true, sprite = 366, color = 5, scale = 0.7 },

    anim     = {
        enabled  = true,
        dict     = 'clothingtie',
        clip     = 'try_tie_negative_a',
        duration = 2200,
        fadeOut  = 400, hold = 250, fadeIn = 400,
    },
}
```

| Key                        | Meaning                                                                   |
| -------------------------- | ------------------------------------------------------------------------- |
| `required`                 | `true` = the player must change before the job starts; `false` = optional |
| `points` / `zMin` / `zMax` | The room polygon and its height range                                     |
| `anchor`                   | Where the player is placed for the change animation                       |
| `blip`                     | Map marker for the room                                                   |
| `anim`                     | The changing animation and its fade timings                               |

{% hint style="info" %}
The room is part of the **`tw-builder-map`** HQ interior. If you move the HQ, move these coordinates with it.
{% endhint %}

***

## Clothing

```lua
Config.ChangeClothesSystem = true   -- dress the player in work clothes on start
Config.JobClothes = { male = {...}, female = {...} }
Config.RefreshSkin = function() end
```

The outfit comes from `Config.JobClothes` and is applied through `skinchanger` / `esx_skin` events plus `Config.RefreshSkin`. If your clothing script differs, edit `Config.RefreshSkin` to match your own call.

***

## Discord Logging

{% hint style="danger" %}
**Do not put the webhook URL in `config/config.lua`.** That file is a **shared** script and ships to every client — a URL there is a published secret. The URLs belong in **`config/secrets/discord.lua`** (server-only).
{% endhint %}

```lua
Config.Discord = {
    enabled    = true,
    botName    = "Tworst Store",
    footerText = "Tworst Builders",
    panelLog   = true,
    panelKeep  = 300,
    events = {
        jobStart = true,  jobFinish = true,  jobAbandon = true,
        lobbyCreate = false, lobbyJoin = true, lobbyLeave = true,
        lobbyDisband = true, reconnect = true, adminForceEnd = true,
        rewardPaid = false, rewardFailure = true,
        security = true, serverStart = true,
    },
    showIdentifiers = false,
    mentionRole     = "",
    minGapMs = 450, maxQueue = 300, maxRetries = 3,
}
```

`minGapMs`, `maxQueue` and `maxRetries` are the rate limiter — they keep a busy server from flooding Discord.

### Webhook URLs — `config/secrets/discord.lua`

The URLs live in a **server-only** file, one channel per category:

```lua
TwSecrets.Discord = {
    botToken = "",             -- only used to fetch avatars for embed thumbnails
    webhooks = {
        default   = "",        -- fallback for any empty category below
        jobstart  = "",        -- a crew started a region
        jobfinish = "",        -- region completed, who got paid what
        lobby     = "",        -- create / join / leave / kick / disband / reconnect
        economy   = "",        -- per-player payout lines (off by default)
        admin     = "",        -- /builderadmin actions
        security  = "",        -- rejected RPC, capacity bypass, non-owner calls
        error     = "",        -- partial payouts and other failures
    },
}
```

An empty category falls back to `default`. If `default` is empty too, that category is simply off — and leaving everything empty is a perfectly valid setup: no URL means no request is ever made, and `/builderadmin` → **Logs** reads the same event stream from server memory either way.

You can also set these as convars in `server.cfg` instead — see [Installation → Step 8](/scripts/builder-job/installation.md). Use `set`, never `setr`.

***

## Admins

```lua
Config.Admins = {
    'discord:000000000000000000',
}

Config.AdminPanel = {
    enabled      = true,
    command      = 'builderadmin',
    cacheSeconds = 60,
    topLimit     = 25,
    stuckMinutes = 90,
    scanLimit    = 500,
}
```

`Config.Admins` gates both `/builderadmin` and the `/tw_bp` site builder — checked at the door **and** again on every write event. Run `/cranesiteid` in-game to print your own identifier.

See [Interface](/scripts/builder-job/interface.md) for what the panel and the site builder actually do.

{% hint style="warning" %}
The script ships with the developer's own Discord IDs in `Config.Admins`. **Replace them with yours** before going live.
{% endhint %}

***

## Vehicle Keys & Fuel

```lua
Config.Vehiclekey       = true
Config.GiveVehicleKey   = function(plate, model, vehicle) end
Config.Removekeys       = true
Config.RemoveVehiclekey = function(plate, model, vehicle) end
Config.SetVehicleFuel   = function(vehicle) end
```

Key and fuel systems are auto-detected. Edit these functions if you run something unusual.

***

## Job Hooks

```lua
Config.startJobFunction = function(source, owneridentifier)
    return true   -- return false to block the job from starting
end

Config.endJobFunction   = function(source, owneridentifier, scoreAmount)
end
```

Use these to plug the job into your own systems — a licence check before starting, a stat update on finish, and so on. Returning `false` from `startJobFunction` blocks the start.

***

## World & Performance

```lua
Config.ZoneExitGraceMs = 10000     -- delay before local props are removed on leaving a site

Config.Ambient = {
    suppress    = true,            -- suppress traffic/peds inside a region
    purge       = true,
    purgeRepeat = true,
    radius      = 400.0,
}
```

{% hint style="info" %}
`ZoneExitGraceMs` matters more than it looks: too short and a player walking the site boundary keeps tearing the scene down and rebuilding it.
{% endhint %}

Performance tuning lives in `config/systems/perf_lod.lua` and `config/systems/perf_budget.lua`.

***

## Feature Systems

Everything under `config/systems/`:

| File                                                                    | Feature                                                                                             |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `interaction.lua`                                                       | Prompt geometry, fonts and scan cadence (style is set in `config.lua`)                              |
| `tutorial.lua`                                                          | Training field, modules, per-job-type suggestions                                                   |
| `vehicle_rental.lua`                                                    | Rental lot, stock, deposit, damage penalty                                                          |
| `leaderboard.lua`                                                       | Top earners / most jobs, row limit                                                                  |
| `tower_crane.lua`                                                       | Tower crane, cabin, ropes, scenery                                                                  |
| `vehicle_crane.lua`                                                     | Mobile crane                                                                                        |
| `pump.lua`                                                              | Concrete pump                                                                                       |
| `excavator.lua`                                                         | Excavator                                                                                           |
| `rigger.lua` / `sling_profiles.lua`                                     | Rigging and sling behaviour                                                                         |
| `plank_stages.lua`, `panelwall.lua`, `job7.lua`, `job8.lua`, `job9.lua` | Per-job mechanics                                                                                   |
| `sound.lua` / `dui.lua`                                                 | Site audio and prop screens                                                                         |
| `perf_lod.lua` / `perf_budget.lua`                                      | LOD levels and frame budget — these back the in-game [Sync menu](/scripts/builder-job/interface.md) |

### Tutorial

```lua
Config.TutorialEnabled = true
Config.TutorialPolicy  = 'suggest'
Config.TutorialByJobType = {
    plank         = { 'cranev2', 'pumpv2' },
    kulestone     = { 'tower' },
    pipe          = { 'cranev2' },
    waterfacility = { 'pumpv2', 'cranev2' },
}
```

Players practise the machines a region needs on a dedicated field before they work it.

### Vehicle Rental

```lua
Config.VehicleRental = {
    enabled        = true,
    depositEnabled = true,
    depositAccount = Config.MoneyType2,
    damagePenalty  = {
        enabled = true, multiplier = 1.0, graceHealthPct = 95,
        useEngine = true, useBody = true,
    },
    requireReturnToFinish = true,
    fullFuelOnRent        = true,
    uniquePlates          = true,
}
```

Each vehicle type has its own parking spot, stock and deposit in `Config.RentalVehicles`. Every deposit is then scaled by `Config.DepositMultiplier`.

### Leaderboard

```lua
Config.Leaderboard = { enabled = true, limit = 10 }
```

When disabled, the tab is hidden from the menu entirely.

### Static Machines

```lua
Config.StaticMachinesByJobType = {
    kulestone = { TL('machine_tower_crane', 'Tower Crane') },
}
```

Scenery machines that stand on a site but are never driven. They are listed in the region's UI info so players know what is waiting for them.

***

## Economy Model (Optional)

`config/economy.lua` can derive money and XP from the **work volume** of each region instead of hand-written constants:

```
effort-seconds = sum(unit count x unit duration x difficulty multiplier)
money          = effort-minutes x moneyPerMinute    -- default 300, rounded to 50
XP             = effort-minutes x xpPerMinute       -- default 45,  rounded to 25
```

A long job earns more; a hard job (crane/machine work) earns more per second.

{% hint style="warning" %}
**Off by default (`enabled = false`).** Until you enable it, `Config.RegionAwards` stays in charge and nothing changes. The built-in durations are estimates — tune them for your server before switching over.
{% endhint %}

***

## UI Positions

```lua
Config.DefaultUIPositions = {
    teamList        = { top = '77.22vh', left = '85.94vw' },
    scoreList       = { top = '2.64vh',  left = '1.61vw' },
    inviteSide      = { top = '2.85vh',  left = '73.07vw' },
    notificationDiv = { top = '40.48vh', left = '81.54vw' },
    keyInfoSide     = { top = '50%',     right = '2.0833vw' },
    dumpsterInfo    = { top = '1.3542vw', left = '50%' },
}
```

These are only defaults — players move the HUD themselves from **Settings → UI Move**, and their layout is saved per player.
