Full Config Reference
The complete default configs/server/contact.lua for Dead Drop. Use this as a reference or starting point for your own configuration.
TIP
This is the full unedited config file. For a detailed explanation of each option, see the Configuration page.
lua
-- SERVER-ONLY (not in fxmanifest files{}, never ships to clients): contact spawn spots + the full
-- fence economy, reward ladder, and the snitch/notify/buy economies. Display bits + on/off switches
-- live in configs/shared/contact.lua; starting heat + decay in configs/server/heat.lua.
return {
-- Candidate contact spots; the server picks ONE per restart and publishes its coords via GlobalState.
Locations = {
vec4(2383.57, 3352.75, 47.41, 90.08), -- Sandy Shores (placeholder)
-- vec4(0.0, 0.0, 0.0, 0.0), -- add more spots here
},
-- Fence payout: 'clean' pays the Qbox cash account, 'dirty' pays the black_money item. XP unaffected.
PayoutType = 'clean', -- 'clean' | 'dirty'
DirtyItem = 'black_money', -- item paid when PayoutType = 'dirty'
CleanAccount = 'cash', -- Qbox account credited when PayoutType = 'clean'
-- Metres a player must be from the contact for any at-the-counter callback (reward, buy, snitch,
-- subscribe) - a shared server-side anti-exploit gate. Falls back to SpawnDistance if unset.
ClaimDistance = 5.0,
-- Trunk selling, server-only half (the switch + radius live in shared Selling.Trunk).
Selling = {
Trunk = {
-- Another player's registered vehicle is ALWAYS refused; this only decides UNREGISTERED
-- NPC/stolen/rented vans: false = sellable (the intended heist-van flow), true = the
-- seller must own the plate in player_vehicles.
RequireOwned = false,
},
},
-- What the contact buys; cash/xp are PER UNIT at full (cool) price. Heat discounts cash, never xp.
Sellables = {
{ item = 'deaddrop_item_1', cash = 1000, xp = 50 },
{ item = 'deaddrop_item_2', cash = 500, xp = 25 },
{ item = 'deaddrop_item_3', cash = 800, xp = 40 },
{ item = 'deaddrop_item_4', cash = 600, xp = 30 },
{ item = 'deaddrop_item_5', cash = 1200, xp = 60 },
{ item = 'deaddrop_item_6', cash = 400, xp = 20 },
{ item = 'deaddrop_item_7', cash = 1500, xp = 75 },
{ item = 'deaddrop_item_8', cash = 700, xp = 35 },
{ item = 'deaddrop_item_9', cash = 900, xp = 45 },
{ item = 'deaddrop_item_10', cash = 2000, xp = 100 },
{ item = 'deaddrop_item_11', cash = 1100, xp = 55 },
{ item = 'deaddrop_item_12', cash = 1300, xp = 65 },
},
-- Heat pricing: what the contact pays/says for hot goods (tracked per item via `heat` metadata).
-- The server resolves price + word before anything reaches the client.
Heat = {
Max = 100, -- metadata `heat` scale: 0..Max
Floor = 0.25, -- never sell below this fraction of base cash, however hot
-- Discount curve, interpolated. `heat` = 0..1 fraction of Max (ascending, first row 0);
-- `off` = cash discount there (0..1). Empty curve = no discount.
Curve = {
{ heat = 0.0, off = 0.00 }, -- cooled: full price
{ heat = 0.34, off = 0.15 }, -- warm
{ heat = 0.67, off = 0.35 }, -- hot
{ heat = 1.0, off = 0.60 }, -- red hot (max)
},
-- Display word per band (separate ascending list, same first-row-0 rule). `key` is a locale
-- key; use `label` instead for a literal untranslated word.
Bands = {
{ heat = 0.0, key = 'contact.heat.cool' },
{ heat = 0.34, key = 'contact.heat.warm' },
{ heat = 0.67, key = 'contact.heat.hot' },
{ heat = 1.0, key = 'contact.heat.redhot' },
},
},
Reputation = {
-- Level ladder, ascending. `xp` = CUMULATIVE XP to reach the level (first row MUST be 0);
-- `key` maps to locale reputation.tier.<key>; optional `reward` = one-time gift on reaching it.
Levels = {
{ xp = 0, key = 'stranger' },
{ xp = 150, key = 'acquaintance', reward = { item = 'lockpick', count = 2 } },
{ xp = 500, key = 'associate', reward = { item = 'advancedlockpick', count = 2 } },
{ xp = 1200, key = 'trusted', reward = { item = 'armour', count = 1 } },
{ xp = 2500, key = 'confidant', reward = { item = 'thermite', count = 1 } },
{ xp = 5000, key = 'inner_circle', reward = { item = 'goldbar', count = 1 } },
},
-- Cash payout multiplier by level (index = level number; missing = 1.0). Enabled = false pays base.
PayoutMultiplier = {
Enabled = true,
ByLevel = {
1.00, -- stranger
1.05, -- acquaintance
1.12, -- associate
1.22, -- trusted
1.35, -- confidant
1.50, -- inner_circle
},
},
},
-- Snitch economy (the menu on/off switch stays client-side in shared/contact.lua).
Snitch = {
MinLevel = 3, -- minimum reputation LEVEL to buy intel
Fee = 5000, -- flat fee per successful snitch (0 = free)
Account = 'cash', -- Qbox account the fee comes from: 'cash' | 'bank'
},
-- Gear shop (the menu switch stays client-side). Entries: item, price, count (default 1), and an
-- optional minLevel gate - locked entries still show in red ("show but refuse"). The backend
-- re-checks level, proximity, funds, and inventory space on every purchase.
Buy = {
Account = 'bank', -- Qbox account purchases come from: 'cash' | 'bank'
Catalog = {
{ item = 'merryweather_tablet', price = 25000, count = 1 }, -- the hacking rig (ungated)
{ item = 'deaddrop_usb_1', price = 4000, count = 1 }, -- Runner Kit: 2 daemons (ungated)
{ item = 'deaddrop_usb_2', price = 4000, count = 1 }, -- Breaker Kit: 2 daemons (ungated)
{ item = 'deaddrop_usb_3', price = 9000, count = 1, minLevel = 2 }, -- Decrypt Suite: 3 daemons - Acquaintance
{ item = 'deaddrop_usb_4', price = 9000, count = 1, minLevel = 4 }, -- Black ICE Suite: 3 daemons - Trusted
},
},
-- Drop-alert subscription (the menu switch stays client-side). OnDrop fires ON THE SERVER once
-- per subscribed online player the moment a new drop is made - swap the notify below for your
-- phone resource (data.src is the subscriber's server id). The default routes through the
-- bridge's notify event, so it renders on whatever notification system the server runs.
Notify = {
MinLevel = 3, -- minimum reputation LEVEL to subscribe
Fee = 10000, -- one-time fee to subscribe (0 = free)
Account = 'bank', -- account the fee comes from: 'cash' | 'bank'
---@param data table { src, citizenid, eventId, containerCount, region = { x, y } }
OnDrop = function(data)
TriggerClientEvent('sd-deaddrop:client:notify', data.src, {
title = locale('contact.notify_title'),
description = locale('contact.notify.alert'),
type = 'inform',
duration = 5000,
})
end,
},
}