Docs / RD-Taxi v2

RD-Taxi v2 Documentation

Server-owner guide: installation, configuration, payment system, and hooks.

AuthorRox Development
Resource namerd-taxi
Version2.0
Framework supportStandalone, QBCore, QBox, ESX
DependencyPolyZone
LicenseScript unlocked - UI locked ($3.99 add-on to unlock)

1. Overview

RD Taxi is an AI-driven taxi service. Players walk to a stop, call a driver, ride to a waypoint, and pay a fare, with a set of realism systems layered on top:

  • Drivers pull over properly for pickup and drop-off instead of stopping in traffic
  • In-cabin voice lines, small talk, and reactive dialogue during the ride
  • Drivers notice and react if a passenger draws a weapon
  • Drivers notice if a passenger is badly hurt and offer to redirect to a hospital or PD
  • Automatic recovery for taxis that get flipped, stuck, or stranded in the air
  • Idle drivers wander near their stop instead of sitting frozen
  • A cancel system with a time-limited window and optional fee
  • A fully pluggable payment system that works with any framework, or none

RD Taxi does not require a specific framework. Payment is entirely optional and wired up by you - see Payment System.

Fully unlocked: every .lua file in RD Taxi v2 is open and editable out of the box - nothing is escrowed. The only locked part is the NUI (the taxi selection UI - html/). If you want that unlocked too, it's available as a small $3.99 add-on (covers the extra development effort) on our store.

2. Installation

  1. Install PolyZone and make sure it starts before rd-taxi in server.cfg.
  2. Drop the rd-taxi folder into your resources directory.
  3. Add ensure rd-taxi to server.cfg, after PolyZone.
  4. Open config.lua and set your Config.TaxiStops coordinates and Config.TaxiDrivers to match your map and roleplay needs.
  5. If you want payment enabled, fill in RD_TAXI_HOOKS.OnChargePlayer / OnRefundPlayer inside custom_functions.lua - see Payment System.
  6. Restart the server.
Edit freely: the whole script ships unlocked, but config.lua and custom_functions.lua are the two files you're actually meant to change day to day. All script files are listed in escrow_ignore inside fxmanifest.lua; only the NUI files under html/ stay locked unless purchased separately.

3. Ride Flow

  1. Player walks into a taxi stop zone, defined by Config.TaxiStops. A marker and optional floating label appear.
  2. Player presses the interact key to open the taxi panel, listing only the driver(s) assigned to that specific stop.
  3. Player picks a driver. The taxi's status becomes en_route and the driver heads to the player.
  4. The taxi arrives, pulls over at the curb, and waits. The player has Config.EntryTimeoutAfterArrival seconds to board.
  5. Player boards, opens their map, and sets a waypoint within Config.WaypointTimeout seconds.
  6. Player confirms the destination. Status becomes delivering. The fare is charged here if Config.PaymentTiming = "on_confirm".
  7. The driver drives to the destination, parks curbside, and unlocks the doors.
  8. The fare is charged here instead if Config.PaymentTiming = "on_arrival".
  9. Player exits within Config.ExitTimeout seconds. The driver returns to its assigned stop and resumes duty.

At any stage the ride can be interrupted - the player can cancel, disconnect, die, get badly hurt, or draw a weapon - and every one of these safely releases the taxi back to available instead of leaving it stuck.

4. Configuration Reference (config.lua)

Core

SettingDescription
Config.Framework"qbcore", "qbox", "esx", or "standalone". Informational only - the core ride logic doesn't branch on it, it's there for your own hooks.
Config.PaymentEnabledMaster on/off switch for the payment system.
Config.TaxiFareFlat fare charged per ride.
Config.PaymentTiming"on_confirm" or "on_arrival" - see Ride Flow.

Blips & Markers

SettingDescription
Config.TaxiBlipSprite / Color / ScaleStatic blip shown at each taxi stop.
Config.StopMarkerThe 3D marker and floating label drawn at each stop - type, color, scale, draw distance, label distance, and so on.
Config.MovingTaxiBlipSprite / Color / ScaleBlip shown while a taxi is actively coming to, or carrying, a player.
Config.ShowBlipWhenEnRoute / ShowBlipWhenDelivering / ShowBlipWhenReturningToggle the moving blip per ride phase.

Stop Labels

Stop names are auto-detected at runtime with GetNameOfZone / GetLabelText (e.g. "Downtown" → "Downtown Taxi Stop" via Config.AutoLabelSuffix). Set a manual label on a Config.TaxiStops entry only if you want to override the auto-detected name.

V2 Realism Toggles (Config.V2)

The main block controlling realistic driving behavior. Set Config.V2.Enabled = false to fall back to simpler, non-realistic driving.

FieldPurpose
VehicleProtectionMode"protected" - taxis can't be damaged or griefed. "realistic" - taxis can take damage.
EnablePullOverPark / EnableDestinationParkWhether the taxi pulls to the curb for pickup / drop-off instead of stopping mid-road.
EnableIdleWanderAvailable taxis cruise near their stop instead of sitting frozen.
EnableIndicators / EnableHazardsTurn signals and hazard lights during the relevant moments.
EnableDriverSpeech / EnableDriverLookAtPlayerDriver voice lines and head-tracking toward the player.
EnableCrashRecoveryAuto-recovery for flipped, stuck, or airborne taxis - see Crash / Stuck Recovery.
Speeds.{Pickup, Trip, Return, Wander}Max driving speed (m/s) per phase.
Distances.*Tuning for when the taxi switches into pulling-over behavior, and how precisely it stops.
Recovery.*Tuning for the stuck / flip / airborne detector.
Dispatch.*Quick Call settings - see Quick Call Dispatch.
Cancel.*Cancel window and cancel fee - see Cancel System.
Arrival.*Curbside-arrival tuning - how far from intersections, and search radius.

Timeouts

SettingDescription
Config.WaypointTimeoutSeconds to pick a destination after boarding, before being kicked.
Config.EntryTimeoutAfterArrivalSeconds to board after the taxi arrives, before the dispatch auto-cancels.
Config.MaxTrollDistanceDistance in meters beyond which wandering away from an incoming taxi can cancel the pickup.
Config.CooldownAfterKickCooldown after being kicked from a taxi before another can be called.
Config.ExitTimeoutSeconds to exit after arriving at the destination.
Config.ReservedTimeoutSeconds a taxi stays reserved for a player before the reservation expires server-side.

Taxi Stops & Drivers

Config.TaxiStops - each entry defines a name, coords, PolyZone size, heading, and spawnCoords (where the taxi parks for that stop).

Config.TaxiDrivers - each entry defines a driver's id, name, pedModel, vehicleModel, image, color, assignedStop (must match a stop's name), and driving personality (ability, aggressiveness).

Important: only taxis whose assignedStop matches the stop a player is standing at will be offered to them. This keeps dispatch distances sane and stops drivers being summoned from across the map.

Voice Lines (Config.VoiceLines)

Controls the in-cabin dialogue system - greetings, idle chatter, weather/night-aware lines, phone call / radio / smoking reactions, regular-customer greetings, ringtone, and volume levels. Most owners only need Enabled and the volume fields; see the inline comments in config.lua for every option.

Gun Detection (Config.GunDetection)

FirearmWeapons and MeleeWeapons are explicit weapon-name lists - edit them to add or remove specific weapons for your server. An explicit list, rather than "any weapon," avoids false positives from flashlights, cameras, parachutes, fire extinguishers, and similar props. Full behavior is covered in Gun Detection.

5. Payment System

Payment is entirely optional and handled through the OnChargePlayer / OnRefundPlayer hooks in custom_functions.lua. This is what makes RD Taxi framework-agnostic - wire the two functions to whatever economy your server uses (QBCore, ESX, a custom bank script, or nothing at all if Config.PaymentEnabled = false).

function RD_TAXI_HOOKS.OnChargePlayer(ctx)
    local ok, msg = exports['your-economy']:RemoveMoney(ctx.source, ctx.amount, "rd-taxi-" .. ctx.reason)
    if ok then
        return { success = true }
    end
    return { success = false, message = msg or "You don't have enough money!" }
end

Returning { success = false } cancels the ride and shows your message to the player. OnRefundPlayer doesn't need a pass/fail - a fire-and-forget call is fine either way.

6. Player Commands

/taxicancel lets a player manually cancel an active ride, registered directly in client.lua. It only works when Config.V2.Cancel.EnableCancelCommand is true.

7. Cancel System

Rides can be cancelled within a configurable window (Config.V2.Cancel), optionally with a fee. Cancelling always safely releases the taxi back to available rather than leaving it in a broken state.

FieldDescription
EnableCancelCommandAllow /taxicancel during a ride.
CancelWindowMsCancelling is only allowed within this many milliseconds of confirming the destination.
CancelFeeEnabled / CancelFeeAmountWhether cancelling charges a fee, and how much.

8. Boarding Protection

A taxi dispatched to one player is reserved server-side for Config.ReservedTimeout seconds. This stops other players jumping into a taxi that's already on its way to someone else, keeping the ride flow consistent and preventing griefing during pickup.

9. Gun Detection

Controlled by Config.GunDetection:

GunDetection = {
    Enabled = true,
    ExitTimeoutMs = 5000,
    IncludeMelee = true,
    FirearmWeapons = { ... },
    MeleeWeapons = { ... }
}

If a passenger draws a weapon from the configured lists during a ride, the driver:

  1. Reacts and stops the vehicle - handbrake, hazards on.
  2. Verbally warns the passenger.
  3. Gives them ExitTimeoutMs to get out.
  4. If they don't leave in time, the driver calls it in (firing RD_TAXI_HOOKS.OnGunDetected - wire your own police-dispatch resource here) and gets out of the car himself rather than sitting there.
  5. Once the passenger leaves, the driver gets back in, the ride is cancelled server-side (fare refunded if on_confirm timing was used), and the taxi resumes normal duty automatically.

If the passenger leaves as soon as they're warned, the driver skips straight to resuming duty.

Detection checks whether the weapon is actually drawn in the passenger's hand, not just equipped in an inventory slot, so a holstered weapon never falsely triggers this.

10. Bleeding Detection

Controlled by Config.BleedingDetection:

BleedingDetection = {
    Enabled = true,
    HealthThreshold = 0.25,
    ResponseTimeoutMs = 8000,
    Hospital = { label = "...", coords = vector3(...) },
    PoliceDepartment = { label = "...", coords = vector3(...) }
}

When a player confirms a destination below HealthThreshold of their max health, the driver notices and offers a choice instead of just driving to the original waypoint: hospital, police station, or keep the original destination. If the player doesn't respond within ResponseTimeoutMs, the driver keeps driving to the original destination.

Note: keep HealthThreshold lower than Config.VoiceLines.HurtHealthThreshold, otherwise the driver will offer a redirect on every ride where it would normally just comment on the player being hurt.

11. Crash / Stuck Recovery

Controlled by Config.V2.Recovery, active only when Config.V2.EnableCrashRecovery = true:

Recovery = {
    CheckIntervalMs = 2500,
    UpsideDownSeconds = 8,
    InAirSeconds = 10,
    StuckSeconds = 25,
    StuckMinMoveMeters = 3.0
}

Every active taxi is monitored for three failure states: flipped upside down, stuck in the air, or not making meaningful progress (StuckMinMoveMeters) while its engine is running. If any state persists past its threshold, the taxi is teleported back to its assigned stop and freed for the next dispatch. Any onboard passenger is notified and their blip cleared.

Note: the stuck check only counts time while the engine is on, so a taxi intentionally parked and waiting for boarding is correctly excluded and won't falsely trigger recovery.

12. Quick Call Dispatch

Lets a player request the closest available taxi without walking to a stop. Controlled by Config.V2.Dispatch:

FieldDescription
EnableQuickCallShows a Quick Call option in the taxi UI that dispatches the closest free taxi to the player.
ClosestUpdateMsHow often taxi positions refresh for closest-dispatch calculations.
ClosestMaxDistanceIf greater than 0, Quick Call only dispatches a taxi within this distance. 0 means unlimited.

13. Server-Owner Hooks (custom_functions.lua)

This file customizes behavior without touching the core resource. It's excluded from escrow specifically so it stays editable.

HookFires whenNotes
OnCancelRequested(ctx)A manual cancel is requested, before default logic runs.Good spot for logging, or to deny a cancel outright.
OnCancelled(ctx)After default cancel logic completes.
OnDeathCancel(ctx)A ride is cancelled because the passenger died.Return { handled = true } to fully override - if you do, you're responsible for freeing/returning the taxi.
OnGunDetected(ctx)The driver spots a weapon and starts the escalation sequence.Wire your police-dispatch resource here. Return value is unused - RD Taxi's own reaction always runs.
OnChargePlayer(ctx)A fare, cancel fee, or gun-related charge is due.See Payment System.
OnRefundPlayer(ctx)A fare or fee needs refunding.See Payment System.

Common ctx fields (best-effort - not every field is present on every hook):

source        -- number, player source
taxiId        -- number
phase         -- string: "en_route" | "delivering" | "returning" | "available" | etc.
reason        -- string: "player_dead" | "player_dropped" | "manual_cancel" | "pickup_cancel" | etc.
pickupStopKey -- string|nil
amount        -- number (payment hooks only)

14. Adding Your Own Stops & Drivers

  1. Add an entry to Config.TaxiStops with a unique name, PolyZone coords / size / heading, and spawnCoords - a vector4, where the 4th component is the spawn heading.
  2. Add an entry to Config.TaxiDrivers with a unique id, driver and vehicle details, and set assignedStop to the name from step 1.
  3. Restart the resource. The driver spawns on the next player connection and is offered only at its assigned stop.

Stop labels are auto-detected from the game world - no need to set one manually unless you want to override the name FiveM detects for that location.

15. Troubleshooting

SymptomLikely cause
Taxi never moves after being dispatchedUsually a vehicle network-ownership issue. Make sure NetworkRequestControlOfEntity runs before drive tasks are issued.
Driver frozen after confirming a destination, or after a mid-ride cancelSame network-ownership issue as above.
"You moved too far away" fires immediately on a fresh callMake sure players are only offered taxis assigned to the stop they're standing at - calling across the map will always struggle to beat Config.MaxTrollDistance.
Payment never charges on a standalone serverPayment should fire based on Config.PaymentEnabled alone. Make sure nothing in client.lua / server.lua is excluding Config.Framework == "standalone".
Taxi stuck indefinitely with no self-recoveryCheck Config.V2.EnableCrashRecovery is true and Config.V2.Recovery values aren't set unreasonably high.
No taxis shown at a stopConfirm at least one driver's assignedStop exactly matches that stop's name.

16. File Structure

rd-taxi/
├── fxmanifest.lua
├── config.lua              -- server owner: all tuning lives here
├── custom_functions.lua    -- server owner: hooks for payment, cancel, gun-detect, death
├── client/
│   ├── client.lua           -- ride flow, driving tasks, voice lines, recovery, gun detection, /taxicancel
│   └── zones.lua             -- PolyZone stop zones, markers, blips, label resolution
├── server/
│   └── server.lua            -- dispatch, status, payment triggers, cancel handling, hooks
└── html/
    ├── index.html / style.css / script.js  -- taxi selection UI (NUI) - locked unless purchased separately
    ├── images/
    └── sounds/

config.lua and custom_functions.lua are the files intended for regular editing by server owners. Every other .lua file is unlocked and readable too - only the html/ UI files are locked by default.

Documentation created by Rox Development - RD Taxi v2.

Questions about
RD-Taxi v2?