Particle Script
This file format is almost completely documented Details are subject to corrections |
Retro games feature a uniform, fixed-function Effect Script system for describing various geometrical effects and weapon systems. The PAK archives contain binary resources using FourCCs to build a key-value dictionary. These codes correspond to application-specific parameters controlling the effect system in question.
The binary script format uses a grammar that supports bool
, int
, float
, float3
, and float4
parameters to be evaluated and assigned to the dictionary. In addition, the various effect systems provide dynamic node classes that are evaluated as part of the effect runtime.
Ultimately, the systems use a recursive, node-based approach of generating animated scalar and vector values to control the effect.
File Layout
All effect script file formats use a context-sensitive, free-form layout to build the key-value dictionary.
- Script Magic FourCC (see table below)
- Entries
- Key FourCC (see script-format articles)
- Value Parameter(s) (one of:)
-
CNST
: Scalar/Vector literal- 1-4 int/float values
-
NONE
: Dummy value (equivalent to not specifying the key at all) - Node Key (see below)
- Node Parameters
-
-
_END
Script Types
Type | Magic | Purpose |
---|---|---|
PART | GPSM
|
Particle effect |
SWHC | SWSH
|
Swoosh effect |
ELSC | ELSM
|
Electric effect |
DPSC | DPSM
|
Decal effect |
WPSC | WPSM
|
Projectile weapon configuration |
CRSC | CRSM
|
Projectile collision response configuration |
Script Nodes
Many of the animated qualities from effect scripts are achieved with dynamic script nodes. These nodes provide parameter I/O interfaces and internally process numeric data that passes through. They may also gather data from other sources within the effect system.
Scope is one of (Constant, System, Particle, Auto)
- Constant parameters are evaluated once initially and retained within the system.
- System parameters are evaluated per-system, per-frame.
- Particle parameters are evaluated per-system, per-frame, per-particle-instance.
- Auto parameters select their scope based on the node's parent context.
Signature | Scope | Description | Notes |
---|---|---|---|
SETR(ILOC=float3 location_vector, IVEC=float3 velocity_vector)
|
System | Point emitter | Used with EMTR attachment to produce particle instances
|
SEMR(float3 location_vector, float3 velocity_vector)
|
System | Point emitter | Seems to be similar to SETR
|
SPHE(float3 local_sphere_origin, float radius, float radial_velocity)
|
System | Sphere emitter | Emits particles from a sphere-surface |
ASPH(float3 local_sphere_origin, float x_ang_bias, float y_ang_bias, float x_ang_range, float y_ang_range, float radius, float radial_velocity)
|
System | Partial sphere emitter | Emits particles from a sphere-surface section |
float SCAL(float value)
|
Particle | Linear-lifetime interpolator | Interpolates from 0.0 to value over particle's lifetime
|
int/float/float3/float4 ADD(int/float/float3/float4 a, int/float/float3/float4 b)
|
Auto | Value adder | Dynamically adds two parameters |
int/float/float3/float4 SUB(int/float/float3/float4 a, int/float/float3/float4 b)
|
Auto | Value subtractor | Dynamically subtracts two parameters |
int/float/float3/float4 MULT(int/float/float3/float4 a, int/float/float3/float4 b)
|
Auto | Value multiplier | Dynamically multiplies two parameters |
float CLMP(float low, float high, float val)
|
Auto | Value clamp | Dynamically clamps val between low and high
|
int RLPT(float lifetime_percent)
|
Particle | Resolve frame-index from lifetime percentage | Computes the frame on which the particle will reach a specified lifetime-percent (0-100) |
float ISWT(float c, float v)
|
Auto | Linear equation evaluator | Evaluates v * frame_index + c
|
int/float RAND(int/float low, int/float high)
|
System | Pseudo-random number generator | Generates a random number between low and high
|
int/float IRND(int/float low, int/float high)
|
Particle | Instance-cached pseudo-random number generator | Generates a random number between low and high and retains the value for each particle instance
|
float LFTW(float a, float b)
|
Particle | Triangle-wave generator | Generates a triangle-wave cycle over the particle instance's lifetime. Evaluates a at 0% lifetime, b at 50% lifetime, then back to a at 100% lifetime
|
int/float/float3/float4 CHAN(int/float/float3/float4 a, int/float/float3/float4 b, int f)
|
Particle | Time-based parameter switch | Evaluates a before particle instance reaches frame index f ; evaluates b afterwards
|
float3 RTOV(float val)
|
Auto | Scalar to vector (vector splat) | Constructs a 3-component vector using val for each component
|
int/float/float3/float4 PULS(int pulse_start_frame, int pulse_frame_count, int/float/float3/float4 a, int/float/float3/float4 b)
|
Particle | Pulsing duty-cycle switch (periodic CHAN )
|
Evaluates a until pulse_start_frame is reached, then evaluates b for pulse_frame_count frames. This cycle repeats indefinitely
|
float SINE(float magnitude, float v, float c)
|
Auto | Animated sine function | v and c are in degrees. Evaluates sin(v * frame_index + c) * magnitude
|
int/float/float3/float4 KEYE(<key-array>)
|
System | Emitter-based key array | Stores an array of values; one for each frame of the emitter's lifetime; with clamped-extrapolation |
int/float/float3/float4 KEYP(<key-array>)
|
Particle | Particle-based key array | Stores an array of 100 values; one for each percentage point of the particle instance's lifetime |
float PAPn()
|
Auto | ADVn access token (1-8)
|
Access the value evaluated for one of the ADVn keys in the particle system
|
float PSLL()
|
– | – | – |
float PRLW()
|
– | – | – |
float PSOF()
|
– | – | – |
float VMAG(float3 v)
|
Auto | Vector magnitude calculator | Evaluates sqrt(v.x^2 + v.y^2, v.z^2)
|
float CLTN(float ca, float cb, float a, float b)
|
Auto | Less-than evaluator switch | If ca < cb then evaluates a , else b
|
float CEQL(float ca, float cb, float a, float b)
|
Auto | Equal evaluator switch | If ca == cb then evaluates a , else b
|
float VXTR(float3 vec)
|
Auto | X component of vector | Extracts X component of vector |
float VYTR(float3 vec)
|
Auto | Y component of vector | Extracts Y component of vector |
float VZTR(float3 vec)
|
Auto | Z component of vector | Extracts Z component of vector |
float CEXT(int val)
|
– | – | – |
float ITRL(float val)
|
– | – | – |
float GTCP(int val)
|
– | – | – |
float MODU(float numerator, float denominator)
|
Auto | Floating-point modulo | Dynamically evaluates remainder-division as numerator % denominator
|
int ILPT(int val)
|
Particle | Clamp to particle frame-count | Clamps val to count of frames in particle instance
|
float4 FADE(float4 a, float4 b, float t)
|
Particle | Time-based (0-end) linear interpolator | Interpolates from a to b over particle instance's first t frames
|
float4 CFDE(float4 a, float4 b, float s, float e)
|
Particle | Time-based (start-end) linear interpolator | Interpolates from a to b between particle instance's s and e frames
|
float3 ANGC(float x_bias, float z_bias, float x_ang, float z_ang, float magnitude)
|
Auto | Spherical-section random vector generator | Generates a vector of magnitude adhering to the XZ-angular constraints provided
|
float3 CIRC(float3 circle_offset, float3 circle_normal, float angle_bias, float angle_range, float magnitude)
|
Auto | Circular-section random vector generator | Generates a vector of magnitude adhering to the circular constraints provided
|
float3 CONE(float3 cone_vector, float base_radius)
|
Auto | Cone random vector generator | Generates a random vector from the cone's tip to somewhere within its base |
WIND(float3 wind_vector, float drift_magnitude)
|
Particle | Wind velocity source | Integrates a non-accelerated force simulating directional wind with a randomized drift |
GRAV(float3 grav_vector)
|
Particle | Gravity velocity source | Integrates a continuously-accelerated force simulating gravitational pull |
SWRL(float3 helix_start, float3 helix_end, float angular_vel, float linear_vel)
|
Particle | Swirl velocity source | Integrates a helically-shaped force simulating a 'swirling' motion |
BNCE(float3 plane_point, float3 plane_normal, float ?, float ?, bool ?)
|
Particle | Bounce velocity source | Establishes a local plane in the system for particles to bounce off |
EXPL(float initial_velocity, float velocity_damping)
|
Particle | Explosion velocity source | Moves particle away from emitted position at initial_velocity while continuously applying velocity_damping
|
IMPL(float3 implosion_point, float force, float ?, float ?, bool ?)
|
Particle | Implosion velocity source? | – |
EMPL(float3 point, float force, float ?, float ?, bool ?)
|
Particle | – | – |
LMPL(float3 point, float force, float ?, float ?, bool ?)
|
Particle | – | – |
float3 SPOS(float3 vec)
|
Particle | Position delta | Subtract from current particle instance position |
float3 PLCO()
|
Particle | World Position | Evaluate particle world position |
float3 PLOC()
|
Particle | Local Position | Evaluate particle local (emitter-space) position |
ATEX(int seg_w, int seg_h, int ?, int ?, int frame_rate, bool loop)
|
Particle | Animated texture attachment | Used in particle script's TEXR key to apply a UV-scanned animated texture
|