Zone
Contents
Format
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 | Texture Chunk CID Count | 4 bytes | t |
0x23C | Texture Page Entry EIDs | 8 x 4 bytes | * |
0x25C | Texture 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 | Far Color R | 1 byte | * |
0x315 | Far Color G | 1 byte | * |
0x316 | Far Color B | 1 byte | * |
0x317 | unused | 1 byte | * |
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) + 0x0 | unknown? | ? bytes | ? |
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/Octree
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 && (maxx != maxy && maxx != maxz)
|
AA AA BB BB CC CC DD DD
|
UL | UR | DL | DR | n/a | n/a | n/a | n/a |
cond && min == maxy && (maxy != maxx && maxy != maxz)
|
AA AA BB BB CC CC DD DD
|
LF | LB | RF | RB | n/a | n/a | n/a | n/a |
cond && min == maxz && (maxz != maxx && maxz != maxy)
|
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
|
U | D | 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.