Collision Format (Scenes)

From CloudModding OoT Wiki
(Redirected from Collision Format)
Jump to: navigation, search

Header

Format:

bbbbcccc ddddeeee ffffgggg vvvv0000
aaaaaaaa pppp0000 llllllll tttttttt
xxxxxxxx wwww0000 mmmmmmmm
Variable Index Description
b 0x00 Absolute minimum along the x-axis for collision vertices
c 0x02 Absolute minimum along the y-axis for collision vertices
d 0x04 Absolute minimum along the z-axis for collision vertices
e 0x06 Absolute maximum along the x-axis for collision vertices
f 0x08 Absolute maximum along the y-axis for collision vertices
g 0x0A Absolute maximum along the z-axis for collision vertices
v 0x0C Number of vertices to load
a 0x10 Segment offset of vertex array
p 0x14 Number of polygons to load
l 0x18 Segment offset of polygon array
t 0x1C Segment offset of polygon type definitions
x 0x20 Segment offset of camera data*
w 0x24 Number of water boxes*
m 0x28 Segment offset of water boxes*

* = optional, set to 0 if it's not needed.

Vertex Array

Each vertex in the array is of the following structure:

/* 0x00 */ s16 x; //Position on x-axis
/* 0x02 */ s16 y; //Position on y-axis
/* 0x04 */ s16 z; //Position on z-axis

Polygon Array

/* 0x00 */ s16? //Polygon Type
/* 0x02 */ s16? //Vertex a (& 0xFFF)
/* 0x04 */ s16? //Vertex b (& 0xFFF)
/* 0x06 */ s16? //Vertex c (& 0xFFF)
/* 0x08 */ s16? //Normal's x-direction (7FFF being 1.0)
/* 0x0A */ s16? //Normal's y-direction (7FFF being 1.0)
/* 0x0C */ s16? //Normal's z-direction (7FFF being 1.0)
/* 0x0E */ s16? //Collision plane's distance from origin

The unit vector normal is expressed as (a,b,c) => ax + by + cz + d = 0, (x,y,z) is point from polygon, d is distance from origin

See collision normals for a code snippet that preforms normal calculation.

Polygon Types

aabbbxcc #w#hkels (repeats for each polygon type)
a = Object set switcher, maybe?  Or instantaneous exit?
Bit 0: Nothing by itself?
Bit 1: Nothing by itself?
Bit 2: Nothing by itself?; 2 + 3 trigger exit immediately (Link stops walking)
Bit 3: Nothing by itself?; 2 + 3 trigger exit immediately (Link stops walking)
Bit 4 through 7 define the object set/exit number, it appears, where illegal values result in nothing happening (game continues as normal).
b = Special Effect Flags
Bit 0: Climbable; 0 + 2 makes Child Link enter crawling mode (only works in center of polygon; can be glitchy if done improperly)
Bit 1: Prevents 0 from working (sometimes climbable; may produce different noise; if so, then 1 + 2 + 3 enters climb-down mode); 1 + 2 enters climb- down mode (used on ladders so Link positions himself properly when approaching from the other side)
Bit 2: Prevents 0 from working; 0 + 1 + 2 makes Link able to grab the surface
Bit 3: Nothing by itself; part of climbable/grabbable/crawlable combos above
Bit 4: Nothing?
Bit 5: Nothing?
Bit 6: Prevents 7 from working?
Bit 7: Jabu-Jabu reaction if struck
Bit 8: Out of Bounds (Link screams, level restarts)
Bit 9: Damages Link (can be slowed by the Goron Tunic)
Bit 10: Nothing?
Bit 11: Warp Transition (must be paired with exit number, otherwise crashes)

If set to 00C : Link can't take Falling Damage.

If set to 006 : Lava/Goo

x = Exit trigger (set it to the exit number as loaded in the scene; values over the defined amount will crash the game); 0 disables trigger
c = Camera view angle
0 Default distance and behavior (same as 5, actually)
1 Extremely high birds-eye view
2 Same
3 Camera follows Link at a close distance
4: Camera follows Link further away
5: Camera stays at a moderate distance away from Link (less than 4, more than 3)
6+: Similar to 5, but at a slightly higher angle
w = Special effects (for walls only)
Bit 1: Damages Link
Bit 2: Nothing?
Bit 3: Nothing?
Bit 4: Nothing?
h = Hookshot
Bit 1: Nothing?
Bit 2: Nothing?
Bit 3: Hookshotable
Bit 4: Nothing?
k = Echo (overrides map)
0: Use map value
1-F: Echo ranges
e = Ambient lighting/color/fog effect (only works if fog or environment fog is enabled)
0: Normal
1: Fog becomes turquoise and intensifies to max; can trigger overflow which trips the z-buffer
2: Fog disappears, z-buffering fails and actors get a green tint
3: Fog disappears, z-buffering fails and actors go black
4: Fog becomes black and intensifies to max; can trigger overflow which trips the z-buffer; blue sometimes seeps in
5: Fog fades almost immediately to black; z-buffering might fail; actors are completely black
6: Everything goes black except collision polygons...?
7: Everything goes black, but graphics are rendered properly
8-F are the same as 0-7.
l = Terrain type (note: the hues only appear if fog or environment fog is enabled)
0: Walkable
1: High angle (Link immediately begins to slide)
2: Walkable
3: Walkable
4: Ambient light dims, reddish hue?
5: Ambient light dims, reddish hue, Link begins to slide
6: Ambient light dims, reddish hue
7: Ambient light dims, reddish hue
8: Ambient light dims, blackish
9: Ambient light dims, blackish, Link begins to slide
A: Ambient light dims, blackish
B: Ambient light dims, blackish
C: Ambient light dims slightly with a bit of red
D: Ambient light dims slightly with a bit of red, Link begins to slide
E: Ambient light dims slightly with a bit of red
F: Ambient light dims slightly with a bit of red
s = Sound effect/ground type
0: Earth/dirt
1: Sand
2: Stone
3: Wet stone
4: Shallow water
5: Not-as-shallow water (lower-pitched sound)
6: Underbrush/grass
7: Lava/goo
8: Earth/dirt
9: Wooden plank
A: Packed earth/wood
B: Earth/dirt
C: Ceramic
D: Loose earth
E: Earth/dirt
F: Earth/dirt

Camera Data

xxxx yyyy zzzzzzzz
x = Unknown
y = Unknown
z = Offset of skybox camera position data.

Skybox Camera Position

xxxx yyyy zzzz aaaa bbbb cccc dddd FFFFFFFF

x = x coordinate
y = y coordinate
z = z coordinate
a = x rotation
b = y rotation
c = z rotation
d = Unknown. (zoom?)

Water

xxxxyyyy zzzzssss rrrr0000 0000qqqq (repeats for each water box)
Note: water is bottomless
Note2: water actors may take over some of the properties described here, such as the level of the top surface.
x = x minimum coordinite for water
y = top surface of water's height.
z = z minimum coordinite for water
s = x size of water
r = z size of water
q = water properties(camera effects?):
0100 = "normal water" I reccomend this variable
0102 = seems to be the same as 0100
0105 = Camera flys off and goes to a random spot?

Credits

MNGoldenEagle/JSA for mostly everything. Water was figured out by spinout. JSA has figured out some of the camera data, but the documentation has been lost AFAIK. However, some documentation on camera data has been released by DeathBasket.

ZHC Collision

// -*- mode: c;-*-
typedef struct {
    local string thisName = "ZHC_CollisionWaterBox";
    SIBE;
    SIT;
    short minX;
    SIT;
    short topY;
    SIT;
    short minZ;
    SIT;
    short sizeX;
    SIT;
    short sizeZ;
    SIT;
    ubyte zeroes[4];
    AssertUBytesNull(zeroes, thisName);
    SIT;
    enum <short> WATER_PROPS {
        WATER_PROP_NORMAL       = 0x0100,
        WATER_PROP_ABNORMAL     = 0x0102,
        WATER_PROP_CAMERAFUCKER = 0x0105,
    } maybeWaterPropertiesOrCameraEffects;
    /*
    AnomEnum( 
        EnumToString( maybeWaterPropertiesOrCameraEffects ),
        maybeWaterPropertiesOrCameraEffects,
        thisName+"->maybeWaterPropertiesOrCameraEffects"
    );
    */
} ZHC_CollisionWaterBox;

typedef struct {
    SIBE;
    SIT;
    ushort type;
    SIT;
    ZVector verts;
    SIT;
    ZNormal normal;
    SIT;
    short displacement;
    SIEND;
} ZHC_CollisionPolyList;

/*
differences (quicksand-major):
terrain_trigger_reset_enable
terrain_hurt_fire_enable
terrain_hookshot_enable
unknown3 = 1 (else: 0)
unknown4 = 15
*/
/*
other notes (for both):
specialEffects == 1
TERRAIN_CAMERA_PROXIMITY_NOTSO_CLOSEUP
1 \ 0 \15 \ TERRAIN_SLOPE_BURGOR \ TERRAIN_SOUND_DIRT
*/

typedef struct {
    // This data closely resembles the NIFF_Mat data type (Material)
    // Specifically: ambient/primary/fog lighting and user values per-poly
    // Outside the typical "UserExpansionBlock"
    local string thisName = "ZHC_CollisionPolyTypeList";
    SIBE;

    SIT; UNK;
    ubyte unknown1 : 2;

    SIT;
    // if these two bits aren't set at the same time, instant transitions
    // do not happen
    enum <ubyte> TERRAIN_TRIGGER_TRANSITION {
        TERRAIN_TRIGGER_TRANSITION_DESERTLOST = 0x3
    } do_trigger_transit : 2;

    SIT;
    ubyte obj_set_or_exit_number : 4;

    // == milestone: 8 bits

    SIT;
    enum <ubyte> TERRAIN_HANDS {
        TERRAIN_HANDS_DO_NOTHING   = 0x0, // 0 0 0 0
                                          // 0 0 0 1 0x1 ?
                                          // 0 0 1 0 0x2 ?
                                          // 0 0 1 1 0x3 ?
                                          // 0 1 0 0 0x4 ?
                                          // 0 1 0 1 0x5 ?
        TERRAIN_HANDS_CLIMB_DOWN   = 0x6, // 0 1 1 0
        TERRAIN_HANDS_CLIMB_DOWN2  = 0x7, // 0 1 1 1
        TERRAIN_HANDS_ALLOW_CLIMB  = 0x8, // 1 0 0 0
                                          // 1 0 0 1 0x9 ?
        TERRAIN_HANDS_ALLOW_CRAWL  = 0xA, // 1 0 1 0
                                          // 1 0 1 1 0xB ?
                                          // 1 1 0 0 0xC ?
                                          // 1 1 0 1 0xD ?
        TERRAIN_HANDS_GRAB_SURFACE = 0xE, // 1 1 1 0
                                          // 1 1 1 1 0xF ? 
    } climbability : 4;

    SIT; UNK;
    ubyte unknown2 : 2;

    SIT;
    // the first bit impedes the second bit
    enum <ubyte> TERRAIN_ANGER_JABBU {
        TERRAIN_ANGER_JABBU_DISABLE = 0x0,
        TERRAIN_ANGER_JABBU_ENABLE  = 0x1,
    } do_anger_jabbu : 2;

    // == milestone: 16 bits

    SIT;
    enum <ubyte> TERRAIN_TRIGGER_RESET {
        TERRAIN_TRIGGER_RESET_DISABLE = 0x0,
        TERRAIN_TRIGGER_RESET_ENABLE  = 0x1,
    } do_out_of_bounds_reset : 1;

    SIT;
    // the second half of this is only used for quicksand?
    enum <ubyte> TERRAIN_HURT_FIRE {
        TERRAIN_HURT_FIRE_DISABLE = 0x0,
        TERRAIN_HURT_FIRE_ENABLE  = 0x1,
        TERRAIN_HURT_FIRE_DISABLE2= 0x2,
        TERRAIN_HURT_FIRE_ENABLE2 = 0x3,
    } do_trigger_hurt_fire : 2;

    SIT;
    // if exitTrigger isn't a valid exit then enabling this will crash
    enum <ubyte> TERRAIN_WARP {
        TERRAIN_WARP_DISABLE = 0x0,
        TERRAIN_WARP_ENABLE  = 0x1,
    } do_warp : 1;

    SIT;
    // 0 == disabled, exit to jump to if this poly triggers one
    ubyte exitTrigger : 4;

    // == milestone: 24 bits

    SIT;
    // anything above 6 is just a higher angle of 5
    enum <ubyte> TERRAIN_CAMERA_PROXIMITY {
        TERRAIN_CAMERA_PROXIMITY_NORMAL         = 0x00,
        TERRAIN_CAMERA_PROXIMITY_HIGHBIRDSEYE   = 0x01,
        TERRAIN_CAMERA_PROXIMITY_HIGHBIRDSEYE2  = 0x02,
        TERRAIN_CAMERA_PROXIMITY_CLOSEUP        = 0x03,
        TERRAIN_CAMERA_PROXIMITY_NOTSO_CLOSEUP  = 0x04,
        TERRAIN_CAMERA_PROXIMITY_NORMAL2        = 0x05, // same as 0x5
        TERRAIN_CAMERA_PROXIMITY_HIGHER         = 0x06,
        TERRAIN_CAMERA_PROXIMITY_PROBABLYUNUSED = 0xFF,
    } camera_modifier;

    // == milestone: 32 bits

    /*
    AnomEnum( 
        EnumToString( camera_modifier ),
        camera_modifier,
        thisName+"->camera_modifier"
    );
    */
    SIT; UNK;
    ubyte unknown3 : 4;

    SIT;
    enum WALLS_HURT {
        WALLS_HURT_DISABLE = 0,
        WALLS_HURT_ENABLE  = 1,
    } do_walls_hurt : 1;

    SIT; UNK;
    ubyte unknown4 : 3;

    // == milestone: 40 bits

    SIT; UNK;
    ubyte unknown5 : 4;

    SIT; UNK;
    ubyte unknown6 : 2;

    SIT;
    enum TERRAIN_HOOKSHOT {
        TERRAIN_HOOKSHOT_DISABLE = 0x0,
        TERRAIN_HOOKSHOT_ENABLE  = 0x1,
    } hookshot : 1;

    SIT; UNK;
    ubyte unknown7 : 1;

    // == milestone: 48 bits

    SIT;
    // Presumably, this is for trick walls that are 
    // bombable or metal surfaces.
    // WILL *OVERRIDE* SCENE ECHO SETTING
    ubyte impact_sound_echo : 4;

    SIT; UNK;
    // this and the next unknown composed ambient settings
    ubyte unknown8 : 4;

    // milestone: 56 bits
    
    SIT; UNK;
    ubyte unknown9 : 2;

    SIT;
    // this spans 2 bits because of how it wraps,
    // only TERRAIN_SLOPE_ENABLE triggers sloping(?)
    enum TERRAIN_SLOPE {
        TERRAIN_SLOPE_DISABLE = 0x0,
        TERRAIN_SLOPE_ENABLE  = 0x1,
        TERRAIN_SLOPE_HOTDOG  = 0x2,
        TERRAIN_SLOPE_BURGOR  = 0x3,
    } slope : 2;

    SIT;
    // this is footstep sounds, but also the sound it makes
    // if struck with a sword
    enum TERRAIN_SOUND {
        TERRAIN_SOUND_DIRT                  = 0x0,
        TERRAIN_SOUND_SAND                  = 0x1,
        TERRAIN_SOUND_STONE_DRY             = 0x2,
        TERRAIN_SOUND_STONE_WET             = 0x3,
        TERRAIN_SOUND_WATER_SHALLOW         = 0x4,
        TERRAIN_SOUND_WATER_DEEP            = 0x5,
        TERRAIN_SOUND_GRASS                 = 0x6,
        TERRAIN_SOUND_LAVA_OR_GOO           = 0x7,
        TERRAIN_SOUND_DIRT2                 = 0x8,
        TERRAIN_SOUND_WOOD_PLANK            = 0x9,
        TERRAIN_SOUND_DIRT_PACKED_OR_WOOD   = 0xA,
        TERRAIN_SOUND_DIRT3                 = 0xB,
        TERRAIN_SOUND_CERAMIC               = 0xC,
        TERRAIN_SOUND_DIRT_LOOSE            = 0xD,
        TERRAIN_SOUND_DIRT4                 = 0xE,
        TERRAIN_SOUND_DIRT5                 = 0xF,
    } terrainSound : 4;

    // milestone: 64 bits
} ZHC_CollisionPolyTypeList;

typedef struct {
    local string thisName = "ZHC_CollisionHeader";
    SIBE;
    SIT;
    ZVector min;
    SIT;
    ZVector max;
    SIT;
    ushort numVerts;
    SIT;
    ubyte zeroes1[2];
    AssertUBytesNull(zeroes1, thisName);
    SIT;
    ZBankPointer vertArrayOffset;
    if( vertArrayOffset.zb.bankNo == bankType ){
        SAVE;
        FSeek(headerStart + vertArrayOffset.offset);
        ZVector verts[numVerts];
        REST;
    } else {
        Assert( 0, "External Bank" );
    }
    SIT;
    ushort numPolys;
    SIT;
    ubyte zeroes2[2];
    AssertUBytesNull(zeroes2, thisName);
    SIT;
    ZBankPointer polyArrayOffset;
    if( polyArrayOffset.zb.bankNo == bankType ){
        SAVE;
        FSeek(headerStart + polyArrayOffset.offset);
        struct {
            ZHC_CollisionPolyList polys[numPolys]<optimize=false>;
        } AllThesePolyLists;
        REST;
    } else {
        Assert( 0, "External Bank" );
    }
    SIT;
    ZBankPointer polyTypeArrayOffset;
    if( polyTypeArrayOffset.zb.bankNo == bankType ){
        SAVE;
        FSeek(headerStart + polyTypeArrayOffset.offset);
        struct {
            ZHC_CollisionPolyTypeList polyTypes[numPolys]<optimize=false>;
        } AllThesePolyTypeLists;
        REST;
    } else {
        Assert( 0, "External Bank" );
    }
    SIT;
    ZBankPointer cameraDataOffset; //if not zeroes
    if( cameraDataOffset.zb.bankNo == bankType ){
        SAVE;
        FSeek(headerStart + cameraDataOffset.offset);
        ZHC_AltCamera cameraData;
        REST;
    } else {
        Assert( 0, "External Bank" );
    }
    SIT;
    ushort numWaterBoxes; //if not zeroes
    SIT;
    ubyte zeroes3[2];
    AssertUBytesNull(zeroes3, thisName);
    
    SIT;
    ZBankPointer waterBoxArrayOffset;
    if( numWaterBoxes ){
        if( waterBoxArrayOffset.zb.bankNo == bankType ){
            SAVE;
            FSeek(headerStart + waterBoxArrayOffset.offset);
            struct {
                ZHC_CollisionWaterBox waterBoxes[numWaterBoxes]<optimize=false>;
            } AllTheseWaterBoxes;
            REST;
        } else {
            Assert( 0, "External Bank" );
        }
    }
    SIEND;
} ZHC_CollisionHeader;

typedef struct {
    local string thisName = "ZHC_CollisionHeader";
    SIBE;
    SIT;
    ubyte command;
    AssertNumberEquals(command, 0x03, thisName);

    SIT;
    ubyte zeroes[3];
    AssertUBytesNull(zeroes, thisName);
    
    ZBankPointer listOffset;
    if( listOffset.zb.bankNo == bankType ){
        SAVE;
        FSeek(headerStart + listOffset.offset);
        ZHC_CollisionHeader collisionHeaders;
        REST;
    } else {
        Assert( 0, "External Bank" );
    }
    SIEND;
} ZHC_CollisionList;
(Source: DerrikeG)