.frc force-feedback effects

The force-feedback effects in the game's Forces folder, as the SideWinder Force Feedback SDK's force editor saved them. The game reads them through the SDK's Visual Force Effects server (vfx.dll, CLSID_VFX), which turns each into DirectInput effects. The game reads 13 of the files and never the rest (Controls).

Layout

A RIFF file of form FORC:

Chunk Contents
LIST INFO INAM, ICMT, ISFT and ICOP, each a single NUL in the shipped files
trgt The GUID of the device the effects were made for, {04ACE095-1FA8-11D0-AA22-00A0C911F471} in every shipped file
LIST trak A LIST efct for each effect

Each efct holds an id chunk, the effect's number, which a group names it by, and a data chunk, its record. A pause also has an impl chunk of one word, 1. Unknown: its meaning.

The record

Every record starts with 104 bytes:

Offset Size Field
0x00 4 104, the size of these fields
0x04 64 The effect's name, such as Sine1, NUL-terminated; the editor left the rest of the buffer as it found it
0x44 4 Kind: 1 a pause, 2 a waveform, 3 a group
0x48 4 Type: a waveform's shape, a group's order, 10 for a pause
0x4C 4 3 in every shipped file: both axes
0x50 4 Direction, in degrees
0x54 4 0 in every shipped file. Unknown
0x58 4 Duration, in milliseconds. A group's is 1000 whatever its members'
0x5C 4 Gain, in percent
0x60 4 100 in every shipped file. Unknown
0x64 4 0, or 1 in a few groups and effects. Unknown

The envelope follows, 32 bytes:

Offset Size Field
0x00 4 32, the envelope's size
0x04 4 0 in every shipped file. Unknown
0x08 4 Attack, in percent of the duration
0x0C 4 Sustain, in percent
0x10 4 Decay, in percent
0x14 4 The level at the start of the attack, in percent
0x18 4 The level at the end of the decay
0x1C 4 The level held between them

A waveform's 20 bytes follow:

Offset Size Field
0x00 4 20
0x04 4 Frequency, in cycles a second
0x08 4 100, or 0 for a constant force. Unknown
0x0C 4 The highest force, in percent, signed
0x10 4 The lowest force

A group's 12 bytes follow, then the ids of its members, a word each:

Offset Size Field
0x00 4 12
0x04 4 How many members
0x08 4 Where the editor held the ids in memory as it saved the file

A pause has nothing after its envelope.

Types

Type Effect
101 Constant force, at the highest force
102, 103 Sine, cosine
104, 105 Square wave, starting at the lowest force and at the highest
106, 107 Ramp up and down, once over the whole effect
108, 109 Triangle wave, rising first and falling first
110, 111 Sawtooth wave, rising and falling
202 Sequence: the members one after the other
203 Superimposition: the members all at once

Every file holds one effect, or a group with its members. The shipped files use 101 to 110.

OpenReliant

src/formats/frc.zig reads a file into its effects, walking its chunks with riff.zig, which reads the game's WAVE sounds as well. input/force.zig plays them as rumble.

Edit this page on GitHub. The documentation is under CC BY-SA 4.0.