Zone
A Crash level is composed of invisible zones. Each zone is a cubic region of 3 dimensional space, with dimensions (width, height, depth) and unique location/position, within its containing level. The space occupied by a zone approximately encompasses [the evidently interactive portions of] up to 8 worlds. All together as a whole, a level's zones encompass all of the apparently interactive space occupied by its worlds and any additional surrounding 'atmosphere'; this complete enclosure defines the approximate boundaries for the entire level.
Contents
Description
In an instance of a Crash game, when initially entering a level, the player character (Crash/Willie) is spawned at a specific location within the level's first zone-(i.e. its initial entry point). At this point, the worlds encompassed by the zone, and possibly other nearby worlds, are visible to the player, and the player character is typically in a location where it appears to be supported by some aspect of the worlds-usually terrain. The player is now free to complete one or more level objectives for furthering its overall game progress.
In a Crash 1 [non-boss] level, the player's primary objective is to progress towards and ultimately reach the goal-i.e. the warp platform located at the end. Crash 2 and 3 extend this objective by requiring that the crystal be collected at some point along the path to the goal. Together, the zones provide the play area through which the player is to roam towards its goal. The player progresses from zone to zone, encountering various obstacles along the way, until it either reaches the goal, or dies in its pursuit.
TBD: introduction for header, dimensions/collision octree, camera paths, and entities
Format
Prototype
This format is only used in the earliest Crash 1 levels (i.e. 02)
Item 1: Header
Offset | Field | Size | Value |
---|---|---|---|
0x0 | World Count | 4 bytes | w |
0x4 | Reserved for World Models | 8 x 0x40 bytes | * |
0x204 | Header Item Count (Header and Collision octree items) | 4 bytes | h |
0x208 | Camera Path Count | 4 bytes | c |
0x20C | Entity Count | 4 bytes | e |
0x210 | Neighbor Zone Count | 4 bytes | n |
0x214 | Neighbor Zone EIDs | 5 x 4 bytes | * |
0x228 | Texture Page Entry Count | 4 bytes | p |
0x22C | Uncompressed Chunk Count | 4 bytes | t |
0x230 | Texture Page Entry EIDs | 8 x 4 bytes | * |
0x250 | Uncompressed Chunk CIDs | 32 x 4 bytes | * |
0x2D0 | Unknown | ? bytes | * |
0x30C | Object Light Source Matrix L11 | 2 bytes | * |
0x30E | Object Light Source Matrix L12 | 2 bytes | * |
0x310 | Object Light Source Matrix L13 | 2 bytes | * |
0x312 | Object Light Source Matrix L21 | 2 bytes | * |
0x314 | Object Light Source Matrix L22 | 2 bytes | * |
0x316 | Object Light Source Matrix L23 | 2 bytes | * |
0x318 | Object Light Source Matrix L31 | 2 bytes | * |
0x31A | Object Light Source Matrix L32 | 2 bytes | * |
0x31C | Object Light Source Matrix L33 | 2 bytes | * |
0x31E | Object Background Color R | 2 bytes | * |
0x320 | Object Background Color G | 2 bytes | * |
0x322 | Object Background Color B | 2 bytes | * |
0x324 | Object Light Color Matrix LR1 | 2 bytes | * |
0x326 | Object Light Color Matrix LR2 | 2 bytes | * |
0x328 | Object Light Color Matrix LR3 | 2 bytes | * |
0x32A | Object Light Color Matrix LG1 | 2 bytes | * |
0x32C | Object Light Color Matrix LG2 | 2 bytes | * |
0x32E | Object Light Color Matrix LG3 | 2 bytes | * |
0x330 | Object Light Color Matrix LB1 | 2 bytes | * |
0x332 | Object Light Color Matrix LB2 | 2 bytes | * |
0x334 | Object Light Color Matrix LB3 | 2 bytes | * |
0x336 | Object Background Color Intensity R | 2 bytes | * |
0x338 | Object Background Color Intensity G | 2 bytes | * |
0x33A | Object Background Color Intensity B | 2 bytes | * |
0x33C | Player Light Source Matrix L11 | 2 bytes | * |
0x33E | Player Light Source Matrix L12 | 2 bytes | * |
0x340 | Player Light Source Matrix L13 | 2 bytes | * |
0x342 | Player Light Source Matrix L21 | 2 bytes | * |
0x344 | Player Light Source Matrix L22 | 2 bytes | * |
0x346 | Player Light Source Matrix L23 | 2 bytes | * |
0x348 | Player Light Source Matrix L31 | 2 bytes | * |
0x34A | Player Light Source Matrix L32 | 2 bytes | * |
0x34C | Player Light Source Matrix L33 | 2 bytes | * |
0x34E | Player Background Color R | 2 bytes | * |
0x350 | Player Background Color G | 2 bytes | * |
0x352 | Player Background Color B | 2 bytes | * |
0x354 | Player Light Color Matrix LR1 | 2 bytes | * |
0x356 | Player Light Color Matrix LR2 | 2 bytes | * |
0x358 | Player Light Color Matrix LR3 | 2 bytes | * |
0x35A | Player Light Color Matrix LG1 | 2 bytes | * |
0x35C | Player Light Color Matrix LG2 | 2 bytes | * |
0x35E | Player Light Color Matrix LG3 | 2 bytes | * |
0x360 | Player Light Color Matrix LB1 | 2 bytes | * |
0x362 | Player Light Color Matrix LB2 | 2 bytes | * |
0x364 | Player Light Color Matrix LB3 | 2 bytes | * |
0x366 | Player Background Color Intensity R | 2 bytes | * |
0x368 | Player Background Color Intensity G | 2 bytes | * |
0x36A | Player Background Color Intensity B | 2 bytes | * |
Item 2: Dimensions/Collision Octree
Offset | Field | Size | Value |
---|---|---|---|
0x0 | Zone Location X | 4 bytes | * |
0x4 | Zone Location Y | 4 bytes | * |
0x8 | Zone Location Z | 4 bytes | * |
0xC | Zone Width | 4 bytes | * |
0x10 | Zone Height | 4 bytes | * |
0x14 | Zone Depth | 4 bytes | * |
0x18 | unknown | 4 bytes | * |
Collision Octree | |||
0x1C | Root Node Index | 2 bytes | * |
0x24 | Octree Nodes | * x 2 bytes | * |
Item 3+n: Camera Path
Offset | Field | Size | Value |
---|---|---|---|
0x0 | [Polygon] Sort List EID | 4 bytes | * |
0x4 | Reserved for pointer to parent zone (entry) | 4 bytes | garbage? |
0x8 | Neighboring Path Count | 4 bytes | * |
0xC | Neighboring Paths | 4 x 4 x 1 byte | * |
Neighbor Path Structure d | |||
0xC + (d x 4) +0x0 | Relation [to this path] | 1 byte | * |
0xC + (d x 4) +0x1 | Parent Zone Index [in neighbor zone list] | 1 byte | * |
0xC + (d x 4) +0x2 | Path Item Index | 1 byte | * |
0xC + (d x 4) +0x3 | Relation to Goal/Misc Flag | 1 byte | * |
end | |||
0x1C | Rel. Index of Entry Point [furthest from goal] | 1 byte | * |
0x1D | Rel. Index of Exit Point [closest to goal] | 1 byte | * |
0x1E | Path Length/Point Count | 2 bytes | L |
0x20 | Camera Mode | 2 bytes | * |
0x22 | Average Distance b/t Consecutive Path Points | 2 bytes | * |
0x24 | Camera Z Zoom/Y Pan Factor | 2 bytes | * |
0x26 | unknown | 2 bytes | * |
0x28 | unknown | 2 bytes | * |
0x2A | unknown | 2 bytes | * |
0x2C | Path Direction X | 2 bytes | * |
0x2E | Path Direction Y | 2 bytes | * |
0x30 | Path Direction Z | 2 bytes | * |
0x32 | Camera Path Points | L x 12 bytes | * |
Camera Path Point Structure p (*point/trans location relative to parent zone location) | |||
0x32 + (p x 12) + 0x0 | Point X/Camera Trans X | 2 bytes | * |
0x32 + (p x 12) + 0x2 | Point Y/Camera Trans Y | 2 bytes | * |
0x32 + (p x 12) + 0x4 | Point Z/Camera Trans Z | 2 bytes | * |
0x32 + (p x 12) + 0x6 | Camera Rotation X | 2 bytes | * |
0x32 + (p x 12) + 0x8 | Camera Rotation Y | 2 bytes | * |
0x32 + (p x 12) + 0xA | Camera Rotation Z | 2 bytes | * |
Item 3+c+n: Entity
Offset | Field | Size | Value |
---|---|---|---|
0x0 | Reserved for pointer to parent zone (entry) | 4 bytes | garbage? |
0x4 | Spawn Configuration Flags | 2 bytes | * |
0x6 | Object Process Type | 2 bytes | * |
0x8 | ID | 2 bytes | * |
0xA | Path Point Count | 2 bytes | L |
0xC | Object Path Points | L x 6 bytes | * |
Object Path Point Structure p | |||
0xC + (p x 6) + 0x0 | Point X | 2 bytes | * |
0xC + (p x 6) + 0x2 | Point Y | 2 bytes | * |
0xC + (p x 6) + 0x4 | Point Z | 2 bytes | * |
End | |||
0xC + (L x 6) | Mode Flags A (or initial Y rot) | 2 bytes | * |
0xC + (L x 6) + 0x2 | Mode Flags B (or initial X rot) | 2 bytes | * |
0xC + (L x 6) + 0x4 | Mode Flags C (or initial Z rot) | 2 bytes | * |
0xC + (L x 6) + 0x6 | Object Type | 1 byte | * |
0xC + (L x 6) + 0x7 | Object Subtype | 1 byte | * |
0xC + (L x 6) + 0x8 | unknown? | 2 bytes if L = 1, otherwise 4 | 0x0 |
Final
Item 1: Header
Offset | Field | Size | Value |
---|---|---|---|
0x0 | World Count | 4 bytes | w |
0x4 | Reserved for World Models | 8 x 0x40 bytes | * |
0x204 | Index of First Camera Path Item | 4 bytes | h |
0x208 | Camera Path Count | 4 bytes | c |
0x20C | Entity Count | 4 bytes | e |
0x210 | Neighbor Zone Count | 4 bytes | n |
0x214 | Neighbor Zone EIDs | 8 x 4 bytes | * |
0x234 | Texture Page Entry Count | 4 bytes | p |
0x238 | Uncompressed Chunk CID Count | 4 bytes | t |
0x23C | Texture Page Entry EIDs | 8 x 4 bytes | * |
0x25C | Uncompressed Chunk CIDs | 32 x 4 bytes | * |
0x2DC | Zone Spawn Flags | 4 bytes | * |
0x2E0 | VRAM Fill Height for clearing draw buffer | 4 bytes | * |
0x2E4 | unknown | 4 bytes | * |
0x2E8 | Zone Visibility Depth? | 4 bytes | * |
0x2EC | unknown | 4 bytes | * |
0x2F0 | unknown | 4 bytes | * |
0x2F4 | unknown | 4 bytes | * |
0x2F8 | unknown | 4 bytes | * |
0x2FC | Zone Flags | 4 bytes | * |
0x300 | Max Death Height? Max Water Height? | 4 bytes | * |
0x304 | unknown | 4 bytes | * |
0x308 | unknown | 4 bytes | * |
0x30C | unknown; see sub_260AC | 4 bytes | * |
0x310 | VRAM Clear Color R | 1 byte | * |
0x311 | VRAM Clear Color G | 1 byte | * |
0x312 | VRAM Clear Color B | 1 byte | * |
0x313 | unused | 1 byte | * |
0x314 | Music entry reference | 4 bytes | * |
0x318 | Object Light Source Matrix L11 | 2 bytes | * |
0x31A | Object Light Source Matrix L12 | 2 bytes | * |
0x31C | Object Light Source Matrix L13 | 2 bytes | * |
0x31E | Object Light Source Matrix L21 | 2 bytes | * |
0x320 | Object Light Source Matrix L22 | 2 bytes | * |
0x322 | Object Light Source Matrix L23 | 2 bytes | * |
0x324 | Object Light Source Matrix L31 | 2 bytes | * |
0x326 | Object Light Source Matrix L32 | 2 bytes | * |
0x328 | Object Light Source Matrix L33 | 2 bytes | * |
0x32A | Object Background Color R | 2 bytes | * |
0x32C | Object Background Color G | 2 bytes | * |
0x32E | Object Background Color B | 2 bytes | * |
0x330 | Object Light Color Matrix LR1 | 2 bytes | * |
0x332 | Object Light Color Matrix LR2 | 2 bytes | * |
0x334 | Object Light Color Matrix LR3 | 2 bytes | * |
0x336 | Object Light Color Matrix LG1 | 2 bytes | * |
0x338 | Object Light Color Matrix LG2 | 2 bytes | * |
0x33A | Object Light Color Matrix LG3 | 2 bytes | * |
0x33C | Object Light Color Matrix LB1 | 2 bytes | * |
0x33E | Object Light Color Matrix LB2 | 2 bytes | * |
0x340 | Object Light Color Matrix LB3 | 2 bytes | * |
0x342 | Object Background Color Intensity R | 2 bytes | * |
0x344 | Object Background Color Intensity G | 2 bytes | * |
0x346 | Object Background Color Intensity B | 2 bytes | * |
0x348 | Player Light Source Matrix L11 | 2 bytes | * |
0x34A | Player Light Source Matrix L12 | 2 bytes | * |
0x34C | Player Light Source Matrix L13 | 2 bytes | * |
0x34E | Player Light Source Matrix L21 | 2 bytes | * |
0x350 | Player Light Source Matrix L22 | 2 bytes | * |
0x352 | Player Light Source Matrix L23 | 2 bytes | * |
0x354 | Player Light Source Matrix L31 | 2 bytes | * |
0x356 | Player Light Source Matrix L32 | 2 bytes | * |
0x358 | Player Light Source Matrix L33 | 2 bytes | * |
0x35A | Player Background Color R | 2 bytes | * |
0x35C | Player Background Color G | 2 bytes | * |
0x35E | Player Background Color B | 2 bytes | * |
0x360 | Player Light Color Matrix LR1 | 2 bytes | * |
0x362 | Player Light Color Matrix LR2 | 2 bytes | * |
0x364 | Player Light Color Matrix LR3 | 2 bytes | * |
0x366 | Player Light Color Matrix LG1 | 2 bytes | * |
0x368 | Player Light Color Matrix LG2 | 2 bytes | * |
0x36A | Player Light Color Matrix LG3 | 2 bytes | * |
0x36C | Player Light Color Matrix LB1 | 2 bytes | * |
0x36E | Player Light Color Matrix LB2 | 2 bytes | * |
0x370 | Player Light Color Matrix LB3 | 2 bytes | * |
0x372 | Player Background Color Intensity R | 2 bytes | * |
0x374 | Player Background Color Intensity G | 2 bytes | * |
0x376 | Player Background Color Intensity B | 2 bytes | * |
Item 2: Dimensions/Collision Octree
Offset | Field | Size | Value |
---|---|---|---|
0x0 | Zone Location X | 4 bytes | * |
0x4 | Zone Location Y | 4 bytes | * |
0x8 | Zone Location Z | 4 bytes | * |
0xC | Zone Width | 4 bytes | * |
0x10 | Zone Height | 4 bytes | * |
0x14 | Zone Depth | 4 bytes | * |
0x18 | unknown | 4 bytes | * |
Collision Octree | |||
0x1C | Root Node Index | 2 bytes | * |
0x1E | Maximum Depth X | 2 bytes | * |
0x20 | Maximum Depth Y | 2 bytes | * |
0x22 | Maximum Depth Z | 2 bytes | * |
0x24 | Octree Nodes | * x 2 bytes | * |
Item 3+n: Camera Path
Offset | Field | Size | Value |
---|---|---|---|
0x0 | [Polygon] Sort List EID | 4 bytes | * |
0x4 | Reserved for pointer to parent zone (entry) | 4 bytes | garbage? |
0x8 | Neighboring Path Count | 4 bytes | * |
0xC | Neighboring Paths | 4 x 4 x 1 byte | * |
Neighbor Path Structure d | |||
0xC + (d x 4) +0x0 | Relation [to this path] | 1 byte | * |
0xC + (d x 4) +0x1 | Parent Zone Index [in neighbor zone list] | 1 byte | * |
0xC + (d x 4) +0x2 | Path Item Index | 1 byte | * |
0xC + (d x 4) +0x3 | Relation to Goal/Misc Flag | 1 byte | * |
end | |||
0x1C | Rel. Index of Entry Point [furthest from goal] | 1 byte | * |
0x1D | Rel. Index of Exit Point [closest to goal] | 1 byte | * |
0x1E | Path Length/Point Count | 2 bytes | L |
0x20 | Camera Mode | 2 bytes | * |
0x22 | Average Distance b/t Consecutive Path Points | 2 bytes | * |
0x24 | Camera Z Zoom/Y Pan Factor | 2 bytes | * |
0x26 | unknown | 2 bytes | * |
0x28 | unknown | 2 bytes | * |
0x2A | unknown | 2 bytes | * |
0x2C | Path Direction X | 2 bytes | * |
0x2E | Path Direction Y | 2 bytes | * |
0x30 | Path Direction Z | 2 bytes | * |
0x32 | Camera Path Points | L x 12 bytes | * |
Camera Path Point Structure p (*point/trans location relative to parent zone location) | |||
0x32 + (p x 12) + 0x0 | Point X/Camera Trans X | 2 bytes | * |
0x32 + (p x 12) + 0x2 | Point Y/Camera Trans Y | 2 bytes | * |
0x32 + (p x 12) + 0x4 | Point Z/Camera Trans Z | 2 bytes | * |
0x32 + (p x 12) + 0x6 | Camera Rotation X | 2 bytes | * |
0x32 + (p x 12) + 0x8 | Camera Rotation Y | 2 bytes | * |
0x32 + (p x 12) + 0xA | Camera Rotation Z | 2 bytes | * |
Item 3+c+n: Entity
Offset | Field | Size | Value |
---|---|---|---|
0x0 | Reserved for pointer to parent zone (entry) | 4 bytes | garbage? |
0x4 | Spawn Configuration Flags | 2 bytes | * |
0x6 | Object Process Type | 2 bytes | * |
0x8 | ID | 2 bytes | * |
0xA | Path Point Count | 2 bytes | L |
0xC | Mode Flags A (or initial Y rot) | 2 bytes | * |
0xE | Mode Flags B (or initial X rot) | 2 bytes | * |
0x10 | Mode Flags C (or initial Z rot) | 2 bytes | * |
0x12 | Object Type | 1 byte | * |
0x13 | Object Subtype | 1 byte | * |
0x14 | Object Path Points | L x 6 bytes | * |
Object Path Point Structure p | |||
0x14 + (p x 6) + 0x0 | Point X | 2 bytes | * |
0x14 + (p x 6) + 0x2 | Point Y | 2 bytes | * |
0x14 + (p x 6) + 0x4 | Point Z | 2 bytes | * |
end | |||
0x14 + (L x 6) | unknown? | 2 bytes if L = 1, otherwise 4 | 0x0 |
Structure
TBD: zonecollisions, entity
struct zoneheader
{
unsigned long worldcount;
wgeomodel world[8];
unsigned long headercount;
unsigned long campathcount;
unsigned long entitycount;
unsigned long neighborcount;
union
{
entry *neighbor[8];
unsigned long neighboreid[8];
};
unsigned long tpagecount;
unsigned long tchunkcount;
unsigned long tpage[8];
unsigned long tchunk[32];
unsigned long loadflags;
unsigned long vramfillh;
unsigned long unknownA;
unsigned long visibilitydepth;
unsigned long unknownB;
unsigned long unknownC;
unsigned long unknownD;
unsigned long unknownE;
unsigned long flags;
unsigned long deathy;
unsigned long unknownF;
unsigned long unknownG;
unsigned long unknownH;
unsigned char vramfillr;
unsigned char vramfillg;
unsigned char vramfillb;
unsigned char unused_a;
unsigned char farcolorr;
unsigned char farcolorg;
unsigned char farcolorb;
unsigned char unused_b;
struct slightmatrix objectlightmatrix;
struct scolor objectcolor;
struct scolormatrix objectcolormatrix;
struct scolor objectlightintensity;
struct slightmatrix playerlightmatrix;
struct scolor playercolor;
struct scolormatrix playercolormatrix;
struct scolor playerlightintensity;
};
struct zonepathdescriptor
{
unsigned char relation;
unsigned char neighborzoneindex;
unsigned char campathindex;
unsigned char goal;
};
struct zonecampathpoint
{
signed short x;
signed short y;
signed short z;
signed short rotx;
signed short roty;
signed short rotz;
};
struct zonecampath
{
unsigned long slsteid;
union
{
entry *parentzone;
unsigned long parentzoneeid;
}
unsigned long neighborpathcount;
struct zonepathdescriptor neighborpathdescriptor[4];
unsigned char entranceindex;
unsigned char exitindex;
unsigned short length;
unsigned short cammode;
signed short avgptdist;
signed short camzoom;
unsigned short unknownA;
unsigned short unknownB;
unsigned short unknownC;
struct svector direction;
struct zonecampathpoint point[];
};
Zone Dimensions/Collision Octree
Collision Octree
Each node in the zone's collision octree, except for the root node, is the child of a parent node. Each parent node has either 8, 4, or 2 children nodes.
Each node corresponds to a portion of 3-dimensional space occupied by the zone. The root node corresponds to the entire region of space occupied by the zone (specified at offsets 0x0 to 0x14). Each child node corresponds to a separate subdivision of the space occupied by its parent. The location and dimensions of a subdivision respectively vary based on the corresponding node's index among its siblings and its depth within the tree.
In relation to its corresponding node's parent's associated region of space, a subdivision can be any region resulting from an even partitioning by any combination of 1 to 3 coordinate axis-aligned hyperplanes:
- Upper left front, upper left back, lower left front, lower left back, upper right front, upper right back, lower right front, or lower right back octant
- Upper left, Lower left, Upper right, Lower right, Front left, Back left, Front right, Back right, Upper front, Upper back, Lower front, or Lower back quadrant
- Left, right, top, bottom, front, or back half
Thus, if a node's parent's associated region of space were split in half along a line parallel to either the x, y, or z axis, then optionally split in half along a line parallel to either one of the remaining axes, and then optionally split in half along a line parallel to the remaining axis, the node's associated region of space could be any of either the resulting halves, quadrants, or octants. In these terms, 3 factors determine the location and dimensions of a subdivision: the number of split lines (1 to 3), the respective axes/axis parallel to those/that split line(s) (x and/or y and/or z), and the number/index of the resulting half, quadrant, or octant that encompasses its space.
For any parent node with depth less than the minimum of the respective maximum x, y, and z depths (specified at offsets 0x1E,0x20,0x22), 3 split lines-each respectively parallel to the x, y, and z axes-determine the 8 octants that, respectively, encompass its children's corresponding subdivisions of space. For the children of parent nodes with a depth greater than or equal to the minimum, the split line(s) parallel to the axis/axes for which is/are specified that minimum are eliminated when determining the corresponding subdivisions. For the children of parent nodes with a depth greater than or equal to the second minimum, i.e. the minimum of the remaining 2 maximums (if any), the respective split lines parallel to the axes for which are specified the minimum and second minimum are eliminated when determining the corresponding subdivisions. The maximum of the 3 maximum depths determines the height of the tree.
For example, suppose maximum depth x were the minimum of the maximum depths-3, for example. Suppose also that maximum depth z were the second minimum-7, for example. For any parent node with depth less than 3, each of its children's corresponding subdivisions is a separate octant of its (the parent's) associated region of space. For any parent node with depth greater than or equal to 3 but less than 7, the x split line is eliminated in determining the subdivisions of its associated region-thus, it is only split in half y-wise and z-wise; equivalently, it is only split into 4 quadrants-an upper front, lower front, upper back, and lower back quadrant. Such a parent node could then have only 4 children, each respectively corresponding to a separate one of the 4 subdivisions/quadrants. For any parent node with depth greater than or equal to 7, the x and z split lines are eliminated in determining the subdivisions of its associated region-thus, it is only split in half y-wise; equivalently, it is only split into 2 halves-a left half and a right half. Such a parent node could then have only 2 children, each respectively corresponding to a separate one of the 2 subdivisions/halves.
- Parent nodes with depth less than the minimum have 8 children-but only if the minimum is nonzero.
- If a unique minimum [max] depth of 0 is specified for only one of the 3 axes, parent nodes with depth less than the second minimum have 4 children.
- If a minimum depth of 0 is specified for 2 of the 3 axes, all parent nodes have 2 children.
- If a minimum depth of 0 is specified for all axes, the tree is empty.
- Parent nodes with depth greater than or equal to the minimum and less than the second minimum(if it exists) have 4 children-but only if the minimum is unique.
- If the same minimum depth is specified for 2 of the 3 axes, parent nodes with depth greater than or equal to the minimum have 2 children.
- If the same nonzero minimum/maximum depth is specified for all axes-that is, there does not exist a second minimum-then all parent nodes have 8 children.
- Parent nodes with depth greater than or equal to the second minimum have 2 children-but only if the [first] minimum or second minimum is unique.
- Height of the tree is given by the maximum [of the max] depth(s).
Octree Node Format
Each node in the octree is specified as an unsigned short (2 bytes). The relative offset of the root node within the item is specified at offset 0x1C.
Internal/parent nodes
Internal/parent nodes are indicated by a cleared LSB (least significant bit); consequently, their [nonzero] value refers to the relative offset of [the first of] their children in the item. Child nodes are stored contiguously as groups of 8, 4, or 2. The cardinality and arrangement of a parent's group of child nodes depends on its depth in relation to the axis associated maximum depths:
Parent Depth Condition | Children Group [format/arrangement] | A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
---|---|---|---|---|---|---|---|---|---|
(d < min) && max
|
AA AA BB BB CC CC DD DD EE EE FF FF GG GG HH HH
|
ULF | ULB | DLF | DLB | URF | URB | DRF | DRB |
cond = (d >= min && d < min2 && min != min2)
| |||||||||
cond && min == maxx
|
AA AA BB BB CC CC DD DD
|
UL | UR | DL | DR | n/a | n/a | n/a | n/a |
cond && min == maxy
|
AA AA BB BB CC CC DD DD
|
LF | LB | RF | RB | n/a | n/a | n/a | n/a |
cond && min == maxz
|
AA AA BB BB CC CC DD DD
|
UF | UB | DF | DB | n/a | n/a | n/a | n/a |
cond = (d >= min2 && (min != min2 || min2 != max)) [|| (d >= min && (min == min2 || min2 == max)) ]
| |||||||||
cond && min2 == maxx
|
AA AA BB BB
|
L | R | n/a | n/a | n/a | n/a | n/a | n/a |
cond && min2 == maxy
|
AA AA BB BB
|
top | bot | n/a | n/a | n/a | n/a | n/a | n/a |
cond && min2 == maxz
|
AA AA BB BB
|
F | B | n/a | n/a | n/a | n/a | n/a | n/a |
- The Parent Depth Condition column lists conditions under which a parent node's contiguous group of children have the associated formats. Only the bolded conditions are relevant if max depths are unique. The following symbols are used for brevity:
d
= parent node depthmax*
= max depth *M
= {max*
} (for*
=x
,y
,z
)min
=min(M)
min2
=min(M - {min})
max = max(M)
- The Children Group column lists the arrangement or byte format of the parent's group of child nodes; depending on conditions, there are either 8 children [A-H], 4 children [A-D], or 2 children [A-B] in the group.
- Each of the A-H columns identifies that child's corresponding subdivision with an abbreviation:
- L = left, R = right, U = upper, D = lower, F = front, B = back
Non-existent nodes
Non-existent nodes are indicated with a value of 0
. A non-existent node refers to empty space; there is nothing particularly interesting about its corresponding subdivision, since the player will never interact/collide with it.
Leaf nodes
Leaf nodes are indicated by a set LSB; the remaining 15 bits describe collision attributes for the node's corresponding subdivision:
UUUUUUSSSSSSTTT1
T
= Node typeS
= Node subtypeU
= Unknown/unused?
Node type and subtype refer to type and subtype of the node's corresponding collidable subdivision of 3 space.
Node Type
Node type determines the primary type of corresponding collidable space:
Type | Description |
---|---|
0 | Solid and Interactive |
1 | Solid Floor/Ground |
2 | Level Boundary Wall |
3 | Pit Area |
4 | Trigger Misc Death on Collision |
Node Subtype
Solid and Interactive, Pit Area, and Trigger Misc Death on Collision type nodes (types 0, 3, and 4) may optionally specify a node subtype. This subtype determines a specific event sent to the player upon collision with the node:
Subtype | Description | Event |
---|---|---|
0 | ? | ? |
1 | ? | ? |
2 | Spin, Fall Over, and Die (death sequence) | 0x700
|
3 | ? | 0xC00
|
4 | Drown | 0x2100
|
5 | Burn to Ash | 0x1F00
|
6 | Explode | 0x1E00
|
7 | ? | 0xD00
|
8 | ? | 0x1200
|
9 | ? | 0x1200
|
10 | ? | 0x1200
|
11 | ? | 0x1200
|
12 | Fall in a Hole and Die | 0x900
|
13 | ? | 0x2300
|
It is yet to be determined whether there are additional subtypes with other purposes.
Camera Paths
In each game, the camera follows behind the player as it makes progress towards the goal. The camera, too, along with the player, makes progress towards the goal, albeit somewhat less advanced but at the same rate; thus, the player's progress within the level and the camera's progress within the level are directly related. In each game, the camera appears to travel a fixed path as it follows behind the player, zooming and panning accordingly.
A zone typically includes one or more connected paths along which the camera is to travel as the player character makes progress within that zone. As a whole, all paths [of all zones] in the level connect to form a central path from the initial player location to the goal, with possibly several divergences at any arbitrary point(s). Each divergence may or may not converge back into to the central path to trace out an alternate route.
Path Points
Each path is composed of a number of closely positioned points that typically trace out an approximate line or smooth curve. Each point corresponds to a position of the camera, and is also associated with a camera orientation. The line or curve traced by a path connects its points in sequence, where points in the path are stored sequentially. Path points are commonly referred to as progress points.
- When the camera is at a point in a path, it is positioned at the location of that point and oriented according to the point's associated orientation.
- After the camera moves from the point that it is currently at to another point in the path, it will be at that other point.
- To move along a path, or move further into its trail, the camera moves from one point on the path to the next, and so on, until it reaches [is at] some desired destination point.
Path Progression
As the player makes progress within a zone, the camera consequently makes progress along the paths in that zone, thus keeping up with the player. As the camera progresses further along a path, it moves further into the path's trail. At any point on the path, by moving to the next point, the camera will have progressed one point further. The camera can progress from one point on the path to the next, and so on, until it reaches a desired destination point. The amount of progress made by the camera in a complete progression is the number of points that it has progressed further.
If the camera begins at the first point in a path and progresses to the nth point, it will have made an amount of progress equal to 1 point less than n. For example, if the camera begins at the first point in a path and progresses to the first point=1st/th point (n=1), then it will have made an amount of progress equal to 1-1=0 (no progress at all). The length of a path is just the number of points that it contains. If the camera begins at the first point in a path and progresses to the last point, it will have made an amount of progress equal to 1 less than the length of the path. The index of a [zero-indexed] path point is equivalent to the amount of progress that the camera will have made [after moving from the beginning/first point] at that point within the path. Thus, each [progress] point is indexed by its corresponding progress value.
Path Retrogression
Nothing prevents the player from retrogressing within a zone [unless it is at the initial entry point]; the player may return all the way back to its initial entry point in the first zone if it wishes. As the player retrogresses within a zone, its progress will rewind, as it is counterbalanced by a subtraction in amount. The camera consequently must retrogress along with the player for its continued viewing. As the camera retrogresses along a path, it moves back towards the beginning of (i.e the first point in) the path's trail. At any point on the path, by moving to the previous point, the camera will have retrogressed one point back towards the beginning. The camera can retrogress from a point on the path to its previous point, and so on, until it reaches any desired destination point that is closer to the beginning of the path's trail. The amount of progress lost by the camera in a complete retrogression is the number of points that it has retrogressed.
Retrogressing too close - problem
At any point on the path, by moving to the previous point, the camera will have retrogressed one point back towards the beginning. However, at the first point, the camera is already at the beginning, and there is no previous point to move to within that path. At the first point on that path, the camera's current progress will be 0, as it has not progressed to any point further. If the camera were to retrogress any closer back to the initial entry point [in the first zone] from [its current position at] the beginning of (i.e. the first point within) the path, its current progress would decumulate to become (1 less than 0 =) -1. However, this refers to an invalid point index; there does not exist a point with this index (i.e. one point before the first point) at which the camera could be positioned.
Progressing too far - problem
At any point on the path, by moving to the next point, the camera will have progressed one point further. However, at the last point, there is no next point to move to within that path. At the last point on that path, the camera's current progress will be 1 less than the length of the path-i.e. the index of the last point on the path. If the camera were to progress any further past [its current position at] the end of (i.e. the last point within) the path, its current progress would accumulate to become (1 less than the length of the path + 1 =) the length of the path. Path points are zero-indexed, however, so this would refer to an invalid point index; there does not exist a point with this index (i.e. one point past the last point) at which the camera could be positioned. If the path were extended past its current last point, this would be a valid index-that of a point that continued the path.
Neighbor Paths - solution
Even unextended, the path still actually does continue past its last point. Recall that several paths in a zone can be connected: a single path may reference one or more connected neighboring paths. A path's neighboring paths may be:
- any path in its parent zone, other than itself
- any path in any of its parent's neighboring zones
Each of a path's neighboring paths contain either points that continue the path past its last point, or points that retrogress before its first point. The path's own points are a retrogression of the neighbor path [points] that continue past its last point, and are a continuation of the neighbor path [points] that retrogress before its first point.
Progressing too far - solution
When the camera reaches the [invalid] progress that is an invalid index of a point that would be one point past the last point in the path, the current path is changed to a neighbor path [with points] that continue(s) the path past its last point; the camera is said to have entered this path, particularly at its entrance (i.e. beginning/first point). As it has only just reached the beginning of/first point in this connected path, the camera's current progress along that path is also set to 0 (index of first point). The camera can then continue to progress within that path as necessary along with the player, just as it had done in the previous path.
Retrogressing too close - solution
When the camera reaches the [invalid] progress that is an invalid index of a point that would be one point before the first point in the path, the current path is changed to a neighbor path [with points] that retrogress(es) from the path before its first point; the camera is said to have re-entered this path, particularly, at its exit (i.e. end/last point). As it has re-entered the connected path at its exit point, the camera's current progress along that path is also set to 1 less than its length (index of last point). The camera can then continue to retrogress within that path as necessary along with the player, just as it had done in the previous path.
Specification
A path specifies up to 4 neighboring paths by including the following information for each path:
- The zone that contains the neighboring path
- The index of the neighboring path within that zone
- Whether the neighboring path, in relation to this path, is a continuation or a retrogression
- A continuation indicates that the neighboring path is closer to the goal than this path
- A retrogression indicates that the neighboring path is further from the goal than this path
- Whether the neighboring path, from the perspective of the player as it faces in the direction of the goal, is:
- In front of the path
- Behind the path
- Above/Below the path
Divergence and Convergence
More than one of a path's neighbors can be either a continuation or a retrogression of the path. Each is either an alternate continuation or retrogression of the path and equivalently either a divergence or convergence from/into the path. For example, at the beginning of the split in route towards the end of N. Sanity Beach, there is a path with 3 neighbors: one a retrogression (the path that leads into it), and the other 2 continuations the left and right branches, respectively, of the path. Right before the goal, the 2 branches meet up again, converging to a singular central path; the point of convergence is of a path with 3 neighbors: one a continuation, which is the final path of all paths in all zones of the level, whose last point is located right behind the goal, and the other 2 retrogressions the left and right branches, respectively, that lead into the path.
Additional Parameters
Each camera path includes the following additional information:
- [Polygon] Sort list
- Parent zone
- Camera mode
- Camera zoom/pan factor
- Length of the path
- Alternate entrance and exit point relative indices
- Average distance between each path point
- Approximate direction of the path (a unit vector)
Average distance between each path point and approximate direction of the path are used to convert the camera's location within the level to a progress along the path. The camera typically has an idea of how much it should move from its current location to keep up with the player, but not in terms of how much it should progress along the path. Usually the camera would like to move to a location that lies outside of the path, but can not since its movement is restricted following along that path. Thus, the scalar projection of the camera's desired, unprojected location onto a linear approximation of the path (i.e. path direction) is computed to determine its approximate projected location or distance along the path. This distance is then divided by the average distance between each path point to determine its actual progress along the path.
Purposes of the other fields are explained elsewhere (See: camera update routine TBD).