CityRP Documentation Repository

Vehicle Params & Script Editor

Last updated

Runtime helpers for reading and writing Source vehicle physics (VehicleParams), plus a developer in-game editor for iterating on vehicle scripts. This is also the foundation future vehicle-modification plugins should build on (item-meta upgrades such as springs, turbo, engine kits, etc.).

Why this exists

CityRP cars get their handling from Valve KeyValues scripts under scripts/vehicles/**/*.txt, applied with SetKeyValue("vehiclescript", ...) before Spawn/Activate. Editing those files and restarting is slow when overhauling content.

GMod exposes Vehicle:GetVehicleParams / Vehicle:SetVehicleParams for live tuning after spawn. Those APIs are the right place for:

  1. A build/dev editor that applies changes immediately and exports a .txt script body
  2. Item-meta modifiers that stack on top of the script baseline at spawn time

Core library

Shared library: core/libraries/sh_vehicleparams.lua → cityrp.vehicleparams

API Purpose
IsTunableVehicle(ent) prop_vehicle_jeep guard
GetEditableParams(veh) GetVehicleParams with speed fields converted to MPH
SetEditableParams(veh, params) Converts those MPH speeds back to HU/s, then SetVehicleParams
CaptureBaseline(veh) / RestoreBaseline(veh) Snapshot / restore script defaults on the entity
RegisterModifier(id, apply, priority?) Register a named runtime modifier
ResolveModifiers(entries) Turn {id, data} requests into an ordered apply list
ApplyModifiers(veh, modifiers, context?) Re-apply from baseline + modifier list
CollectModifiersFromMeta(item, meta, veh?) Built-in meta → entries, plus collect hook
ApplyFromItemMeta(veh, item, meta) Spawn-time entry point
SerializeKeyValues(params, header?) Export a "Vehicle" KeyValues block for scripts
BuildEditorSections(params) / ApplyEditorValues(...) Schema-driven editor helpers

MPH vs HU/s

GetVehicleParams returns engine.maxSpeed / maxRevSpeed / boostMaxSpeed in hammer units per second. Since 2021, SetVehicleParams uses the same units (HU/s), not miles per hour — the older wiki note that Set expects MPH is stale, and passing MPH numbers back in makes a car crawl and bounce. Vehicle .txt scripts still store those fields in MPH.

The library always works in MPH on the editable side (GetEditableParams / modifiers / editor / export). SetEditableParams converts back to HU/s before writing. Conversion factor: 17.6 HU/s per MPH.

Spawn integration

Vehicles plugin SpawnVehicle captures a baseline immediately after Activate, then calls ApplyFromItemMeta. Re-applying modifiers always starts from that baseline so stacking stays deterministic.

In-game editor

Plugin: core/plugins/vehiclescript_editor/

Command !vehiclescript
Access Developer only (/ flag / IsDeveloperOnly)
Target Vehicle you are sitting in, otherwise the jeep under your crosshair

Actions:

  • Apply — write the form values to the live entity via SetVehicleParams
  • Reset — restore the captured script baseline
  • Export — serialize a "Vehicle" KeyValues block to data/cityrp/vehicle_scripts/<name>.txt and copy it to the clipboard

Sounds ("Vehicle_Sounds") are not edited here; paste the exported "Vehicle" block into the existing script file and keep the sounds section as-is.

Item-meta modifiers (foundation)

base_vehicle already declares springs and turbo. Those fields are no longer display-only: spawn applies them through the modifier registry.

Meta field Modifier id Effect (intentionally mild)
springs (−10…10) springs Scales axle spring constant / max body force (~±50% at extremes)
turbo (bool) turbo Enables torque boost and raises boost force / duration / max speed

Adding a future upgrade

cityrp.vehicleparams.RegisterModifier("engine_upgrade", function(params, context)
	local tier = tonumber(context.data) or 1
	params.engine.horsepower = (params.engine.horsepower or 0) * (1 + 0.1 * tier)
	params.engine.maxSpeed = (params.engine.maxSpeed or 0) * (1 + 0.05 * tier)
end, 70)

hook.Add("CityRP.VehicleParams.CollectModifiers", "my_vehicle_mods", function(entries, item, meta, veh)
	local tier = cityrp.itemmeta.GetField(item, meta, "engine_upgrade")
	if tier then
		table.insert(entries, {id = "engine_upgrade", data = tier})
	end
end)

Prefer a dedicated plugin for player-facing upgrade shops/items. Keep the apply math in RegisterModifier so the editor, spawn path, and future systems share one code path.

Collect hook

CityRP.VehicleParams.CollectModifiers(entries, item, meta, veh) — append {id=..., data=...} tables to entries. Unknown ids are skipped with a debug log line.

Testing

On the build/dev server as a developer:

  1. Spawn a car, look at it, run !vehiclescript
  2. Raise HorsePower / MaxSpeed, Apply, drive
  3. Reset, confirm script feel returns
  4. Export, confirm clipboard + data/cityrp/vehicle_scripts/
  5. /giveitem <you> <car> 1 meta:springs=5;turbo=1 — spawn and confirm stiffer suspension / boost