NullSect
Systems nominal

Docs / Electrician / Configuration

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

KeyDefaultEffect
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.DebugfalsePrints debug lines and draws target zones.
Config.DebugCategoriesnilnil = all. Or e.g. { rpc = true, jobs = true } (rpc, jobs, power, vehicle, session, profile, bridge).
Config.UseOxLib / Config.UseOxTargettrueAllow those integrations even when the resource is running.
Config.Company.label / .shortLSPLShown in the terminal, HUD and notifications.

Features

Config.Features switches whole subsystems off without touching code:

FlagOff means
CustomersNo NPC customers, no dialogue, no satisfaction bonus.
RandomEventsNo mid-job complications.
AssignmentsNo daily assignment page or rewards.
UpgradesEquipment upgrades cannot be bought (existing tiers keep working).
VehiclesNo service van (and with Toolbox on, nowhere to take the toolbox from — turn both off together).
ToolboxThe toolbox requirement disappears.
PowerStateJobs no longer cut power; the statebag stays all-on.
EmergenciesNo emergency calls and no dispatch cards.
HudIntegrationNever 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)

KeyEffect
coordsDuty point + job board. vector4(x, y, z, heading).
interactDistanceRadius of the duty interaction.
blipenable, sprite, color, scale.
markerenable, type, size, drawDistance — the marker thread only draws inside drawDistance.
shop.coords / shop.markerEquipment bench: upgrades and tool servicing are only possible within 6 m of it (or of the board).
vehicle.spawnWhere the van appears; also the return area.
vehicle.returnRadiusHow close the van must be to store it.
vehicle.warpInPut the player in the driver seat on spawn.
vehicle.plateFormatstring.format pattern with one number, e.g. 'ELEC%04d'.

UI and keys

KeyDefaultEffect
Config.UI.accent#ffb23fAccent colour of the whole NUI.
Config.UI.scale1.00.8 – 1.3, scales the interface.
Config.UI.summarySeconds11How long the end-of-job card stays.
Config.UI.hudEnabledtrueThe own job HUD (independent of ns-hud). Players can also switch it off on the tablet's settings page.
Config.UI.soundtrueInterface 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.tabletPropprop_cs_tabletThe prop the electrician holds while the tablet is open. Set it to nil for no prop.
Config.UI.tabletAnimamb@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.enabledtrueThe 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.itemelectrician_tabletItem name of the tablet.
Config.Keybinds.accept / .declineY / UAnswer the dispatch card.
Config.Keybinds.dialogueGTalk 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)

KeyDefaultEffect
defaultRateLimit400ms between two calls of the same RPC per player.
floodCapacity / floodRefillPerSecond28 / 7Token bucket across every RPC.
maxRequestId65535Upper bound for request ids.
flagWindowSeconds / flagLogCooldown120 / 15Suspicious-behaviour window and log throttle.
dropAfterFlags00 = 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):

KeyDefaultMeaning
useDefaultstrueAlso use the built-in sites of data/locations.lua (empty since 1.3.0).
filedata/locations.jsonWhere recorded sites are stored (keep it when updating).
viewRange120.0World view: how far markers and labels are drawn.
boxModelsprop_elecbox_*Electrical box props the recorder snaps to. Models missing on your game build are skipped; add your own props here.
boxSearchRadius6.0Metres around you to look for a box.
scan.radius60.0Scanner: metres around you that are searched for electrical props.
scan.minSpacing35.0Scanner: no two sites closer than this.
scan.categoriesbox, breaker, streetlight, traffic, transformerProp 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)

KeyDefaultEffect
boardSize4Offers generated per board.
boardRefreshSeconds150A board older than this is regenerated on the next request.
offerLifetimeSeconds240How long one offer can be accepted.
siteRadius30.0Arrival radius (travel step).
interactRadius3.5Radius for diagnosis, minigames and the restore step.
customerRadius4.0Talking distance (+2 m tolerance server-side).
defaultTimeLimitSeconds900Used when a job type has no timeLimit.
cancelCooldownSeconds45Break after a cancelled, failed or expired job.
completeCooldownSeconds8Break after a finished job.
emergencyChance0.18Chance a normal offer becomes an emergency (needs level + reputation).
emergencyTimeFactor0.65Emergency time limit multiplier.
requireToolboxtrueA job cannot be accepted without the toolbox.
sameLocationCooldownSeconds600A finished site is not offered again this soon.
minSiteDistance / maxSiteDistance120 / 4200Offers 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:

MinigameKeys
fuseboxslots, timeMs
wiringwires, timeMs, tolerance
circuitswitches, timeMs
breakersteps, timeMs
voltagerounds, speed, window, required
multimeterdurationMs, drift, requiredHold
cablestages, 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:

EffectMeaning
probeAccuracyAdded chance of an exact measurement.
probesExtra measurements per job.
toleranceExtra allowed mistakes in minigames.
timeBonusExtra minigame time (fraction).
wearFactorMultiplier on equipment wear.
qualityAdded payment/quality share.
hazardClassHighest 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)

KeyEffect
enabledMaster switch for the power state.
stateKeyStatebag key, default ns-electrician:power.
useArtificialLightstrue 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.
restoreFlashSecondsLength 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 becomes active when it is finished.
  • TALK / REPORT need customer = true and a dialogue set from data/dialogues.lua.
  • The hidden fault comes from the first INSPECT step; a job without one has no diagnosis.
  • RESTORE only makes sense with cutsPower = true.
  • Add the locale keys you used to both locales/en.lua and locales/tr.lua.

Cart

Your cart is empty.