A static utility that spawns a one-shot coloured particle tracer between two points using a cloned tracer prefab. It clones the BulletTracers.TracerScene, positions/rotates it from origin to target, sets particle effect tint/gradient and trail renderer color while disabled, then enables the clone and returns the GameObject. It also exposes a console command to toggle tracers globally.
using Sandbox;
using System;
namespace NZombies;
/// <summary>
/// A one-shot coloured tracer between two points, cloned from the bullet tracer prefab.
///
/// ⛔ EXTRACTED FROM `Fireworks`, WHICH AUTHORED IT FIRST, THE MOMENT A SECOND MOD WANTED IT.
/// Dead Wire's arcs are the same thing in a different colour, and the two facts this needs to know
/// about `tracer.prefab` are both non-obvious enough that a copy would drift:
///
/// • `Tint` MULTIPLIES the effect's gradient, which ramps white → yellow → orange. Tinting alone
/// turns a blue request into muddy green. The gradient has to be REPLACED.
/// • `ParticleTrailRenderer` carries its OWN colour, on its own component. Set only the effect
/// and you get a yellow trail behind a coloured head, which reads as a bug.
///
/// One author for both, per INSTRUCTIONS.md §3.
///
/// ⚠️ THIS IS THE PROJECT'S ONLY LINE-BETWEEN-TWO-POINTS PRIMITIVE, and it is a particle rather
/// than a beam because that is what exists. Upstream draws Dead Wire's arc with
/// `util.ParticleTracerEx( "bo3_waffe_jump", from, to )` — also a tracer particle between two
/// positions — so this is the faithful mechanism, not a substitute for a missing one.
/// </summary>
public static class ColourTracer
{
static bool? _enabled;
/// <summary>
/// Draw tracers at all. On.
///
/// ⚠️ ONE SWITCH FOR EVERY CALLER, so "the tracers look wrong" can be separated from "the
/// effect is wrong" in a single command, for whichever mod is being looked at.
/// </summary>
public static bool Enabled { get => _enabled ?? true; set => _enabled = value; }
/// <summary>
/// Draw one tracer from `from` to `to`, coloured.
///
/// ⚠️ THE COLOUR IS WRITTEN WHILE THE CLONE IS DISABLED, then the object is enabled. A particle
/// effect that starts enabled has already emitted its first particles by the time the colour
/// lands, so the head of every tracer would flash the prefab's yellow before turning. Same
/// clone-disabled-then-configure order `BlastEffect` uses, and for the same class of reason.
///
/// ⚠️ IT RETURNS THE OBJECT so a caller that wants to follow the arc can, but nothing does yet
/// and nothing has to — the clone carries `TemporaryEffect`, which cleans it up.
/// </summary>
public static GameObject Draw( Vector3 from, Vector3 to, Color colour, string name = "nz_tracer" )
{
if ( !Enabled ) return null;
var prefab = BulletTracers.TracerScene;
if ( prefab is null ) return null;
var dir = to - from;
if ( dir.IsNearlyZero() ) return null;
var go = prefab.Clone( new CloneConfig
{
Transform = new Transform( from, Rotation.LookAt( dir.Normal ) ),
StartEnabled = false,
Name = name,
} );
foreach ( var fx in go.Components
.GetAll<ParticleEffect>( FindMode.EverythingInSelfAndDescendants ) )
{
fx.Tint = colour;
fx.Gradient = colour;
}
foreach ( var tr in go.Components
.GetAll<ParticleTrailRenderer>( FindMode.EverythingInSelfAndDescendants ) )
tr.Color = colour;
go.Enabled = true;
return go;
}
/// <summary>`nz_tracer_fx [0|1]` — read or toggle every coloured tracer at once.</summary>
[ConCmd( "nz_tracer_fx" )]
public static void Cmd( int state = -1 )
{
if ( state >= 0 ) Enabled = state > 0;
Log.Info( $"[nz-fx] coloured tracers {(Enabled ? "ON" : "OFF")}"
+ $" · prefab {(BulletTracers.TracerScene is null ? "MISSING" : "loaded")}" );
}
}