📊
Alchemy (.ale)

💥 Table of contents

🔥 Overview

Alchemy is a particle effects system in Freelancer rendering. Almost all visual effects are made in this system, like weapon projectiles, explosions, engine exhausts and many more.

stateDiagram-v2
    direction LR

    ALEffectLibData: ALEffectLib
    AlchemyNodeLibraryData: AlchemyNodeLibrary

    [*] --> ALEffectLib
    ALEffectLib --> ALEffectLibData
    [*] --> AlchemyNodeLibrary
    AlchemyNodeLibrary --> AlchemyNodeLibraryData

Alchemy data is presented by two entries in UTF:

  • ALEffectLib for effect library.
  • AlchemyNodeLibrary for node library.

Both entries appear in .ale files inside folder entries of same names.

Strings in ALE structures (astring) are NUL-terminated and prefixed by character count as uint16. Number of characters is always even regardless of actual string length: there will always be one or two NUL bytes at the end of string.

💨 Alchemy Effect Library

Effect library contains effect entries which are referenced in effect .ini files via effect_crc property of [VisEffect] section.

Name Type Description
version float Version (1.0 or 1.1).
effectCount uint32 Effects count.
effects varying

🔥 Effect

A single effect is comprised of hierarchy of node instances which reference node archetypes in Alchemy node library. These nodes typically fall into three categories: emitters, appearances and fields.

Emitters generate particles (points in space with direction and velocity), appearances visualize particles to be rendered with certain shapes, colors and textures, and fields can affect particles physically like applying gravity force to accelerate particles.

Name Type Description
name astring Effect name (ex.: "gf_jumpgate_rings").
unused float[4] Unused floats.
instanceCount uint32 Node instances count.
nodeInstances varying Node instances.
pairCount uint32 Node pair count.
nodePairs varying Node pairs.
  • Unused floats appear only when version is 1.1f.

Each node instance is:

Name Type Description
flags uint32 1 for attachment node, 0 for instance node.
name uint32 Node's Node_Name value FLCRC32 (case-sensitive).
parentId int32 Node instance parent id (32768 for none).
refId int32 Node instance id.
  • CRC pointing to a node in node library CRC of "Node_Name" parameter.
  • Node instance indices start with 1.
  • Order of node instances in effect is used for draw order.

Each node pair is:

Name Type Description
sourceId int32 Pair source node instance (emitter/appearance).
targetId int32 Pair target node instance (appearance/field).

📌 Alchemy Node Library

Node library is a collection of node archetypes. Nodes have type property describing its behavior and list of properties, some of which are fixed values and some are animated.

Name Type Description
version float32 Version (1.0 or 1.1).
nodeCount uint32 Node count.
nodes varying Node archetype.

Individual node archetype contains:

Name Type Description
name astring Node type (ex.: "FxBasicAppearance").
properties varying Node properties.
  • Read node properties until property type is 0.

Each property:

Name Type Description
type uint16 Property value type.
name uint32 FLCRC32 of property name (case-sensitive).
data varying Property data based on type.

Type is:

Value Name Animated
0x001 Boolean No
0x002 Integer No
0x003 Float No
0x103 String No
0x104 Blending No
0x105 Transform Yes
0x200 Float Yes
0x201 Color Yes
0x202 Curve Yes

💥 Boolean (0x1 or 0x8001)

  • Contains no data, true/false is determined by most significant bit, i.e. 0x1 is false and 0x8001 is true.

📎 Integer (0x2)

Name Type Description
value int32 Signed integer number value.

🔭 Float (0x3)

Name Type Description
value float Float point number value.

💥 String (0x103)

Name Type Description
value astring String value.

💢 Color blending (0x104)

Name Type Description
source uint32 Blending source mode.
target uint32 Blending target mode (destination).

Possible values for source and target are:

Value Name Factor
1 D3DBLEND_ZERO 0, 0, 0, 0
2 D3DBLEND_ONE 1, 1, 1, 1
3 D3DBLEND_SRCCOLOR Rs, Gs, Bs, As
4 D3DBLEND_INVSRCCOLOR 1 - Rs, 1 - Gs, 1 - Bs, 1 - As
5 D3DBLEND_SRCALPHA As, As, As, As
6 D3DBLEND_INVSRCALPHA 1 - As, 1 - As, 1 - As, 1 - As
7 D3DBLEND_DESTALPHA Ad, Ad, Ad, Ad
8 D3DBLEND_INVDESTALPHA 1 - Ad, 1 - Ad, 1 - Ad, 1 - Ad
9 D3DBLEND_DESTCOLOR Rd, Gd, Bd, Ad
10 D3DBLEND_INVDESTCOLOR 1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad
11 D3DBLEND_SRCALPHASAT f, f, f, 1 (f = min(As, 1 - Ad))

📌 Transform (0x105)

Name Type Description
flags uint32
translate curve[3] Translation animation.
rotate curve[3] Rotation animation.
scale curve[3] Scale animation.
  • Curve type is animated curve structure.
  • If most significant byte in flags is 0 skip translate/rotate/scale altogether.

🔥 Animated float (0x200)

Name Type Description
easing uint8 Blending value easing type.
keyframeCount uint8 Blending keyframe count (1 or more).
keyframes varying Blending keyframes.

Each blending parameter keyframe:

Name Type Description
key float Parameter key.
easing uint8 Value easing type.
keyframeCount uint8 Value keyframe count (1 or more).
keyframes varying Value keyframes.

Each value keyframe:

Name Type Description
key float Keyframe key.
value float Keyframe number value.
  • Typically animated float key is relative (0.0 to 1.0).

🔭 Animated color (0x201)

Name Type Description
easing uint8 Blending value easing type.
keyframeCount uint8 Blending keyframe count (1 or more).
keyframes varying Blending keyframes.

Each blending parameter keyframe:

Name Type Description
key float Parameter key.
easing uint8 Value easing type.
keyframeCount uint8 Value keyframe count (1 or more).
keyframes varying Value keyframes.

Each value keyframe:

Name Type Description
key float Keyframe key.
value float[3] Keyframe color value (RGB).
  • Typically animated color key is relative (0.0 to 1.0).

🔭 Animated curve (0x202)

Name Type Description
easing uint8 Blending value easing type.
keyframeCount uint8 Blending keyframe count (1 or more).
keyframes varying

Each blending parameter keyframe:

Name Type Description
key float Parameter key.
defaultValue float Default value.
wrapFlags uint16 Wrapping flags for out of bounds keys.
keyframeCount uint16 Keyframe count (0 or more).
keyframes varying Value keyframes.

Each value keyframe:

Name Type Description
key float Keyframe key.
value float Keyframe value.
valueOut float Keyframe outgoing value.
valueIn float Keyframe incoming value.
  • Typically animated curve key is time (seconds).

💢 Easing types

Value Description
1 Linear.
2 Ease in.
3 Ease out.
4 Ease both.
5 Step.

📌 Wrap flags

Determine what happens for out of bounds values.

Value Description
0x0001 Repeat before.
0x0002 Mirror before.
0x0004 Clamp before.
0x0010 Repeat after.
0x0020 Mirror after.
0x0040 Clamp after.

💥 Evaluating animated curve value

/**
 * Evaluate curve value between keyframes.
 * @param w Transition state between keyframes
 * @param a Start keyframe value
 * @param b End keyframe value
 * @param d Delta between start and end keyframe keys
 * @returns
 */
mixCurve(w: number, a: Vector3, b: Vector3, d: number) {
    const { x: ax, z: av } = a;
    const { x: bx, y: bv } = b;

    d *= .5;

    const a0 = ax + av * d;
    const b0 = bx - bv * d;

    const a1 = lerp(w, ax, a0);
    const b1 = lerp(w, a0, bx);

    const a2 = lerp(w, ax, b0);
    const b2 = lerp(w, b0, bx);

    const a3 = lerp(w, a1, a2);
    const b3 = lerp(w, b1, b2);

    return lerp(w, a3, b3);
}
  • lerp is a generic linear interpolation function.