CONFIGURATION — ns-electrician
Everything below lives in config.lua unless another file is named. Data that describes
content (job types, locations, dialogues, events, equipment tiers, assignments) lives in
data/*.lua; both stay editable under escrow.
Core
| Key | Default | Effect |
|---|---|---|
Config.Framework | 'auto' | 'auto', 'qbox', 'qbcore', 'esx', 'standalone'. Auto picks the first started framework. |
Config.Locale | 'tr' | Active language (locales/<code>.lua). |
Config.FallbackLocale | 'en' | Used for keys the active language is missing. |
Config.Debug | false | Prints debug lines and draws target zones. |
Config.DebugCategories | nil | nil = all. Or e.g. { rpc = true, jobs = true } (rpc, jobs, power, vehicle, session, profile, bridge). |
Config.UseOxLib / Config.UseOxTarget | true | Allow those integrations even when the resource is running. |
Config.Company.label / .short | LSPL | Shown in the terminal, HUD and notifications. |
Features
Config.Features switches whole subsystems off without touching code:
| Flag | Off means |
|---|---|
Customers | No NPC customers, no dialogue, no satisfaction bonus. |
RandomEvents | No mid-job complications. |
Assignments | No daily assignment page or rewards. |
Upgrades | Equipment upgrades cannot be bought (existing tiers keep working). |
Vehicles | No service van (and with Toolbox on, nowhere to take the toolbox from — turn both off together). |
Toolbox | The toolbox requirement disappears. |
PowerState | Jobs no longer cut power; the statebag stays all-on. |
Emergencies | No emergency calls and no dispatch cards. |
HudIntegration | Never talks to ns-hud. |
Job requirement
Config.Job = { required = true, name = 'electrician', minGrade = 0, requireOnDuty = false }
required = false lets anyone clock in. requireOnDuty = true additionally demands the
framework's duty flag.
Depot (Config.Center)
| Key | Effect |
|---|---|
coords | Duty point + job board. vector4(x, y, z, heading). |
interactDistance | Radius of the duty interaction. |
blip | enable, sprite, color, scale. |
marker | enable, type, size, drawDistance — the marker thread only draws inside drawDistance. |
shop.coords / shop.marker | Equipment bench: upgrades and tool servicing are only possible within 6 m of it (or of the board). |
vehicle.spawn | Where the van appears; also the return area. |
vehicle.returnRadius | How close the van must be to store it. |
vehicle.warpIn | Put the player in the driver seat on spawn. |
vehicle.plateFormat | string.format pattern with one number, e.g. 'ELEC%04d'. |
UI and keys
| Key | Default | Effect |
|---|---|---|
Config.UI.accent | #ffb23f | Accent colour of the whole NUI. |
Config.UI.scale | 1.0 | 0.8 – 1.3, scales the interface. |
Config.UI.summarySeconds | 11 | How long the end-of-job card stays. |
Config.UI.hudEnabled | true | The own job HUD (independent of ns-hud). Players can also switch it off on the tablet's settings page. |
Config.UI.sound | true | Interface sounds. They are synthesized in the NUI (WebAudio), so there are no audio files; players set their own volume on the settings page. |
Config.UI.tabletProp | prop_cs_tablet | The prop the electrician holds while the tablet is open. Set it to nil for no prop. |
Config.UI.tabletAnim | amb@code_human_in_bus_passenger_idles@female@tablet@base / base | { dict, clip } played while the tablet is open. Set the table to nil for no animation. |
Config.Tablet.enabled | true | The terminal is an inventory item taken at the depot; using it opens the tablet and a shift needs it. false (or standalone without ox_inventory): the depot point clocks in and opens the terminal. |
Config.Tablet.item | electrician_tablet | Item name of the tablet. |
Config.Keybinds.accept / .decline | Y / U | Answer the dispatch card. |
Config.Keybinds.dialogue | G | Talk to the customer. |
Players can rebind everything in Settings → Key Bindings → FiveM. Interface volume and the
HUD switch live on the tablet's settings page and are stored with the game's own key/value
store on the player's machine (ns_electrician_ui), so they survive a reconnect without any
server storage.
Config.Target: provider (auto/ox_target/qb-target/none), distance,
promptControl (control id for the built-in prompt, 38 = E), promptNearDistance.
Config.Notifications: provider (auto/ox_lib/qbox/qbcore/esx/native/custom),
duration, position, and custom = function(message, type, duration) for your own system.
Security (Config.Security)
| Key | Default | Effect |
|---|---|---|
defaultRateLimit | 400 | ms between two calls of the same RPC per player. |
floodCapacity / floodRefillPerSecond | 28 / 7 | Token bucket across every RPC. |
maxRequestId | 65535 | Upper bound for request ids. |
flagWindowSeconds / flagLogCooldown | 120 / 15 | Suspicious-behaviour window and log throttle. |
dropAfterFlags | 0 | 0 = never kick automatically. |
Config.Admin: commands = { locations, testJob, reset, grant } to rename the commands.
Who may run them is decided by the framework's own admin check, so there is nothing to grant.
Without a framework the fallback is Config.Standalone.isAdmin (the server's admin group).
Config.Locations (job sites, see /eleclocations):
| Key | Default | Meaning |
|---|---|---|
useDefaults | true | Also use the built-in sites of data/locations.lua (empty since 1.3.0). |
file | data/locations.json | Where recorded sites are stored (keep it when updating). |
viewRange | 120.0 | World view: how far markers and labels are drawn. |
boxModels | prop_elecbox_* | Electrical box props the recorder snaps to. Models missing on your game build are skipped; add your own props here. |
boxSearchRadius | 6.0 | Metres around you to look for a box. |
scan.radius | 60.0 | Scanner: metres around you that are searched for electrical props. |
scan.minSpacing | 35.0 | Scanner: no two sites closer than this. |
scan.categories | box, breaker, streetlight, traffic, transformer | Prop groups the scanner looks for. Each has models, tags (job classes), power (power system scope: district, lighting, industrial), labelKey and color. Add your own group or models here. breaker (business sites, the manager waits at the panel) starts empty: teach its models in game. |
The power system of a scanned site is picked from its position with Data.PowerAreas
(data/locations.lua).
Models taught in scan mode (aim at a prop, H) are stored as scanModels in
data/locations.json and added to the category you picked.
Config.Database: autoMigrate, jobLogRetentionDays (45), auditRetentionDays (30).
Assignments older than seven days are always purged.
Progression
Levels (Config.Levels)
maxLevel = 30,
curve = { base = 320, exponent = 1.42 }, -- total XP for a level: base * (level-1)^exponent
thresholds = nil, -- optional { [level] = totalXp } table, overrides the curve
titles = { [1] = 'title_apprentice', [5] = 'title_junior', [10] = 'title_electrician',
[20] = 'title_senior', [30] = 'title_master' },
Titles are locale keys — change the text in locales/*.lua, the level in the table.
Reputation (Config.Reputation)
start, min, max, tiers (locale key per threshold), gain, loss and gates.
gates is the minimum reputation needed per job class:
gates = { business = 45.0, industrial = 60.0, emergency = 55.0, vip = 78.0 },
Reputation goes up for finished, flawless, fast, emergency and well-explained jobs; it drops for mistakes, wrong diagnoses, cancels, abandons and timeouts.
Unlocks (Config.Unlocks)
Level gates keyed by name: job_business, job_industrial, job_emergency, job_vip,
vehicle_tier2, vehicle_tier3, upgrade_tier2, upgrade_tier3.
An unknown key counts as locked, so do not delete entries that data files reference.
XP (Config.Xp)
base per job, difficulty multipliers, emergencyMultiplier, plus flat bonuses:
flawlessBonus, fastSolveBonus, satisfactionBonus (scaled by satisfaction),
correctDiagnosis, minigameSuccess (per passed minigame), assignmentMultiplier.
Payment (Config.Payment)
Server-side formula, in order:
pay = jobType.basePay
* difficulty[difficulty]
* emergencyMultiplier (emergency calls only)
* quality (1 - mistakes*mistakePenalty - wrongDiagnosis*wrongDiagnosisPenalty, min 0.3)
* (1 + speedBonusMax * timeLeftShare)
* (1 + reputationBonusMax * reputationShare)
* (1 + equipment quality bonus)
* (1 + qualityBonusMax) (flawless only)
* (1 + satisfactionBonusMax * satisfaction)
* (1 + nightBonus) (street work at night)
* event modifiers
→ clamped to [minPay, maxPay]
account chooses 'bank' or 'cash'.
Job flow (Config.Jobs)
| Key | Default | Effect |
|---|---|---|
boardSize | 4 | Offers generated per board. |
boardRefreshSeconds | 150 | A board older than this is regenerated on the next request. |
offerLifetimeSeconds | 240 | How long one offer can be accepted. |
siteRadius | 30.0 | Arrival radius (travel step). |
interactRadius | 3.5 | Radius for diagnosis, minigames and the restore step. |
customerRadius | 4.0 | Talking distance (+2 m tolerance server-side). |
defaultTimeLimitSeconds | 900 | Used when a job type has no timeLimit. |
cancelCooldownSeconds | 45 | Break after a cancelled, failed or expired job. |
completeCooldownSeconds | 8 | Break after a finished job. |
emergencyChance | 0.18 | Chance a normal offer becomes an emergency (needs level + reputation). |
emergencyTimeFactor | 0.65 | Emergency time limit multiplier. |
requireToolbox | true | A job cannot be accepted without the toolbox. |
sameLocationCooldownSeconds | 600 | A finished site is not offered again this soon. |
minSiteDistance / maxSiteDistance | 120 / 4200 | Offers are generated inside this distance band. |
Config.Diagnosis: probeCooldownMs, maxWrongDiagnosis (one more wrong call than this fails
the job), and accuracy = { [tier] = chance } — the chance that a measurement gives an exact
reading per multimeter tier (equipment effects are added on top).
Config.Time: source (auto reads GlobalState.currentTime.hour from a weather/time sync
resource, fixed, real), fixedHour, nightFrom, nightTo.
Minigames (Config.Minigames)
Global: maxAttempts (shown in the UI), failJobAfterMaxAttempts (false = the player may keep
trying, every failure still costs mistakes and wear), retryCooldownMs.
Per minigame, keyed by difficulty:
| Minigame | Keys |
|---|---|
fusebox | slots, timeMs |
wiring | wires, timeMs, tolerance |
circuit | switches, timeMs |
breaker | steps, timeMs |
voltage | rounds, speed, window, required |
multimeter | durationMs, drift, requiredHold |
cable | stages, timeMs, window |
Minigames with no explicit tolerance use EASY 2 / NORMAL 1 / HARD 1 / EXPERT 0 allowed
mistakes; the tool kit tier and random events shift that number.
Equipment (Config.Equipment + data/equipment.lua)
Config.Equipment: requireItems, items (tool id → inventory item), wearPerJob,
wearPerMistake, serviceCostPerPoint, toolboxProp, ladderProp.
data/equipment.lua holds the tiers themselves. Each tier has labelKey, price, unlock
(a Config.Unlocks key) and effects:
| Effect | Meaning |
|---|---|
probeAccuracy | Added chance of an exact measurement. |
probes | Extra measurements per job. |
tolerance | Extra allowed mistakes in minigames. |
timeBonus | Extra minigame time (fraction). |
wearFactor | Multiplier on equipment wear. |
quality | Added payment/quality share. |
hazardClass | Highest job class allowed (Data.HazardClass: residential/street 0, business 1, industrial 2). |
Vehicles (Config.Vehicles)
tiers = {
{ id = 'van', model = 'burrito3', labelKey = 'vehicle_van', price = 0, unlock = nil, ... },
...
}
Ordered cheapest → best; they must be bought in order. unlock is a Config.Unlocks key,
deleteOnShiftEnd removes the van when the shift ends, livery sets a livery index (-1 = none).
Power (Config.Power)
| Key | Effect |
|---|---|
enabled | Master switch for the power state. |
stateKey | Statebag key, default ns-electrician:power. |
useArtificialLights | true adds a local blackout effect for the electrician working an outage. Off by default because it is a client-side visual that affects the whole map for that player. |
restoreFlashSeconds | Length of the light flash when power returns. |
Systems themselves are defined in data/locations.lua (Data.PowerSystems) and referenced by
each location's power field.
Events and assignments
Config.Events: chance (per trigger) and maxPerJob.
The events themselves are in data/events.lua; only these effect keys are understood:
invalidateHint, extraStep, toleranceDelta, wear, timeLimitFactor, payFactor,
xpFactor, repeatRestore.
Config.Assignments: enabled, count (drawn per day), resetHour (server local hour).
Templates with metric, target and reward are in data/assignments.lua. Valid metrics:
jobs, flawless, emergency, diagnosis, minigames, class:<class>, type:<jobTypeId>.
Adding a job type
data/jobtypes.lua, append to Data.JobTypes:
{
id = 'my_job', -- never rename after release (stored in the job log)
labelKey = 'job_my_job', descKey = 'job_my_job_desc',
class = 'residential', -- residential | business | street | industrial
difficulty = 'NORMAL', weight = 10,
minLevel = 3, unlock = nil, repGate = nil,
locationTags = { 'residential' },
customer = true, dialogue = 'house_fault',
basePay = 400, xpFactor = 1.2, timeLimit = 600, cutsPower = true,
tools = { 'multimeter', 'screwdriver' },
steps = {
{ type = Const.Step.TRAVEL, labelKey = 'obj_drive_site' },
{ type = Const.Step.TALK, labelKey = 'obj_talk_customer' },
{ type = Const.Step.INSPECT, labelKey = 'obj_find_breaker', pool = 'breaker',
count = { EASY = 4, NORMAL = 6, HARD = 7, EXPERT = 8 } },
{ type = Const.Step.MINIGAME, labelKey = 'obj_rewire_circuit', game = Const.Minigame.WIRING },
{ type = Const.Step.RESTORE, labelKey = 'obj_restore_power' },
{ type = Const.Step.REPORT, labelKey = 'obj_report_customer' },
},
},
Rules the server enforces:
- The first step should be
TRAVEL— the job only becomesactivewhen it is finished. TALK/REPORTneedcustomer = trueand adialogueset fromdata/dialogues.lua.- The hidden fault comes from the first
INSPECTstep; a job without one has no diagnosis. RESTOREonly makes sense withcutsPower = true.- Add the locale keys you used to both
locales/en.luaandlocales/tr.lua.