Skip to content

Add setVehicleNitroColor, getVehicleNitroColor and resetVehicleNitroColor#4945

Open
TheCrazy17 wants to merge 4 commits into
multitheftauto:masterfrom
TheCrazy17:feature/vehicle-nitro-color
Open

Add setVehicleNitroColor, getVehicleNitroColor and resetVehicleNitroColor#4945
TheCrazy17 wants to merge 4 commits into
multitheftauto:masterfrom
TheCrazy17:feature/vehicle-nitro-color

Conversation

@TheCrazy17

Copy link
Copy Markdown

Summary

Adds per-vehicle nitro flame colour customization, available on both client and server and synced to all players:

bool setVehicleNitroColor ( vehicle theVehicle, int r, int g, int b [, int a = 255 ] )
int, int, int, int getVehicleNitroColor ( vehicle theVehicle )  -- returns false if no custom colour is set
bool resetVehicleNitroColor ( vehicle theVehicle )

OOP: vehicle:setNitroColor(...), vehicle:getNitroColor(), vehicle:resetNitroColor().

Video

Technical approach:

  • The "nitro" FX blueprint's colour keyframes are shared by every vehicle, so they are re-tinted just-in-time as each vehicle's particles are rendered (hook on the per-particle render info call in FxEmitterBP_c::Render). The original keyframes are cached and used as a brightness envelope, so the requested hue fully replaces the default cyan; vehicles without a custom colour keep the exact default look.
  • While a custom colour is applied, the nitro emitters switch from additive to standard alpha blending (restored on reset), so dark colours - including black - render correctly. The blend state is shared by all nitro particles in a frame, so default-coloured vehicles share it while a custom-coloured nitro is on screen.
  • Synced via a new element RPC (added at the end of the enum) and included in the vehicle entity-add data, so players who join or stream the vehicle in later see the correct colour.

Motivation

The nitro flame colour is hardcoded in the shared FX blueprint. The only workaround today is replacing the effect texture or using shaders, which affects every vehicle globally - there is no way to give each vehicle its own nitro colour. This is a frequently requested customization feature for tuning, race and DM servers.

Test plan

Tested with a resource that spawns 10 vehicles with random nitro colours (half of them also with random alpha), nitro added and activated:

-- Spawn a row of cars with random nitro colours
for i = 0, 9 do
    local veh = createVehicle(411, i * 5, 0, 4)
    addVehicleUpgrade(veh, 1010) -- nitro
    setVehicleNitroColor(veh, math.random(0, 255), math.random(0, 255), math.random(0, 255))
    setVehicleNitroActivated(veh, true)
end

-- /nitrocolor r g b [a]
addCommandHandler("nitrocolor", function(player, _, r, g, b, a)
    setVehicleNitroColor(getPedOccupiedVehicle(player), r, g, b, a)
end)

-- /nitroreset
addCommandHandler("nitroreset", function(player)
    resetVehicleNitroColor(getPedOccupiedVehicle(player))
end)
  • Each vehicle shows its own colour simultaneously, including white, pink and black (previously impossible hues).
  • resetVehicleNitroColor restores the exact default look (original keyframes and additive blending).
  • Changing the colour while the nitro is burning applies immediately.
  • A second client connecting after the colours were set sees all colours correctly (entity-add sync), as well as after streaming vehicles out and back in.
  • Restarting the resource (destroying 10 vehicles while their flames are still fading out) no longer crashes: a use-after-free found in debug builds (pure virtual call in the render hook) is fixed by unregistering the vehicle's nitro systems in the CVehicleSA destructor.
  • Vehicles without a custom colour render identically to vanilla.

Checklist

  • Your code should follow the coding guidelines.
  • Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.

Allows scripts to recolour a vehicle's nitro flames per-vehicle (client and
server side, synced via a new element RPC). The shared "nitro" FX blueprint's
colour keyframes are re-tinted just-in-time as each vehicle's particles are
rendered, using the original keyframes as a brightness envelope so any colour
(including white) fully replaces the default cyan hue. No colour set means the
original effect colours are used.
- While a custom colour is applied, the nitro emitters switch from additive
  to standard alpha blending (restored on reset), so the requested colour
  renders exactly - dark colours and black included - instead of fading out
  as the additive contribution approaches zero.
- setVehicleNitroColor now accepts an optional alpha (r, g, b [, a = 255])
  that scales the effect's alpha keyframes, preserving the flame's fade
  animation; getVehicleNitroColor returns r, g, b, a.
- The nitro colour is now included in the vehicle's entity-add data, so
  players who join (or stream the vehicle in) after the colour was set see
  it correctly instead of the default colours.
A vehicle's nitro FX systems are destroyed deferred by the game (they fade
out first), so destroying a vehicle left its entries in the nitro system map
pointing at a deleted CVehicleSA, and the render hook then called a virtual
function on it (pure virtual call -> 0xC0000409). Unregister the vehicle's
nitro systems in the CVehicleSA destructor, so entries are removed when
either side is destroyed first.
Comment thread Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp Outdated
Comment thread Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp Outdated
Comment thread Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp Outdated
Comment thread Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp Outdated
@Xenius97

Copy link
Copy Markdown
Contributor

By the way, it looks good, but for the new features, the ArgumentParser should be used.
See here: https://github.com/multitheftauto/mtasa-docs/blob/main/mtasa-blue/CODING_GUIDELINES.md#argument-parser

Converts setVehicleNitroColor, getVehicleNitroColor and
resetVehicleNitroColor on both client and server from the legacy
CScriptArgReader pattern to the new ArgumentParser, as requested
in review.
@TheCrazy17

Copy link
Copy Markdown
Author

By the way, it looks good, but for the new features, the ArgumentParser should be used. See here: https://github.com/multitheftauto/mtasa-docs/blob/main/mtasa-blue/CODING_GUIDELINES.md#argument-parser

Thanks for pointing that out! All three functions now use ArgumentParser (client + server), done in 6b704a7. Good to know for future PRs!

@TheCrazy17 TheCrazy17 requested a review from Xenius97 June 11, 2026 18:40
@Xenius97

Copy link
Copy Markdown
Contributor

It looks good to me, but I’m not going to accept it yet, let’s wait for the experts. Nice work! 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants