you define the fields in order as a list in init-specs with the field name being prepended with a : to form a key name. The format is therefore (:<field> <params, inlined...>) e.g. (:x (meters -0.09) (meters 0.18)) defines the x field with params (meters -0.09) and (meters 0.18). Each spec defines how the value for that field will be initialized. It can be for example a random number or a specific sound. The value MUST be valid at compile-time, so you cannot for example call GOAL functions or have branches here.
fields MUST be defined in ascending order according to the sp-field-id enum. The compiler will throw an error if you break this rule, so you don't have to worry about compiling bad code due to this.
you can have a field have the same value as a previously-defined field by specifying :copy <field-name to copy from> as the params. This is useful when you want to randomize, for example, the scale of a particle uniformly - you generate one random value for scalex then copy the result to scaley and scalez. If you just had the same params for all three fields, each would end up with a different random value. copy command example: (:scale-y :copy scale-x). You must NOT provide more than these two params or it won't work!
Copying only works for fields that have already been defined previously. If you break this rule, the compiler will print a non-fatal warning to the compiler and your particle might not work correctly in-game (the value it ends up copying tends to be zero).
There are plenty of fields that are never set in the original games, so we do not know how or if they work! There are also fields that are specifically forbidden, and you will get an error trying to define them.
There are additional specific rules as to what type of parameters can be used:
the texture field MUST take a single texture-id.
the flags field MUST take a single list of flags from the sp-cpuinfo-flag enum.
the next-launcher field MUST take a single particle ID.
the sound field MUST take a single static-sound-spec.
any of the following combinations of parameters are also valid (though they may not work outside their intended context, for example specifying a number in the func field):
1 param: symbol - the field's value will be the symbol provided.
1 param: float - the field's value will be the float provided.
2 params: float float - the field's value will be any random float between param-1 and (+ param-1 param-2) exclusive.
3 params: float float float - the field's value will be any random float between param-1 and (+ param-1 (* param-2 param-3)) exclusive.
3 params: float int float - the field's value will be a float between param-1 and (+ param-1 (* param-2 param-3))inclusive, with param-2 being a random integer. What this means is that (:r 64.0 2 32.0) will set r to one of 3 values: 64.0 ((+ 64.0 (* 0 32.0))), 96.0 ((+ 64.0 (* 1 32.0))) or 128.0 ((+ 64.0 (* 2 32.0))). This is used for when you want to randomize the value of a field in discreet "steps."
1 param: int - the field's value will be the int provided.
2 params: int int - the field's value will be any random int between param-1 and (+ param-1 param-2) exclusive.
3 params: int int int - the field's value will be any random int between param-1 and (+ param-1 (* param-2 param-3)) exclusive.
IMPORTANT NOTE: (seconds <value>) is valid and parsed as int. (degrees <value>) and (meters <value>) are valid and parsed as floats.
used similarly to the :copy command, you can instead use the :data command to specify any arbitrary object to be placed in the field (see source code for examples). This is used for weird texture animations and is very TBD. Avoid using this for your custom particles for now!!
breaking these rules may cause the compiler to emit an "end" command (also inserted automatically at the end of the list) which will cause the particle engine to cease setting fields past that point.
The basic gist is:
init-specs
with the field name being prepended with a : to form a key name. The format is therefore(:<field> <params, inlined...>)
e.g.(:x (meters -0.09) (meters 0.18))
defines thex
field with params(meters -0.09)
and(meters 0.18)
. Each spec defines how the value for that field will be initialized. It can be for example a random number or a specific sound. The value MUST be valid at compile-time, so you cannot for example call GOAL functions or have branches here.sp-field-id
enum. The compiler will throw an error if you break this rule, so you don't have to worry about compiling bad code due to this.:copy <field-name to copy from>
as the params. This is useful when you want to randomize, for example, the scale of a particle uniformly - you generate one random value forscalex
then copy the result toscaley
andscalez
. If you just had the same params for all three fields, each would end up with a different random value. copy command example:(:scale-y :copy scale-x)
. You must NOT provide more than these two params or it won't work!texture
field MUST take a singletexture-id
.flags
field MUST take a single list of flags from thesp-cpuinfo-flag
enum.next-launcher
field MUST take a single particle ID.sound
field MUST take a singlestatic-sound-spec
.func
field):symbol
- the field's value will be the symbol provided.float
- the field's value will be the float provided.float float
- the field's value will be any random float betweenparam-1
and(+ param-1 param-2)
exclusive.float float float
- the field's value will be any random float betweenparam-1
and(+ param-1 (* param-2 param-3))
exclusive.float int float
- the field's value will be a float betweenparam-1
and(+ param-1 (* param-2 param-3))
inclusive, withparam-2
being a random integer. What this means is that(:r 64.0 2 32.0)
will setr
to one of 3 values:64.0
((+ 64.0 (* 0 32.0))
),96.0
((+ 64.0 (* 1 32.0))
) or128.0
((+ 64.0 (* 2 32.0))
). This is used for when you want to randomize the value of a field in discreet "steps."int
- the field's value will be the int provided.int int
- the field's value will be any random int betweenparam-1
and(+ param-1 param-2)
exclusive.int int int
- the field's value will be any random int betweenparam-1
and(+ param-1 (* param-2 param-3))
exclusive.(seconds <value>)
is valid and parsed asint
.(degrees <value>)
and(meters <value>)
are valid and parsed asfloat
s.:copy
command, you can instead use the:data
command to specify any arbitraryobject
to be placed in the field (see source code for examples). This is used for weird texture animations and is very TBD. Avoid using this for your custom particles for now!!