Documentation

Config

Explanations and examples for the current catalytic configuration.

Edit zyke_catalytic/shared/unlocked/config.lua. Distances are metres, durations ending in Ms are milliseconds, and chances are percentages unless stated otherwise. Camera offsets are metres from the cut.

Keybinds can be changed in GTA / FiveM settings. Framework, inventory, target, and webhook settings live in zyke_lib. Grinder, disc, and battery settings live in zyke_anglegrinder.

#Full Default Config

#Config.Settings.catalytic

#enabled

Enables the resource. When disabled, jacks, theft, installs, effects, and the fence are unavailable.

Example:

lua
enabled = true

#admin.enabled

Enables the admin panel and the admin vehicle target.

Example:

lua
enabled = true

#admin.command

Command that opens the admin panel.

Example:

lua
command = "catadmin"

#admin.permission

Permission checked on both client and server for the admin panel, vehicle target, and test commands. This is a permission identifier, not a job name.

Example:

lua
permission = "command"

#admin.refreshMs

Milliseconds between automatic refreshes while the admin panel is open.

Example:

lua
refreshMs = 3000

#settings.commands

Commands that open the personal settings menu. The menu is also at the bottom of the fence menu. Use an empty table for no command.

Example:

lua
commands = {"catalytic", "catsettings"}

#Converter Sizes

Each entry under Config.Settings.catalytic.sizes defines one converter size. Defaults use small, medium, and large. In the paths below, <size> means one of these keys.

SettingSmallMediumLarge
Itemcatalytic_converter_smallcatalytic_converter_mediumcatalytic_converter_large
Base price350600900
Cut checks per pipe1 easy2 easy2 medium
Disc wear6–1210–1614–22

#sizes.<size>.item

Inventory item given for a stolen converter of this size. The item stores the vehicle, plate, grade, value, and condition in its metadata.

Example:

lua
item = "catalytic_converter_small"

#sizes.<size>.price

Fence base payout for a converter in perfect condition, before the vehicle's value multiplier and grade value.

Example:

lua
price = 350

#sizes.<size>.prop

Converter model. Grade suffixes are added to this name.

Example:

lua
prop = "zyke_catalytic_small"

#sizes.<size>.stages

One entry per pipe cut, verified by zyke_anglegrinder. seconds plus the grinder's secondsPerCheck for each checks preset make up the cut's length; the hardest preset sets its difficulty.

Example:

lua
stages = {
    {checks = {"easy"}, seconds = 1},
    {checks = {"easy"}, seconds = 1},
}

#sizes.<size>.durabilityLoss

Disc wear range for the whole theft. Clean cuts halve it.

Example:

lua
durabilityLoss = {min = 6, max = 12}

#Grades

Grades are rolled once per car and shown on the converter under it.

#grades.engineBias

Tilts the roll toward better grades for a healthy engine and worse grades for a wrecked one. 0 leaves it to chance.

Example:

lua
engineBias = 0.5

#grades.list

Grades from best to worst. weight is the share of cars with that grade, value multiplies the fence payout, and suffix is added to the size's prop and item image names. label is a locale key. The defaults range from pristine (1.35) to holed (0.35).

Example:

lua
list = {
    {name = "pristine", label = "grade:pristine", weight = 4, value = 1.35, suffix = "_pristine"},
    {name = "clean", label = "grade:clean", weight = 6, value = 1.25},
    {name = "holed", label = "grade:holed", weight = 5, value = 0.35, suffix = "_holed"},
}

#Guards

Anti-theft guards are cut through before the pipes. A car's guard is rolled the first time a thief goes under it and kept by plate and model, along with completed cuts, until the resource restarts.

#guards.enabled

Enables anti-theft guards.

Example:

lua
enabled = true

#guards.chance

Percent of cars with a guard.

Example:

lua
chance = 15

#guards.valueChance

Extra percent added for every whole value multiplier above 1, so more valuable converters are guarded more often.

Example:

lua
valueChance = 15

#guards.types

Guard types: cable (two stainless cables), cage (three welded hoops), and shield (a plate cut across at both ends). weight is each type's share of guarded cars, stage is the grind stage of each cut in the same form as size stages, and durabilityLoss is the extra disc wear for all its cuts.

Example:

lua
types = {
    cable = {label = "guard:cable", weight = 50, stage = {seconds = 1}, durabilityLoss = {min = 2, max = 4}},
    cage = {label = "guard:cage", weight = 32, stage = {checks = {"medium"}}, durabilityLoss = {min = 6, max = 10}},
    shield = {label = "guard:shield", weight = 18, stage = {checks = {"hard"}, seconds = 1}, durabilityLoss = {min = 10, max = 16}},
}

#guards.lunge

Most condition points the converter loses when the disc breaks through a cable or hoop and is pushed past the gap into the converter.

Example:

lua
lunge = 12

#guards.camera

Close-up on a hoop or shield during the cut. Cables use the converter cut camera.

Example:

lua
camera = {
    offset = {x = 0.3, y = 0.34, z = -0.2},
    look = {x = 0.0, y = -0.04, z = 0.0},
    fov = 50.0,
    blendInMs = 900,
    blendOutMs = 700,
}

#guards.plateCut

Shield plate cut. The disc only cuts once plunged through the plate. Plunged more than depth further, it cuts at dragSpeed of the pace and wears dragWear times faster. sensitivity is metres moved per unit of mouse movement.

Example:

lua
plateCut = {
    depth = 0.01,
    dragSpeed = 0.6,
    dragWear = 2.0,
    sensitivity = {push = 0.048, plunge = 0.016},
}

#Vehicles

#vehicles.classes

Vehicle class to converter size and value multiplier. value multiplies what the converter is worth at the fence and on contract hand-ins, and is stored on the item. Classes left out, such as motorcycles, boats, and aircraft, cannot be cut.

Example:

lua
classes = {
    [0] = {size = "small"}, -- Compacts
    [2] = {size = "large"}, -- SUVs
    [7] = {size = "medium", value = 2.0}, -- Super
}

#vehicles.models

Spawn name to size and value, replacing the class entry. Hybrids carry the most precious metal by default.

Example:

lua
models = {
    dilettante = {size = "small", value = 2.5},
}

#vehicles.excluded

Spawn names without a converter, such as electric vehicles. Vehicles without an exhaust bone are skipped too.

Example:

lua
excluded = {"voltic", "raiden", "cyclone", "neon"}

#vehicles.requireEngineOff

Only allows parked vehicles with the engine off. Vehicles must always have no driver and be stationary.

Example:

lua
requireEngineOff = true

#vehicles.blockOwned

Refuses vehicles owned by a player, looked up by plate in owned_vehicles on ESX or player_vehicles on QBCore and Qbox. Applied in the server can-check hooks.

Example:

lua
blockOwned = true

#vehicles.position

Converter position under the body. forward is a share of the half length ahead of the centre, inset is metres in from the side, and height is metres above the underbody.

Example:

lua
position = {forward = 0.3, inset = 0.35, height = 0.25}

#vehicles.reach

Furthest distance from the cut point at which a player can start the theft.

Example:

lua
reach = 1.6

#Theft

#theft.alarmChance

Percent chance per theft that the car alarm goes off when the grinder first bites into the metal. Alarms call OnConverterAlert.

Example:

lua
alarmChance = 35

#theft.witnessDistance

Overrides zyke_anglegrinder's witness distance for converter cuts. false keeps the grinder's value.

Example:

lua
witnessDistance = false

#theft.pullOut

Converter held in the left hand as the player slides out, and the stow animation played once standing. The prop is removed despawnMs into the animation.

Example:

lua
pullOut = {
    stow = {dict = "anim@heists@humane_labs@finale@keycards", clip = "ped_a_pass", ms = 1200, despawnMs = 1000},
    bone = 18905,
    offset = {x = 0.18, y = 0.02, z = -0.02},
    rotation = {x = -80.0, y = 0.0, z = 90.0},
}

#theft.condition

Converter condition from the vehicle's engine health. A wrecked engine still yields at least min percent; wearMax is the most random wear removed.

Example:

lua
condition = {min = 40, wearMax = 8}

#theft.scene.jack.item

Reusable jack item. Placing it takes the item; picking the jack back up returns it.

Example:

lua
item = "catalytic_jack"

#theft.scene.jack.aimDistance

Furthest distance from the player to the aimed jacking point.

Example:

lua
aimDistance = 4.0

#theft.scene.jack.promptDistance

Distance from a raised car's lie spot within which its go-under marker shows.

Example:

lua
promptDistance = 10.0

#theft.scene.jack.skipClearance

Floor clearance in metres at which a parked car can be gone under without a jack. A jacked Sultan gives about 0.26, a Baller 0.41, and a Sandking 0.90.

Example:

lua
skipClearance = 0.35

#theft.scene.jack.roll

Most tilt in degrees as the near side rises on the jack.

Example:

lua
roll = 12.0

#theft.scene.jack.strokes

Handle strokes needed to lift the car.

Example:

lua
strokes = 6

#theft.scene.jack.releaseMs

Time the opened valve takes to lower the car.

Example:

lua
releaseMs = 2500

#theft.scene.jack.kneelDistance

Distance back from the jack along its handle where the player kneels.

Example:

lua
kneelDistance = 0.72

#theft.scene.jack.pump

Pump animation played over the kneel; the lever follows its stroke. kneel, release, putDown, pickUp, and draw use the same format for the other jack animations.

Example:

lua
pump = {dict = "zyke_catalytic_jack_anims", clip = "pump", flag = 49}

#theft.scene.jack.hold

Carry animation and bone attachment while aiming the jack.

Example:

lua
hold = {
    anim = {dict = "move_weapon@jerrycan@generic", clip = "idle"},
    bone = 57005,
    offset = {x = 0.27, y = -0.01, z = -0.025},
    rotation = {x = -0.5, y = -81.5, z = -12.0},
}

#theft.scene.anims

Under-car enter, loop, and exit animations. phase holds an animation still at that share of its clip.

Example:

lua
anims = {
    enter = {dict = "amb@world_human_vehicle_mechanic@male@enter", clip = "enter"},
    loop = {dict = "amb@world_human_vehicle_mechanic@male@base", clip = "base", phase = 0.69},
    exit = {dict = "amb@world_human_vehicle_mechanic@male@exit", clip = "exit"},
}

#theft.scene.lieOut

Distance out from the car's side where the player lies.

Example:

lua
lieOut = 0.35

#theft.scene.grip

Grinder grip while lying, passed to zyke_anglegrinder so every client sees it.

Example:

lua
grip = {
    bone = 57005,
    offset = {x = 0.12, y = 0.02, z = -0.02},
    rotation = {x = 0.0, y = 180.0, z = 90.0},
}

#theft.scene.pipeGap

Distance between the pipe and the disc edge, toward the floor.

Example:

lua
pipeGap = 0.03

#theft.scene.camera

Under-car camera. x points toward the car's centre, y along the pipe away from the converter, and z up.

Example:

lua
camera = {
    offset = {x = 0.35, y = 0.55, z = -0.18},
    look = {x = 0.0, y = -0.05, z = 0.0},
    fov = 50.0,
    blendInMs = 900,
    blendOutMs = 700,
}

#theft.scene.light

Head torch lighting the underside while the player works.

Example:

lua
light = {color = {r = 255, g = 228, b = 196}, range = 2.2, intensity = 3.0}

#theft.minigame

converterCut drives the grinder in a close-up on the pipes. pipeCut plays a ring panel where the disc is steered around the pipe.

Example:

lua
minigame = "converterCut"

#Converter Cut

Settings under Config.Settings.catalytic.theft.converterCut. The mouse slides the grinder along the pipe and feeds it into the metal while the press key spins it. The joint cuts clean; off it, the cut is slower, wears the disc faster, and damages the converter.

#converterCut.keys

Keys that spin the disc.

Example:

lua
keys = {press = {"LEFTMOUSE", "SPACE"}}

#converterCut.sensitivity

Metres the disc moves per unit of mouse movement.

Example:

lua
sensitivity = {slide = 0.048, feed = 0.02}

#converterCut.pressure

Feed depth band in metres. Under min, the disc only rubs; over max, it binds and costs bindDamage condition per second. wander scales how far the disc's grab drifts, so the feed needs steady correction.

Example:

lua
pressure = {min = 0.003, max = 0.012, bindDamage = 8, wander = 1.5}

#converterCut.spot

Within tolerance metres of the joint, the cut is clean. Off-spot effects build over the next falloff metres.

Example:

lua
spot = {tolerance = 0.012, falloff = 0.04}

#converterCut.offSpot

Fully off the joint: cut speed share, disc wear multiplier, and condition lost per pipe. Cutting on the converter's side multiplies the damage by converterSide.

Example:

lua
offSpot = {speed = 0.45, wear = 2.5, damage = 30, converterSide = 1.5}

#converterCut.maxDamage

Most condition points one theft can remove from the converter.

Example:

lua
maxDamage = 60

#converterCut.commitDepth

Kerf depth at which the disc is held until dropped clear of the pipe.

Example:

lua
commitDepth = 0.003

#converterCut.twist

Sideways movement that binds a committed disc.

Example:

lua
twist = 0.012

#converterCut.lean

Degrees the grinder body leans out toward the player.

Example:

lua
lean = 20.0

#converterCut.mark

Chalk band around the joint, as wide as the clean zone. false for none.

Example:

lua
mark = {r = 245, g = 222, b = 120, a = 160}

#converterCut.camera

Close-up on the pipe being cut.

Example:

lua
camera = {
    offset = {x = 0.32, y = 0.4, z = -0.22},
    look = {x = 0.0, y = -0.08, z = 0.0},
    fov = 50.0,
    blendInMs = 900,
    blendOutMs = 700,
}

#Pipe Cut

Settings under Config.Settings.catalytic.theft.pipeCut, used when minigame = "pipeCut". The disc is steered around the pipe while held in. Lingering heats the metal until the disc binds; sweeping too fast skates without cutting.

#pipeCut.segments

Parts around the pipe, each cut through on its own.

Example:

lua
segments = 12

#pipeCut.keys

Keys that hold the disc in and steer it. Names are zyke_lib key names, so each follows the player's own binding.

Example:

lua
keys = {press = {"LEFTMOUSE", "SPACE"}, left = "A", right = "D"}

#pipeCut.acceleration

How fast the swing builds while steering, in safe sweep speeds per second.

Example:

lua
acceleration = 3.0

#pipeCut.friction

How fast the swing dies out after steering.

Example:

lua
friction = 2.5

#pipeCut.difficulties

Per difficulty: pass is the share of a part one pass can cut before binding, skate is how many times the slowest safe sweep the disc can go before skating, and cool is how many parts' cut time a bound part needs to cool.

Example:

lua
difficulties = {
    easy = {pass = 0.7, skate = 2.8, cool = 2.5},
    medium = {pass = 0.55, skate = 2.3, cool = 3.0},
    hard = {pass = 0.45, skate = 1.9, cool = 3.5},
}

#pipeCut.glowSeconds

Seconds a freshly cut part keeps glowing.

Example:

lua
glowSeconds = 4.0

#Effects

What running without a converter does to a vehicle, seen and heard by every nearby player.

#effects.enabled

Enables the missing-converter effects.

Example:

lua
enabled = true

#effects.engineSound

Engine sound used while the converter is missing, as any vehicle audio name. false keeps the stock sound.

Example:

lua
engineSound = "tornado6"

#effects.engineSoundStock

Stock audio names restored after install, keyed by lowercase model name. Only needed for addon vehicles whose audioNameHash differs from the model name.

Example:

lua
engineSoundStock = {
    mycar = "comet2",
}

#effects.engineAudioDamage

Rough engine note, from 0 (stock) to 1 (fully damaged).

Example:

lua
engineAudioDamage = 0.9

#effects.exhaustPops

Enables pops and crackles off throttle for vehicles that do not pop by default.

Example:

lua
exhaustPops = true

#effects.backfire

Exhaust flames when the driver lifts off above minRpm (a 0 to 1 share of the rev range), and on misfires.

Example:

lua
backfire = {
    enabled = true,
    chance = 70,
    minRpm = 0.45,
    cooldownMs = 1000,
    asset = "core",
    name = "veh_backfire",
    scale = 1.0,
}

#effects.misfire

Brief engine cut-outs under throttle. Interval and duration are rolled between min and max.

Example:

lua
misfire = {
    enabled = true,
    intervalMs = {min = 2500, max = 7000},
    durationMs = {min = 120, max = 320},
}

#effects.smoke

Dark exhaust puffs while the throttle is above minThrottle. offset moves the smoke from each exhaust tip, rotation turns the particle, and colour tints it from 0 to 1 per channel.

Example:

lua
smoke = {
    enabled = true,
    minThrottle = 0.8,
    delayMs = 400,
    intervalMs = 1400,
    durationMs = 600,
    asset = "scr_recartheft",
    name = "scr_wheel_burnout",
    scale = 0.4,
    offset = vec3(0.0, -0.3, 0.12),
    rotation = vec3(-30.0, 0.0, 180.0),
    colour = {r = 0.08, g = 0.08, b = 0.08},
    alpha = 0.45,
}

#effects.powerMultiplier

Engine torque multiplier for the driver. 1.0 for no power loss.

Example:

lua
powerMultiplier = 0.7

#effects.checkEngineNotify

Notifies the driver when they start driving a vehicle without its converter.

Example:

lua
checkEngineNotify = true

#persistence.enabled

Keeps missing converters by plate, so a garage respawn still runs rough.

Example:

lua
enabled = true

#persistence.days

Days before a missing-converter record expires. false keeps it until a converter is installed.

Example:

lua
days = 14

#Install

#install.enabled

Enables installing replacement converters from the item and the vehicle target.

Example:

lua
enabled = true

#install.items

Items that can be installed. Stolen converters also work when listed here.

Example:

lua
items = {"catalytic_converter_new"}

#install.seconds

Install duration in seconds.

Example:

lua
seconds = 12

#install.reach

Furthest distance from the vehicle's side at which an install can start.

Example:

lua
reach = 2.5

#install.anim

Animation played during the install.

Example:

lua
anim = {dict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", clip = "machinic_loop_mechandplayer", flag = 1}

#install.prop

Prop held during the install. false for none.

Example:

lua
prop = {model = "zyke_catalytic_new", bone = 18905, pos = vec3(0.16, 0.02, -0.03), rot = vec3(-80.0, 0.0, 90.0)}

#Fence

Fence peds buy stolen converters, hand out contracts, and sell tools. Item entries use configured item names, so renamed items need their entries updated too.

#fence.enabled

Enables fence peds.

Example:

lua
enabled = true

#fence.payoutAccount

Account the fence pays into, such as cash, bank, or black_money.

Example:

lua
payoutAccount = "cash"

#fence.conditionFloor

Share of the payout a converter in 0% condition still fetches.

Example:

lua
conditionFloor = 0.5

#fence.wornShare

Share of the fence's price a used part at 100% durability fetches when sold back.

Example:

lua
wornShare = 0.8

#fence.market

Shared demand for converters sold outright, saved in the database. The fence pays at most maxShare of a converter's value; every sale lowers that by dropPerSale, and it recovers by recoverPerHour. Below minShare, he buys nothing until it recovers to reopenShare. Contracts are not affected.

Example:

lua
market = {maxShare = 0.4, minShare = 0.1, reopenShare = 0.15, dropPerSale = 0.01, recoverPerHour = 0.05}

#fence.sellRep

Reputation rolled per converter sold outright. Requires contracts to be enabled.

Example:

lua
sellRep = {min = 1, max = 2}

#fence.recharge

Battery recharges for fences with recharge = true. item is zyke_anglegrinder's battery item, price is flat per recharge, and chargeAmount is the percent restored.

Example:

lua
recharge = {item = "anglegrinder_battery", seconds = 8, price = 100, chargeAmount = 100}

#fence.positions

Fence peds. coords includes the heading. hours limits him to real-life server hours from 0 to 24, and can run past midnight; leave it out to keep him there all day. buysConverters, contracts, and recharge toggle his services. items are sold, buyback items are bought per piece, and wornBuyback parts are bought by durability, dropping to the broken item's price at 0%.

Example:

lua
positions = {
    {
        label = "Scrap Buyer",
        model = "s_m_y_xmech_02",
        coords = vec4(2355.86, 3144.49, 48.21, 172.48),
        scenario = "WORLD_HUMAN_SMOKING",
        -- hours = {from = 20, to = 6},
        blip = {enabled = true, sprite = 527, color = 1, scale = 0.7},
        buysConverters = true,
        contracts = true,
        recharge = true,
        items = {
            {name = "catalytic_jack", price = 450},
        },
        buyback = {
            {name = "anglegrinder_disc_broken", price = 10},
        },
        wornBuyback = {
            {name = "anglegrinder_disc", broken = "anglegrinder_disc_broken"},
        },
    },
}

#Contracts

Contracts are handed out to each player separately. Reputation decides access: board offers, concurrent jobs, the daily limit, and which pool entries appear. See Fence & Contracts.

#contracts.enabled

Enables contracts and reputation.

Example:

lua
enabled = true

#contracts.offerSlots

Job slots on the board. Slots the player's level has not unlocked show as locked.

Example:

lua
offerSlots = 4

#contracts.limitHours

Hours each taken job counts toward the daily limit.

Example:

lua
limitHours = 16

#contracts.levels

Reputation levels; the highest reached wins. offers is how many slots hold a job, active how many can run at once, and daily how many can be taken within limitHours. label is a locale key.

Example:

lua
levels = {
    {rep = 0, label = "level:stranger", offers = 1, active = 1, daily = 2},
    {rep = 100, label = "level:runner", offers = 2, active = 1, daily = 3},
    {rep = 250, label = "level:regular", offers = 3, active = 2, daily = 4},
    {rep = 500, label = "level:trusted", offers = 4, active = 2, daily = 6},
    {rep = 1000, label = "level:partner", offers = 4, active = 3, daily = 8},
}

#contracts.boardMinutes

Minutes before offered jobs are replaced.

Example:

lua
boardMinutes = 45

#contracts.standards

Condition standards the fence asks for. condition is the lowest converter condition that meets it, and value multiplies the job's payout and reputation. label and brief are locale keys.

Example:

lua
standards = {
    {name = "pristine", condition = 75, value = 1.4, label = "standard:pristine", brief = "standard:pristineBrief"},
    {name = "any", condition = 20, value = 0.7, label = "standard:any", brief = "standard:anyBrief"},
}

#contracts.scoring

How a hand-in is scored against the standard. Meeting it exactly pays the job as offered. Each point over adds payout and reputation up to exceed; each point under removes them down to short, where reputation turns into a loss. Each grade worse than accepted counts as gradeStep points under. wrong applies to a converter that is not what he asked for, and excellentAt is the points over that rate as excellent.

Example:

lua
scoring = {
    exceed = {range = 25, payout = 1.3, rep = 1.5},
    short = {range = 30, payout = 0.4, rep = -1.0},
    gradeStep = 10,
    excellentAt = 15,
    wrong = {payout = 0.25, rep = -1.0},
}

#contracts.failedRep

Share of the job's reputation lost when it runs out of time or is dropped.

Example:

lua
failedRep = 0.75

#contracts.idle

Reputation decay. After graceHours since the last finished job, points are lost every everyHours until the next one.

Example:

lua
idle = {enabled = true, graceHours = 24, everyHours = 24, points = 15}

#contracts.trendDays

Days of history summed for the trend in the fence menu.

Example:

lua
trendDays = 7

#contracts.tracker

On-screen list of running jobs with their steps and time left. position is top-left, top-right, center-left, center-right, bottom-left, or bottom-right; offset is the gap to the screen edges in percent of the screen height. key is the default toggle key; "" leaves it for players to bind.

Example:

lua
tracker = {
    enabled = true,
    position = "top-left",
    offset = {x = 2.5, y = 2.5},
    key = "",
}

#contracts.target

Target jobs spawn a locked vehicle at a free location and give the player a search area radius metres wide around it.

Example:

lua
target = {
    radius = 120.0,
    locations = {
        vec4(212.0, -810.0, 30.65, 340.0),
    },
}

#contracts.pool

Jobs the fence can offer. type is spec for any converter of the listed sizes, model for one cut from a listed model, or target for the spawned vehicle. level is the lowest reputation level that offers it, weight how often it is picked, standards the standards he picks from, grade the worst accepted grade, and minutes the time to deliver. payout and rep are rolled from their ranges before the standard's value.

Example:

lua
pool = {
    {type = "spec", level = 1, weight = 10, sizes = {"small", "medium"}, standards = {"rough", "any"}, payout = {min = 450, max = 700}, rep = {min = 8, max = 12}, minutes = 90},
    {type = "target", level = 3, weight = 6, models = {"baller", "granger", "bison", "felon", "tailgater"}, standards = {"clean", "decent"}, payout = {min = 1300, max = 1800}, rep = {min = 20, max = 28}, minutes = 45},
}