qb-towjob
qb-towjob gives the tow job a flatbed, NPC vehicles to collect, and a payout at the end of a
shift. The flatbed requires a deposit that is refunded on return.
The /tow command is also usable by the mechanic job, which makes this resource a soft
dependency of a mechanic workflow. See qb-mechanicjob.
Before deploying it, read Payout. The shift payout scales with a drop count sent by the client.
The manifest at the commit linked above declares version 1.2.0.
Dependencies and start order
From the manifest: @qb-core/shared/locale.lua, config.lua and locales as shared scripts, the
PolyZone client files client.lua, BoxZone.lua, ComboZone.lua, plus client/main.lua and
server/main.lua.
From the implementation: qb-core for the full core object, and
qb-inventory for the crypto stick reward.
Start order: qb-core, qb-inventory, PolyZone, then qb-towjob.
Note that server/main.lua calls exports['qb-core']:GetCoreObject() with no filter, so it holds a
reference to the whole core table including QBCore.Shared.Items.
Configuration
| Key | Default | Meaning |
|---|---|---|
Config.UseTarget | from the UseTarget convar | Set setr UseTarget true in server.cfg |
Config.BailPrice | 250 | Flatbed deposit |
Config.Vehicles | { flatbed = 'Flatbed' } | Job vehicles |
Config.Locations | table | main headquarters, vehicle spawn, dropoff |
The per-drop pay and the tax rate are not in the config. PaymentTax = 15 is a local in
server/main.lua, and the per-drop price is math.random(150, 170) in the same file.
Commands
| Command | Registered with | Who can use it |
|---|---|---|
/npc | QBCore.Commands.Add | Everyone, toggles the NPC display |
/tow | QBCore.Commands.Add | Handler checks job.name is tow or mechanic |
Both use the default user permission, so the job check inside the handler is the real gate.
Server surface
| Handler | Kind | Arguments |
|---|---|---|
qb-tow:server:DoBail | net event | bool, vehInfo |
qb-tow:server:nano | net event | vehNetID |
qb-tow:server:11101110 | net event | drops |
Deposit
DoBail with bool = true charges Config.BailPrice from cash, or from the bank if cash is short,
records the amount per citizenid, and spawns the vehicle. With bool = false it refunds the
recorded amount to the bank. The record lives in memory, so a restart between taking and returning
the flatbed loses the refund.
Note the refund always goes to the bank even when the charge came from cash.
Crypto stick find
qb-tow:server:nano takes a network ID, resolves the entity on the server, and requires:
- the caller’s
job.nameto betow - the distance between the caller’s vehicle and the target vehicle to be 11.0 or less
Failure results in DropPlayer. On success there is a roughly 25 percent chance of a
cryptostick. Note it resolves the entity from a network ID rather than trusting coordinates, which
is the correct way to reference an entity across the client and server boundary. See
OneSync and networked entities for why.
Payout
qb-tow:server:11101110 is the shift payout. It checks the caller’s job is tow and that the
caller is within 6.0 units of Config.Locations['main'].coords, both read server side, then
computes:
local DropPrice = math.random(150, 170)
local price = (DropPrice * drops) + bonus
local taxAmount = math.ceil((price / 100) * PaymentTax)
Player.Functions.AddMoney('bank', price - taxAmount, 'tow-salary')drops arrives from the client and is only passed through tonumber. It is not compared against
anything the server recorded, so the payout scales linearly with a value the client chooses. That is
the one thing to fix before running this on a public server. Track completed drops per source on the
server, as qb-garbagejob does with its route table, and ignore the
client’s number.
The bonus tiers are also worth reading before tuning them:
if drops > 5 then bonus = ...
elseif drops > 10 then bonus = ...
elseif drops > 15 then bonus = ...
elseif drops > 20 then bonus = ...
endBecause the chain is ordered ascending, any value above 5 matches the first branch and the three later branches are unreachable. Reverse the order if you want the higher tiers to apply.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Deposit not refunded after a restart | The deposit table is in memory only |
| Refund arrives in the bank after a cash payment | The refund branch always targets the bank |
| Player dropped on the crypto stick roll | Job is not tow, or the vehicles are more than 11 units apart |
| No payout | Not within 6.0 units of the headquarters coordinates, or the job is not tow |
| Bonus tiers never change | The elseif ordering, see above |
/tow does nothing | The job is neither tow nor mechanic |
Proposed manual smoke test
Not yet executed. On staging:
- Take the flatbed, confirm the charge, return it, confirm the refund and which account it lands in.
- Restart the server between those steps and confirm the refund is lost.
- Complete one drop and confirm the payout after tax.
- Fire the payout event from outside 6 units and confirm the drop.
- After adding server-side drop tracking, confirm a forged count no longer changes the payout.