Microsoft Word Microsoft Word - Space Cadet Pinball
Minimize Maximize Close
New Open Save
Print (No Printer) Print Preview Spelling and Grammar
Cut Copy Paste Format Painter
Undo Undo
Redo Redo
Insert Hyperlink Web Toolbar
Tables and Borders Insert Microsoft Excel Worksheet Columns Drawing
Document Map Show/Hide ¶
100%
Office Assistant
Normal
Times New Roman
10
Bold Italic Underline
Align Left Center Align Right Justify
Numbering Bullets Decrease Indent Increase Indent
Outside Border Outside Border
Highlight (Yellow) Highlight (Yellow)
Font Color (Red) Font Color (Red)
First Line Indent Hanging Indent Left Indent
Right Indent Right Indent Right Indent

Space Cadet Pinball

How Was a Built-In Game So Much Fun?

Space Cadet Pinball logo

3D Pinball for Windows - Space Cadet (better known as Space Cadet Pinball) is one of the most well-known games from the Windows XP era.

This game was developed by Cinematronics for Windows 95 (and later included in Windows XP). Another game called Full Tilt! Pinball was also developed afterwards, which features Space Cadet as one of the three tables.

This page will only be focusing on the version of Space Cadet Pinball included with Windows XP.


If you've found any errors in the documentation or want to suggest any changes or additions, please contact 겑衐诠芜蟭莼볿骵薖详鳔誷齛꒦諶鳓芗.

Table of Contents

Cheats

Prior to launching the ball out of the deployment chute, players can input any of the codes below to gain their associated effects.

CodeEffect
HIDDEN TESTEnable cheat mode
GMAXActivate the gravity well
RMAXIncrease rank
1MAXGain an extra ball
BMAXNever lose a ball

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
BSpawn an extra ball if the ball isn't on the table
HShow the high score dialog and set a new high score
MShow memory usage
RIncrease rank
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

If both Y and H are pressed when in cheat mode, it will trigger a "graphics render history" mode, which draws using a red palette for any changed areas of the screen.

Additionally, there are 2 other codes that are programmed into the game, but their effects and activations have been dummied out of the final game.

These codes are CINEMATRONICS. and QUOTES.. However, these codes are used in pre-release version of the game.

The following pages discuss the various cheats found within the pre-release versions of Space Cadet Pinball.

April 26th, 1995

Below are the codes used in the April 26th build of Space Cadet Pinball.

CodeEffect
TESTEnable cheat mode

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
UpUnknown (increases a counter by 1)
0Detect whether the center lights are on (on/off in title bar)
1-9Turn on the center lights
BSpawn an extra ball if the ball isn't on the table
HSet graphics render history flag
YDisplay FPS in the title bar
F1Progress the game by a single frame when in single-step mode
F3Enable REPLAY MODE
F4Unknown (decrements counter 0..5000 by 1)
F5Unknown (decrements counter 0..5000 by 2)
F6Unknown (decrements counter 0..5000 by 100)
F7Write to capture.log
F8Read from capture.log
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

May 22nd, 1995

Below are the codes used in the May 22nd build of Space Cadet Pinball.

CodeEffect
TESTEnable cheat mode

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
UpUnknown (increases a counter by 1)
0Detect whether the center lights are on (on/off in title bar)
1-9Turn on the center lights
BSpawn an extra ball if the ball isn't on the table
HSet graphics render history flag
YDisplay FPS in the title bar
F1Progress the game by a single frame when in single-step mode
F4Unknown (decrements counter 0..5000 by 1)
F5Unknown (decrements counter 0..5000 by 2)
F6Unknown (decrements counter 0..5000 by 100)
F7Write to capture.log
F8Read from capture.log
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

May 26th, 1995

Below are the codes used in the May 26th build of Space Cadet Pinball.

CodeEffect
TESTEnable cheat mode

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
UpUnknown (increases a counter by 1)
BSpawn an extra ball if the ball isn't on the table
HSet graphics render history flag
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

June 12th, 1995

Below are the codes used in the June 12th build of Space Cadet Pinball.

CodeEffect
TESTEnable cheat mode
CINEMATRONICSDisplay staff list

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
BSpawn an extra ball if the ball isn't on the table
HShow the high score dialog and set a new high score
RIncrease rank
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

Staff List

Below is the staff list displayed when entering the CINEMATRONICS code.

June 12th staff list
Staff list display
Programming by
Michael Sandige
-----
John Taylor
Greg Hospelhorn
-----
David Stafford
-----
Art by
John Frantz
Ryan Medeiros
-----
Design by
Kevin Gliner
-----
Audio by
Matt Ridgeway
Donald S. Griffin
-----
Executive Producer
David Stafford
-----
Producer
Kevin Gliner
-----
Special Thanks
Paula Sandige
-----
Jim Cooper
Jim Mischel
-----
Danny Thorpe
Jamie Risdon

June 16th, 1995

Below are the codes used in the June 16th build of Space Cadet Pinball.

CodeEffect
HIDDEN TESTEnable cheat mode
CINEMATRONICSDisplay staff list
QUOTESDisplay quotes

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
BSpawn an extra ball if the ball isn't on the table
HSet graphics render history flag
RIncrease rank
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

Staff List

Below is the staff list displayed when entering the CINEMATRONICS code.

June 16th staff list
Staff list display
Programming by
Michael Sandige
-----
John Taylor
Greg Hospelhorn
-----
David Stafford
-----
Art by
John Frantz
Ryan Medeiros
-----
Design by
Kevin Gliner
-----
Audio by
Matt Ridgeway
Donald S. Griffin
-----
Executive Producer
David Stafford
-----
Producer
Kevin Gliner
-----
Special Thanks
Paula Sandige
-----
Jim Cooper
Jim Mischel
-----
Danny Thorpe
Jamie Risdon

Quotes

Below are the quotes displayed when entering the QUOTES code.

June 16th quotes
Quotes display
No matter where you go there you are.
-----
Tomorrow already sucks
-----
That worked to good to be right.

June 28th, 1995

Below are the codes used in the June 28th build of Space Cadet Pinball.

CodeEffect
HIDDEN TESTEnable cheat mode
CINEMATRONICS.Display staff list
QUOTES.Display quotes

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
BSpawn an extra ball if the ball isn't on the table
HShow the high score dialog and set a new high score
MShow memory usage
RIncrease rank
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

Staff List

Below is the staff list displayed when entering the CINEMATRONICS. code.

June 28th staff list
Staff list display
Programming by
Michael Sandige
-----
John Taylor
-----
Greg Hospelhorn
-----
David Stafford
-----
Art by
John Frantz
-----
Ryan Medeiros
-----
Design by
Kevin Gliner
-----
Audio by
Matt Ridgeway
-----
Donald S. Griffin
-----
Executive Producer
David Stafford
-----
Producer
Kevin Gliner
-----
Special Thanks
Paula Sandige
-----
Jim Cooper
-----
Jim Mischel
-----
Danny Thorpe
-----
Jamie Risdon
-----
Brad Silverberg
-----
Jeff Camp
-----
Alex St. John

Quotes

Below are the quotes displayed when entering the QUOTES. code.

June 28th quotes
Quotes display
Hey, is that a screen saver?
-----
I guess it has been a good week
-----
She may already be a glue bottle
-----
If you don't come in Saturday,
...

-----
don't even bother coming in Sunday.
-----
Tomorrow already sucks
-----
I knew it worked too good to be right.
-----
World's most expensive flippers

July 3rd, 1995

Below are the codes used in the July 3rd build of Space Cadet Pinball.

CodeEffect
HIDDEN TESTEnable cheat mode
CINEMATRONICS.Display staff list
QUOTES.Display quotes

When in cheat mode, the keys below trigger their associated functionality.

KeyEffect
BSpawn an extra ball if the ball isn't on the table
HShow the high score dialog and set a new high score
MShow memory usage
RIncrease rank
YDisplay FPS in the title bar
F1Progress the game by a single frame when paused
F11Runs port_draw() for TEdgeManager (dummied out)
F12Runs port_draw() for all components on the table
F15Toggles single-step mode

Staff List

Below is the staff list displayed when entering the CINEMATRONICS. code.

July 3rd staff list
Staff list display
Programming by
Michael Sandige
-----
John Taylor
-----
Greg Hospelhorn
-----
David Stafford
-----
Art by
John Frantz
-----
Ryan Medeiros
-----
Design by
Kevin Gliner
-----
Audio by
Matt Ridgeway
-----
Donald S. Griffin
-----
Executive Producer
David Stafford
-----
Producer
Kevin Gliner
-----
Special Thanks
Paula Sandige
-----
Jim Cooper
-----
Jim Mischel
-----
Danny Thorpe
-----
Jamie Risdon
-----
Brad Silverberg
-----
Jeff Camp
-----
Alex St. John

Quotes

Below are the quotes displayed when entering the QUOTES. code.

July 3rd quotes
Quotes display
Hey, is that a screen saver?
-----
I guess it has been a good week
-----
She may already be a glue bottle
-----
If you don't come in Saturday,
...

-----
don't even bother coming in Sunday.
-----
Tomorrow already sucks
-----
I knew it worked too good to be right.
-----
World's most expensive flippers

FONT.DAT

This file goes unused in the final game, but it could have possibly been an early version of the numbers used for the score display or used to display numbers as part of debug functionality.

FONT.DAT Bitmap Data
Bitmap data within the FONT.DAT file

Actual Font Data

The actual font glyphs used by the final game are stored within the PBMSG_FT resource, which can be found in the pinball.exe executable at offset 0x23FB0.

The data for the font glyphs themselves begins at offset 0x240D1 and ends at offset 0x29476.

Each font glyph has the following format:

struct PinballFontGlyph
{
    BYTE    width;
    BYTE    pixels[];
}

The width of the glyph (in pixels) is defined by width, and the height of each glyph is always 22 pixels.

The number of pixels (bytes) that make up the glyph is width * 22.

Font Data
Font glyphs used in Space Cadet Pinball

Unused Font Data

There's an additional unused font that exists in the PINBALL2.MID file at offset 0x86. I'm not sure why it's stored with a MIDI extension, but the file only contains font glyph data.

Each glyph uses the same PinballFontGlyph format above, except the height of each glyph is 23 pixels.

PINBALL2.MID bitmap data
Unused font within the PINBALL2.MID file

PINBALL.DAT

This file contains a significant portion of what makes the game work, such as sprites, components, collision, physics, and more.

PINBALL.DAT data
The PINBALL.DAT file controls all of this

Overview

The file consists of a header, followed by a record table.

The record table is a collection of records, which are just groups of data.

Each record contains one or more fields (properties), which hold the actual data.

Think of it like an Excel spreadsheet:

  • Record Table: The entire spreadsheet
  • Record: A row in the spreadsheet
  • Field: A column within the row
struct DatFile
{
    DatHeader   header;
    Record      record_table[];
}

The size (in bytes) of record_table is determined by the table_size header value in the next section.

DAT Header

At the beginning of the file is a 183-byte header with the following format:

struct DatHeader
{
    CHAR    sig[21];
    CHAR    game_name[50];
    CHAR    table_name[100];
    INT     filesize;
    SHORT   num_records;   
    INT     table_size;
    SHORT   extra_size;
}

The value of sig must be PARTOUT(4.0)RESOURCE with a null byte (00) at the end.

game_name is the name of the game (3D-Pinball), and table_name is the name of the current table.

filesize is the total size (in bytes) of the PINBALL.DAT file.

num_records is the number of records in the record table, and table_size is the total size (in bytes) of the record table.

It seems that extra_size may have been used to specify an extra part of the header. This is 0 in the final game, and any additional fields are simply skipped over.

Record Entries

Each record is a group of fields, and each record starts with a 1-byte value determining the number of fields it contains.

struct Record
{
    BYTE    num_fields;
    Field   fields[];
}

Take the string of bytes below as an example. (You'll learn all about the field types in the next sections)

02 00 CA 00 09 04 00 00 00 2E 2E 2E 00

Let's see what this translates to step-by-step:

  • 02: This record contains 2 fields.
  • 00: The 1st field is a Type field.
  • CA 00: This is 202 in little endian format, so this record's type is A_SOUND.
  • 09: The 2nd field is a String field.
  • 04 00 00 00: This next record is 4 bytes long.
  • 2E 2E 2E 00: This is the ASCII string ....

Next let's take a look at the types of fields that can be stored in records.

Field Entries

Each field starts with a 1-byte field type identifier, followed by the field's data.

Every field type except for the Type field is always followed by a 4-byte length that determines the size (in bytes) of the field.

struct Field
{
    BYTE    type;
    INT     length;
    ...
}

There are 13 possible field types that a record can have.

  • 00: Type
  • 01: Image
  • 02: XImage
  • 03: DLabel
  • 04: Construction
  • 05: Palette
  • 06: Color Cycle
  • 07: Color Rotate
  • 08: Integer
  • 09: String
  • 0A: Attributes
  • 0B: Float Attributes
  • 0C: Z Buffer

Each field type has its own rules for how it processes the data that follows, so we'll take a look at each one.

Field Type: Type

This field is always followed by a single 16-bit value that determines the type of the record.

Below are the possible record types.

Hex
Decimal
Type
C8 00
200
AN_OBJECT
C9 00
201
A_STATE
CA 00
202
A_SOUND
2C 01
300
MATERIAL
90 01
400
KICKER

Field Type: Image

This field defines an image (sprite) that will potentially be drawn on screen.

struct Image
{
    BYTE    resolution;
    SHORT   width;
    SHORT   height;
    SHORT   x;
    SHORT   y;
    INT     size;
    BYTE    type;
    BYTE    pixels[];
}

resolution is always 0 since this indicates a resolution of 640x480.

width and height are the width and height of the image in pixels.

x and y are the X and Y offsets of the image on the table.

size is the total size of the image in bytes.

type is always 1, indicating a device-independent bitmap.

pixels is an array of palette indices that compose the final bitmap.

Field Type: XImage

This field goes unused in the final game. Its usage remains shrouded in mystery.

Field Type: DLabel

This field identifies the name (or label) of the record.

struct DLabel
{
    CHAR    name[];
}

The length of the name string is determined by the field's length value.

Field Type: Construction

This field goes unused in the final game. Its usage remains shrouded in mystery.

Field Type: Palette

This field identifies the palette to be used for all Image types. This palette is also referenced by the font glyph data discussed on page 3.

Each entry in the palette is a color in BGRA format. This means the first byte is the blue value, then green, then red, and finally alpha.

The alpha value is unused in the final game, and the color black (00 00 00 00) is used for transparency.

struct Color
{
    BYTE    b;
    BYTE    g;
    BYTE    r;
    BYTE    a;
}

The palette itself is simply a collection of these color structures.

struct Palette
{
    Color   colors[];
}

The number of actual color entries in the palette can be determined by dividing the field's length value by 4.

Field Type: Color Cycle

This field goes unused in the final game. Its usage remains shrouded in mystery.

Field Type: Color Rotate

This field goes unused in the final game. Its usage remains shrouded in mystery.

Field Type: Integer

This field goes unused in the final game. Its usage remains shrouded in mystery.

Field Type: String

This field identifies a string to be used for later processing.

If the record Type is A_SOUND, then this is the filename of a sound.

struct String
{
    CHAR    str[];
}

The length of the str string is determined by the field's length value.

Field Type: Attributes

This field identifies attributes that affect the game in some way.

Each attribute is identified by a 2-byte identifier, followed by the attribute's data. Each attribute's data is a series of 2-byte values.

struct Attribute
{
    SHORT   type;
    ...
}

There are various different attribute types, as shown below.

Hex
Decimal
Type
05 00
5
Single-Line Text Box
64 00
100
Number of States
2C 01
300
Material Reference
30 01
304
Soft Hit Sound
90 01
400
Kicker Reference
96 01
406
Hard Hit Sound
58 02
600
Table Size *
5A 02
602
Collision Plane
01 04
1025
Table Object Array
03 04
1027
Image Array
4C 04
1100
Activation Sound
4D 04
1101
Deactivation Sound
DC 05
1500
Multi-Line Text Box
* The Table Size is actually determined by the record with label "table_size", but it's being noted here since it's the sole exception to the rule.

As with each field type, each attribute type has its own rules for how it processes the data that follows.

Single-Line Text Box

This attribute takes 4 2-byte values that determine the offset and size of the text box.

struct SingleLineTextBox
{
    SHORT   x;
    SHORT   y;
    SHORT   width;
    SHORT   height;
}

The x and y values determine the top-left offset of the text box.

The width and height values determine the size of the text box.

Number of States

This attribute determines the number of states that a component can have.

This also dictates that the next series of records will be states ("children") of the current record.

struct NumberOfStates
{
    SHORT   num_states;
}

The number of records to set as children of this record are determined by (num_states - 1).

For example, if num_states was 8, then the next 7 records will be child states of the current record.

Material Reference

This attribute determines the record to be used as a "Material", which controls the Elasticity and Smoothness properties.

The Elasticity and Smoothness properties are discussed more in the Float Attributes section.

struct MaterialReference
{
    SHORT   record_id;
}

The Material to be used is determined by the record_id value.

Soft Hit Sound

This attribute determines which A_SOUND record to be used when the ball rolls over the component.

struct SoftHitSound
{
    SHORT   record_id;
}

The A_SOUND record to be used is determined by the record_id value.

Kicker Reference

This attribute determines the record to be used as a "Kicker", which controls various properties about the Kicker.

The specific Kicker properties are discussed more in the Float Attributes section.

struct KickerReference
{
    SHORT   record_id;
}

The Kicker to be used is determined by the record_id value.

Hard Hit Sound

This attribute determines which A_SOUND record to be used when the ball bounces off the component.

struct HardHitSound
{
    SHORT   record_id;
}

The A_SOUND record to be used is determined by the record_id value.

Table Size

This attribute is a special case, and isn't really identified by the value 600.

Instead, the 600 is actually the table width, and the following 2-byte value is the table height.

struct TableSize
{
    SHORT   width = 600;
    SHORT   height;
}

The width and height values determine the total size of the playable area.

These values also determine the window size.

Collision Plane

This attribute determines which collision plane the component resides on.

Plane 2 indicates the topmost plane, e.g. where the ramp bumpers are.

Plane 1 resides between plane 0 (the ground plane) and plane 2, and functions as a "transition" plane of sorts.

struct CollisionPlane
{
    SHORT   plane;
}

If a component doesn't have a Collision Plane attribute, it resides on plane 0 (the ground plane).

Table Object Array

This attribute determines the components that are shown on the table during gameplay.

As the name implies, this defines an array of records alongside a component type for each record.

Each entry in the array has the following format:

struct TableObject
{
    SHORT   object_type;
    SHORT   record_id;
}

The object_type identifies the type of object that the record represents.

The record being associated with the object type is identified by the record_id value.

Below are the possible object types.

Hex
Decimal
Type
E8 03
1000
Table Wall (Polygon)
F2 03
1010
Table Wall (Circle)
E9 03
1001
Plunger
EA 03
1002
Light
EB 03
1003
Left Flipper
EC 03
1004
Right Flipper
ED 03
1005
Bumper
EE 03
1006
Target
EF 03
1007
Drain (Kill Plane)
F3 03
1011
Ball Blocker
F4 03
1012
Kickout (Hyperspace, Black Hole)
F5 03
1013
Gate (Blocks kicker access)
F6 03
1014
Kicker
F7 03
1015
Rollover
F8 03
1016
One-Way
F9 03
1017
Wormhole (Sink)
FA 03
1018
Flag
FB 03
1019
Target (Button)
FC 03
1020
Space Warp Rollover
FD 03
1021
Ramp
FE 03
1022
Ramp Hole
FF 03
1023
Demo
00 04
1024
Deployment Light (Skill Shot)
02 04
1026
Light Group
04 04
1028
Bumper Group
05 04
1029
Gravity Well
06 04
1030
Fuel Lights
07 04
1031
Sound
08 04
1032
Timer
09 04
1033
Text Box

Below is the structure of the actual Table Object Array.

struct TableObjectArray
{
    TableObject     objects[];
}

The number of TableObject entries can be calculated by subtracting 2 from the field length, then dividing by 4.

Image Array

This attribute determines a group of images, with the record typically also having an associated DLabel field.

Each entry in the array is a record ID. Each target record must have an Image field.

struct ImageArray
{
    SHORT   record_ids[];
}

The number of record ID entries can be calculated by subtracting 2 from the field length, then dividing by 2.

Activation Sound

This attribute determines which A_SOUND record to be used when the component is activated.

struct ActivationSound
{
    SHORT   record_id;
}

The A_SOUND record to be used is determined by the record_id value.

Deactivation Sound

This attribute determines which A_SOUND record to be used when the component is deactivated.

struct DeactivationSound
{
    SHORT   record_id;
}

The A_SOUND record to be used is determined by the record_id value.

Multi-Line Text Box

This attribute takes 4 2-byte values that determine the offset and size of the text box.

struct MultiLineTextBox
{
    SHORT   x;
    SHORT   y;
    SHORT   width;
    SHORT   height;
}

The x and y values determine the top-left offset of the text box.

The width and height values determine the size of the text box.

Field Type: Float Attributes

Like the Attributes field, this field also identifies attributes that affect the game in some way.

The main difference is that these values are all float values, i.e. numbers like 3.14 instead of 3.

Each float attribute is identified by a 4-byte identifier, followed by the attribute's data. Each float attribute's data is a series of 4-byte values.

struct FloatAttribute
{
    FLOAT   type;
    ...
}

There are various different float attribute types, as shown below.

Hex
Decimal
Type
00 00 80 3F
1.0
Camera Matrix
00 80 96 43
301.0
Material: Smoothness
00 00 97 43
302.0
Material: Elasticity
00 80 98 43
305.0
Gravity
00 00 99 43
306.0
Activation Radius
00 80 C8 43
401.0
Kicker: Threshold
00 00 C9 43
402.0
Kicker: Boost
00 80 C9 43
403.0
Kicker: Eject Force
00 00 CA 43
404.0
Kicker: Eject Direction
00 80 CA 43
405.0
Kicker: Eject Angle
00 00 CB 43
406.0
Kicker: Hard Hit Sound
00 80 CB 43
407.0
Kicker: Deactivation Timer
00 00 CC 43
408.0
Kicker: Ball Position
00 00 FA 43
500.0
Ball: Collision Z Offset
00 80 FA 43
501.0
Ball: Sprite Distance
00 00 16 44
600.0
Collision
00 40 16 44
601.0
Ball: Spawn Position
00 C0 16 44
603.0
Rollover Collision
00 00 2F 44
700.0
Table Center
00 40 2F 44
701.0
Gravity Multiplier
00 00 48 44
800.0
Flipper: Base Position
00 40 48 44
801.0
Flipper: Tip Position (Idle)
00 80 48 44
802.0
Flipper: Tip Position (Active)
00 C0 48 44
803.0
Flipper: Force
00 00 49 44
804.0
Flipper: Activate Speed
00 40 49 44
805.0
Flipper: Deactivate Speed
00 00 61 44
900.0
Light On Duration
00 40 61 44
901.0
Light Off Duration
00 C0 61 44
903.0
Light Group Timer
00 00 62 44
904.0
Fuel Graph Light Timers
00 00 96 44
1200.0
Maximum Flag Speed
00 20 96 44
1201.0
Minimum Flag Speed
00 40 96 44
1202.0
Flag Friction
00 80 A2 44
1300.0
Ramp: Incline
00 A0 A2 44
1301.0
Ramp: Enter Line
00 C0 A2 44
1302.0
Ramp: Transition Line
00 E0 A2 44
1303.0
Ramp: Plane Transition
00 00 A3 44
1304.0
Ramp: Plane Change Flag
00 20 A3 44
1305.0
Ramp: Z Offset Flag
00 00 AF 44
1400.0
Demo: Left Flipper Trigger Line
00 20 AF 44
1401.0
Demo: Left Flipper Trigger Raycast
00 40 AF 44
1402.0
Demo: Right Flipper Trigger Line
00 60 AF 44
1403.0
Demo: Right Flipper Trigger Raycast
00 80 AF 44
1404.0
Demo: Plunger Trigger Line
* The Camera Matrix is actually determined by the record with label "camera_info", but it's being noted here since it's the sole exception to the rule.

As with each field type, each attribute type has its own rules for how it processes the data that follows.

Camera Matrix

This float attribute consists of 15 different float values that define the camera's 3D projection matrix.

The camera matrix is used for calculating the positioning of collision, the ball's current depth, and a few other things.

Like the Table Size attribute, it isn't really identified by the value 1.0.

Instead, the 1.0 is actually the first part of the structure, followed by 14 additional float values.

struct Camera
{
    FLOAT   m00 = 1.0;
    FLOAT   m01;
    FLOAT   m02;
    FLOAT   m03;
    FLOAT   m10;
    FLOAT   m11;
    FLOAT   m12;
    FLOAT   m13;
    FLOAT   m20;
    FLOAT   m21;
    FLOAT   m22;
    FLOAT   m23;
    FLOAT   distance;
    FLOAT   near;
    FLOAT   far;
}

The first 12 values (m00 to m23) compose the actual 4x4 camera matrix, which is composed as follows:

[ m00, m01, m02, m03 ]
[ m10, m11, m12, m13 ]
[ m20, m21, m22, m23 ]
[ 0.0, 0.0, 0.0, 1.0 ]

distance identifies the distance between the camera and the subject.

near and far determine the near and far clipping planes, respectively.

Camera Matrix Modification
Animated example of how modifying the camera matrix affects the collision

Material: Smoothness

This float attribute determines the Smoothness of the material.

A material's Smoothness determines how intensely the material's Elasticity (bounce) is applied.

A higher Smoothness means the ball won't bounce as hard off the collision surface.

struct MaterialSmoothness
{
    FLOAT   smoothness;
}

Material: Elasticity

This float attribute determines the Elasticity of the material.

A material's Elasticity determines how hard the ball bounces off the object.

A higher Elasticity means the ball will bounce off much harder and faster.

struct MaterialElasticity
{
    FLOAT   elasticity;
}

Gravity

This float attribute determines the amount of gravity that the component exerts.

A higher gravity value indicates that the gravity is stronger and pulls the ball much more.

struct Gravity
{
    FLOAT   amount;
}

The amount value determines how much gravity is applied to the ball.

Note: The record with the DLabel field value of table has the following structure:

struct TableGravity
{
    FLOAT   amount;
    FLOAT   x;
    FLOAT   y;
}

x and y are the angles for the X and Y axes, respectively.

Activation Radius

This float attribute determines the activation radius for the component.

If the ball falls within this area, the ball will snap to the position of the activated component.

struct ActivationRadius
{
    FLOAT   radius;
}

Kicker: Threshold

This float attribute determines the amount of force required to activate the component.

The higher the threshold, the harder the ball has to hit the component for it to activate.

struct KickerThreshold
{
    FLOAT   threshold;
}

Kicker: Boost

This float attribute determines how hard the ball is propelled away from the component after activation.

A higher value means the ball will be propelled away harder and faster.

struct KickerBoost
{
    FLOAT   boost;
}

Kicker: Eject Force

This float attribute determines how hard the ball is ejected from a kickout, wormhole, or the escape chute.

A higher value means the ball will be ejected harder and faster.

struct KickerEjectForce
{
    FLOAT   force;
}

Kicker: Eject Direction

This float attribute determines the direction that the ball should be ejected.

struct KickerEjectDirection
{
    FLOAT   horiz;
    FLOAT   vert;
}

The possible horizontal directions are as follows:

const float LEFT    =    1.0;
const float RIGHT   =   -1.0;

The possible vertical directions are as follows:

const float UP      =    1.0;
const float DOWN    =   -1.0;

If the ball should only be ejected along the horizontal or vertical axis, a value of 0.0 can be supplied for the non-ejecting axis.

const float NONE    =   0.0;

Kicker: Eject Angle

This float attribute determines the possible angle of ejection, specified in radians.

The ejection angle starts from the Eject Direction angle and continues clockwise.

struct KickerEjectAngle
{
    FLOAT   angle;
}

Kicker: Hard Hit Sound

This float attribute determines which A_SOUND record to be used when the ball bounces off the component.

This is functionally equivalent to the Hard Hit Sound attribute (the non-float one).

struct KickerHardHitSound
{
    FLOAT   record_id;
}

The A_SOUND record to be used is determined by the record_id value.

Kicker: Deactivation Timer

This float attribute determines how long the component will stay active before deactivating.

struct KickerDeactivationTimer
{
    FLOAT   seconds;
}

Kicker: Ball Position

This float attribute determines the ball's Z position after entering a kickout.

This also determines the ball's XYZ position after falling through the ramp hole.

struct KickerBallPosition
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   z;
}

Note: The record with the DLabel field value of ramp_hole has the following structure:

struct KickerBallPosition
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   z;
    FLOAT   z2;
}

Ball: Collision Z Offset

This float attribute determines the Z offset of the ball.

This is mostly used when determining the ball's collision.

struct BallCollisionOffset
{
    FLOAT   z;
}

Ball: Sprite Distance

This float attribute determines the XYZ locations where the ball changes from one sprite to another.

This usually happens when the ball gets closer to or further from the camera.

It should be noted that only the Y and Z values are used, while X is 0.0 by default and isn't used.

struct BallSpriteDistance
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   z;
}

Collision

This float attribute consists of a series of points that determines the collision of the component.

Each point has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The structure first identifies the number of points in the polygon, followed by a series of XY points that make up the collision polygon.

struct Collision
{
    FLOAT   num_points;
    Point   points[];
    FLOAT   unused;
}

Note: If num_points is 1.0, this indicates that the point is instead a circle with the following structure:

struct Circle
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   radius;
}

In the case of a circle, the structure has a single Circle variable instead of a Point array.

struct Collision
{
    FLOAT   num_points;
    Circle  circle;
    FLOAT   unused;
}

In both cases, the unused variable has a varying value between records, but goes unused.

Ball Position Modifier (Sink/Plunger)

This float attribute determines where the ball is respawned after entering a wormhole.

This also determines the initial spawning location of the ball when the game starts or after a ball is lost.

struct BallSpawnPosition
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   z;
    FLOAT   unused;
}

The x and y variables determine the position of the ball on the table.

The z and unused variables go unused.

Rollover Collision

This float attribute determines the collision for rollover components.

Each point has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The structure is the same as the Collision float attribute.

struct RolloverCollision
{
    FLOAT   num_points;
    Point   points[];
    FLOAT   unused;
}

As with the Collision float attribute, the unused variable goes unused.

Table Center

This float attribute determines the coordinates of the center of the table.

struct TableCenter
{
    FLOAT   x;
    FLOAT   y;
}

Gravity Multiplier

This float attribute determines the amount of gravity applied to the ball.

struct GravityMult
{
    FLOAT   amount;
}

Flipper: Base Position

This float attribute determines the position of the flipper's base.

The position is a circle with an XY coordinate and radius.

struct FlipperBase
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   radius;
    FLOAT   unused;
}

Flipper: Tip Position (Idle)

This float attribute determines the position of the flipper's tip when the flipper is idle.

struct FlipperTipIdle
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   radius;
    FLOAT   unused;
}

Flipper: Tip Position (Active)

This float attribute determines the position of the flipper's tip when the flipper is active.

struct FlipperTipActive
{
    FLOAT   x;
    FLOAT   y;
    FLOAT   radius;
    FLOAT   unused;
}

Flipper: Force

This float attribute determines how hard the flipper propels the ball.

struct FlipperForce
{
    FLOAT   force;
}

Flipper: Activate Speed

This float attribute determines how quickly the flipper goes from idle to active (fully extended).

struct FlipperActivateSpeed
{
    FLOAT   seconds;
}

Flipper: Deactivate Speed

This float attribute determines how quickly the flipper goes from active (fully extended) to idle.

struct FlipperDeactivateSpeed
{
    FLOAT   seconds;
}

Light On Duration

This float attribute determines how long a light should stay on for.

struct LightOnDuration
{
    FLOAT   seconds;
}

Light Off Duration

This float attribute determines how long a light should stay off for.

struct LightOffDuration
{
    FLOAT   seconds;
}

Light Group Timer

This float attribute determines the default timer for the light group.

struct LightGroupTimer
{
    FLOAT   seconds;
}

Fuel Graph Light Timers

This float attribute determines the delay/blink timers for each of the fuel graph lights.

Each timer has the following structure:

struct FuelTimer
{
    FLOAT   off_seconds;
    FLOAT   on_seconds;
}

off_seconds determines how long the light should be in a "blinking" state before it turns off.

on_seconds determines how long the light should stay on before it enters the "blinking" state.

The timers are grouped together in the following structure:

struct FuelGraphLightTimers
{
    FuelTimer   timers[];
}

The number of timer entries can be determined by dividing the float attribute's length value by 2.

The timers are stored in reverse order, with the top light being the last timer entry and the last light being the first timer entry.

Maximum Flag Speed

This float attribute determines the maximum speed for a flag component.

struct MaxFlagSpeed
{
    FLOAT   amount;
}

Minimum Flag Speed

This float attribute determines the minimum speed for a flag component.

struct MinFlagSpeed
{
    FLOAT   amount;
}

Flag Friction

This float attribute determines the friction applied to a flag component.

struct FlagFriction
{
    FLOAT   amount;
}

Ramp: Incline

This float attribute determines the incline of a ramp and how it affects the ball.

This gives the ramp realistic gravity by giving each part of the ramp specific gravity characteristics.

Each part of the ramp is represented by a triangular area with varying amounts of gravity.

Each point in the triangle has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

Each part of the ramp has the following structure:

struct RampPart
{
    FLOAT   x_offset;
    FLOAT   y_offset;
    FLOAT   z_offset;
    Point   p1;
    Point   p2;
    Point   p3;
    FLOAT   grav_x;
    FLOAT   grav_y;
    FLOAT   unused1;
    FLOAT   unused2;
}

x_offset, y_offset, and z_offset determine the relative offset of the ball on the ramp.

p1, p2, and p3 determine the points of the triangular portion of the incline.

grav_x and grav_y determine the gravity applied in the X and Y directions, respectively.

unused1 and unused2 are both unused.

The entire ramp incline is grouped as follows:

struct RampIncline
{
    FLOAT       num_parts;
    RampPart    parts[];
}

Ramp: Enter Line

This float attribute determines a line marking where the ramp starts.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The transition line has the following structure:

struct RampEnterLine
{
    FLOAT   group;
    FLOAT   enabled;
    FLOAT   unused;
    Point   p1;
    Point   p2;
    FLOAT   z_offset;
}

group determines the group that the collision is a part of.

enabled determines whether the collision is enabled.

unused goes unused.

p1 and p2 determine the start and end points of the line.

z_offset determines the ball's Z offset.

Ramp: Transition Line

This float attribute determines a line marking where the ball transitions from the table plane to the ramp plane.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The transition line has the following structure:

struct RampTransitionLine
{
    FLOAT   group;
    FLOAT   enabled;
    FLOAT   unused;
    Point   p1;
    Point   p2;
    FLOAT   z_offset;
}

group determines the group that the collision is a part of.

enabled determines whether the collision is enabled.

unused goes unused.

p1 and p2 determine the start and end points of the line.

z_offset determines the ball's Z offset.

Ramp: One-Way Line

This float attribute determines a line marking where the ball moves past the one-way gate on the ramp plane.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The transition line has the following structure:

struct RampOneWayLine
{
    FLOAT   group;
    FLOAT   unused;
    Point   p1;
    Point   p2;
    FLOAT   z_offset;
}

group determines the group that the collision is a part of.

unused goes unused.

p1 and p2 determine the start and end points of the line.

z_offset determines the ball's Z offset.

Ramp: Plane Change Flag

This float attribute determines whether the component is triggering a plane transition.

This is only used for the ramp hole.

struct RampPlaneChangeFlag
{
    FLOAT   enabled;
}

Ramp: Z Offset Flag

This float attribute determines whether the ball's Z offset should be modified.

struct RampZOffsetFlag
{
    FLOAT   enabled;
}

Demo: Left Flipper Trigger Line

This float attribute determines a line marking where the left flipper should detect the ball in the demo.

This is only used when the ball rolls towards the left flipper after passing through the left return lane or the bonus lane.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The trigger line has the following structure:

struct DemoLeftTriggerLine
{
    FLOAT   num_points;
    Point   points[];
    FLOAT   unused;
}

num_points determines how many points there are in the line.

Demo: Left Flipper Trigger Raycast

This float attribute determines a triangle marking where the left flipper should detect the ball in the demo.

This is used when the ball falls downwards from the center towards the left flipper.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

Each line has the following structure:

struct Line
{
    Point   p1;
    Point   p2;
}

The trigger raycast itself has the following structure:

struct DemoLeftTriggerLine
{
    FLOAT   num_points;
    Line    lines[];
    FLOAT   unused;
}

num_points determines how many points there are in the raycast.

lines are the lines that make up the raycast. The number of lines can be determined by dividing num_points by 2.

Demo: Right Flipper Trigger Line

This float attribute determines a line marking where the right flipper should detect the ball in the demo.

This is only used when the ball rolls towards the right flipper after passing through the right return lane.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The trigger line has the following structure:

struct DemoRightTriggerLine
{
    FLOAT   num_points;
    Point   points[];
    FLOAT   unused;
}

num_points determines how many points there are in the line.

Demo: Right Flipper Trigger Raycast

This float attribute determines a triangle marking where the right flipper should detect the ball in the demo.

This is used when the ball falls downwards from the center towards the right flipper.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

Each line has the following structure:

struct Line
{
    Point   p1;
    Point   p2;
}

The trigger raycast itself has the following structure:

struct DemoLeftTriggerLine
{
    FLOAT   num_points;
    Line    lines[];
    FLOAT   unused;
}

num_points determines how many points there are in the raycast.

lines are the lines that make up the raycast. The number of lines can be determined by dividing num_points by 2.

Demo: Plunger Trigger Line

This float attribute determines a line marking where the plunger should start being pulled back in the demo.

Each point in the line has the following structure:

struct Point
{
    FLOAT   x;
    FLOAT   y;
}

The trigger line has the following structure:

struct DemoPlungerTriggerLine
{
    FLOAT   num_points;
    Point   points[];
    FLOAT   unused;
}

num_points determines how many points there are in the line.

Field Type: Z Buffer

This field determines the Z buffer for the component, which controls how the component is drawn in 3D space.

struct ZBuffer
{
    SHORT   width;
    SHORT   height;
    SHORT   stride;
    INT     unused1;
    SHORT   unused2;
    SHORT   unused3;
    SHORT   buffer[];
}

width and height are the width and height of the image in pixels.

stride is the number of 16-bit values that compose a single scanline.

unused1, unused2, and unused3 are all unused.

buffer is an array of 16-bit values indices that compose the Z buffer.

The length of the buffer array can be determined by calculating stride × height.

Z Buffer Example
Animated example of how the Z buffer influences a component's depth