NR_Towing

A multi-framework towing job system (ESX, QBCore, QBX) with auto-detection, flatbed mechanics, roadside repair missions, leveling, dispatch queue, in-app store, and a custom React UI.

Features

Dependencies

Resource Description Required
es_extended / qb-core / qbx_core Core framework (auto-detected) One of these
ox_lib UI library (callbacks, notifications) Yes
oxmysql MySQL database (leveling, player data) Yes
Inventory system ox_inventory, qb-inventory, ps-inventory, lj-inventory, codem-inventory, core_inventory, origen_inventory, and more (auto-detected) One of these
ox_target / qb-target Target interaction for HQ ped Optional
NR_Tablet Opens towing UI via tablet app Optional

Installation

Step 1: Download

Download NR_Towing from your Tebex purchase and extract it to your resources folder:

server/
  └── resources/
      └── [echo]/
          └── NR_Towing/

Step 2: 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:

['tow_tire'] = {
    label = 'Tire',
    weight = 500,
    stack = true,
},

['tow_sparkplug'] = {
    label = 'Spark Plug Kit',
    weight = 200,
    stack = true,
},

['tow_battery'] = {
    label = 'Replacement Battery',
    weight = 800,
    stack = true,
},

qb-core — Add to qb-core/shared/items.lua:

tow_tire = { name = 'tow_tire', label = 'Tire', weight = 500, type = 'item', image = 'tow_tire.png', unique = false, useable = false, shouldClose = false, description = 'A replacement tire for roadside repairs' },
tow_sparkplug = { name = 'tow_sparkplug', label = 'Spark Plug Kit', weight = 200, type = 'item', image = 'tow_sparkplug.png', unique = false, useable = false, shouldClose = false, description = 'A spark plug kit for engine repairs' },
tow_battery = { name = 'tow_battery', label = 'Replacement Battery', weight = 800, type = 'item', image = 'tow_battery.png', unique = false, useable = false, shouldClose = false, description = 'A replacement battery for dead vehicles' },
💡 Item Images

Don't forget to add corresponding images (tow_tire.png, tow_sparkplug.png, tow_battery.png) to your inventory's image directory.

Step 3: server.cfg

Add the resource to your server configuration. ox_lib and oxmysql must start before NR_Towing:

ensure ox_lib
ensure oxmysql
ensure ox_inventory
ensure NR_Towing

Step 4: Configure

Edit config.lua to customize the towing job (see Configuration section below).

Step 5: Restart

Restart your server to load the resource. The database table for player levels will be created automatically.

⚠️ Important

If using NR_Tablet integration (Config.UsingNRTablet = true), make sure NR_Tablet is started before NR_Towing. If not using NR_Tablet, the UI opens with F4 by default.

How It Works

1. Clocking In

Head to the Towing HQ (marked on the map with a blip). Interact with the HQ ped to open the towing app. From the duty screen, clock in to start your shift. A flatbed truck spawns at the designated spawn point.

2. Joining the Dispatch Queue

Once on duty, hit the dispatch button from the dashboard. You'll enter the dispatch queue and receive a tow call after the configured delay (default: 120 seconds).

3. Tow Jobs (Level 6+)

After reaching level 6, you receive full tow calls. Drive your flatbed to the breakdown location, load the vehicle, then deliver it to the impound lot:

4. Repair Jobs (Level 1-5)

New players start with roadside repair calls using a speedo van instead of a flatbed. Repair jobs include:

Repair Type Required Item Description
Flat Tire tow_tire x1 Replace a single burst tire with a timed minigame
2 Flat Tires tow_tire x2 Replace two burst tires with timed minigames
Bad Spark Plugs tow_sparkplug x1 Open the hood and install new spark plugs
Dead Battery tow_battery x1 Open the hood and replace the dead battery

Each repair has a timed minigame (default: 10 seconds). Failing the minigame breaks the part and you must try again.

5. Leveling Up

Earn XP for each completed job. The XP formula scales with your level:

XP needed = currentLevel x XPPerLevel
-- Example: Level 1 = 100 XP, Level 5 = 500 XP, Level 10 = 1000 XP

The max level is 25 by default. View your rank and the leaderboard from the Rank tab in the app.

6. In-App Store

Purchase repair items from the store tab. Items have level requirements and are paid with cash or bank funds:

Item Price Min Level
Tire $50 1
Spark Plug Kit $75 1
Replacement Battery $100 1

Configuration

General Settings

Config.Debug = false              -- Enable debug logging
Config.Theme = '#C4B702'          -- UI accent color (hex)
Config.Keybind = 'F4'            -- Key to open UI (when not using NR_Tablet)
Config.UsingNRTablet = true       -- Open via NR_Tablet export
Config.UsingTarget = false        -- Use ox_target for HQ ped interaction
Config.UsingExternalUI = false    -- Use external UI (is_ui / ox_lib fallback)

HQ & Flatbed

Config.HQPed = {
    model = 's_m_y_xmech_02',
    coords = vec4(408.9579, -1623.0558, 29.2919, 229.1624),
    scenario = 'WORLD_HUMAN_CLIPBOARD'
}

Config.HQBlip = {
    coords = vec3(408.9579, -1623.0558, 29.2919),
    sprite = 68,
    color = 5,
    scale = 0.8,
    label = 'Towing HQ'
}

Config.ClockInDistance = 3.0                                        -- Proximity to go on duty
Config.FlatbedSpawn = vec4(401.7856, -1632.3269, 29.2919, 136.5435)
Config.FlatbedModel = 'flatbed3'

Tow Truck Settings

Config.Trucks = {
    [`flatbed3`] = {
        attachVehBone = 'misc_a',        -- Bone for vehicle attachment
        attachOffset = vector4(0.0, 1.0, 0.7, 0.0),  -- Attachment offset
        maxBedMovement = 0.18,           -- Maximum bed tilt range
        bedSpeed = 0.0005,               -- Bed tilt speed
    },
}

Config.KeepPressedToMoveBed = false  -- Hold vs toggle bed movement

Rewards & Leveling

Config.RewardMin = 500     -- Minimum payout per tow job
Config.RewardMax = 1500    -- Maximum payout per tow job
Config.XPPerJob = 50       -- XP earned per completed job

Config.MaxLevel = 25       -- Highest achievable level
Config.XPPerLevel = 100    -- XP multiplier per level

Dispatch

Config.DispatchDelay = 120   -- Seconds before receiving a dispatch call
Config.DropoffLocation = vec4(401.7856, -1632.3269, 29.2919, 136.5435)

Repair System (Level 1-5)

Config.RepairMaxLevel = 5          -- Max level for repair-only jobs
Config.RepairVehicle = 'speedo'    -- Vehicle given for repair calls

Config.MiniGameTimers = {
    tire = 10,          -- Seconds to complete tire minigame
    sparkplugs = 10,    -- Seconds to complete spark plug minigame
    battery = 10,       -- Seconds to complete battery minigame
}

Store Items

Config.StoreItems = {
    { item = 'tow_tire',      label = 'Tire',                price = 50,  minLevel = 1 },
    { item = 'tow_sparkplug', label = 'Spark Plug Kit',      price = 75,  minLevel = 1 },
    { item = 'tow_battery',   label = 'Replacement Battery', price = 100, minLevel = 1 },
}

Adding Breakdown Locations

Add new entries to the Config.Breakdowns table. Each breakdown supports optional ped, engine damage, open doors, and burst tyres:

Config.Breakdowns = {
    [15] = {
        vehicle = {
            coords = vec4(x, y, z, heading),
            model = "Vehicle Name",
            hash = `vehiclehash`,
            engineHealth = 200,           -- Optional: lower = more damaged
            doors = { [4] = true },       -- Optional: door indices to open
            tyres = { [1] = true },       -- Optional: tyre indices to burst
        },
        ped = {                           -- Optional: NPC at breakdown
            coords = vec4(x, y, z, heading),
            model = "ped_model",
            hash = `ped_model`,
            scenario = "WORLD_HUMAN_SMOKING",
        },
        fullname = "Customer Name",
        reason = 'Reason for call',
    },
}

Adding Repair Types

Add new entries to Config.RepairTypes for custom roadside repair scenarios:

Config.RepairTypes = {
    [5] = {
        id = 'custom_repair',
        label = 'Custom Repair',
        reason = 'Custom issue',
        item = 'your_item',
        itemLabel = 'Your Item',
        itemCount = 1,
        progressDuration = 5000,
        progressLabel = 'Repairing...',
        engineHealth = 200,     -- Optional
        openHood = true,        -- Optional
        tyres = {},             -- Optional
    },
}

Locale / Translations

All text is defined in locales.lua. You can translate or customize every notification, HUD message, and interaction prompt. Key locale strings include:

Key Default Value
Locale.wentOnDuty You are now on duty.
Locale.jobStarted Tow call received! Head to your flatbed.
Locale.jobCompleted Tow job completed! Payment received.
Locale.vehicleAttached Vehicle secured on the flatbed.
Locale.hookTaken Hook taken. Attach it to a vehicle.
Locale.leveledUp You reached Level %s!
Locale.purchasedItem Purchased %s!

File Structure

NR_Towing/
  ├── config.lua          -- All configuration (editable)
  ├── locales.lua         -- All text/translations (editable)
  ├── fxmanifest.lua      -- Resource manifest
  ├── Escrowed/
  │   ├── client/
  │   │   └── main.lua    -- Client logic (escrowed)
  │   └── server/
  │       └── main.lua    -- Server logic (escrowed)
  └── web/
      ├── src/            -- React source files
      └── build/          -- Compiled UI (used by NUI)

Troubleshooting

UI not opening

Flatbed not spawning

Hook/attach not working

Repair items not working

No dispatch calls received

Database errors

Target interaction not showing

Support

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