Water boxes
Users browsing this thread: 1 Guest(s)

I haven't seen any in-depth information about SM64's water boxes on the web anywhere, so I thought it would be helpful to have a thread about them.

Generally speaking, when I say "water box" I am referring to a boxed region in the level that might have some effect on Mario. This is mostly used for water, which makes Mario go into his swimming state. That is why I refer to them as water boxes. They are also used for mist in JRB, which does nothing to Mario, and the toxic haze in HMC which slowly drains Mario's health.

To add a water box in a level, you need to setup both the collision and the visual part. I'll be using the castle grounds level data as an example.

Setting up the collision

The collision for water boxes is defined as part of the Level script 0x2E command loading routine. The sub-routine is pretty simple and straight forward, as the first two bytes after [00 44] is just the number of water boxes to be loaded. Then every 12 bytes will define the properties of the collision for that water box.

00 44 // Start defining water boxes
00 02 // Number of water boxes to be loaded.
00 00 E4 27 E3 CA 20 3D FF C6 FF AF // Water box 1 collision data
00 01 04 00 FF C6 20 26 1F C9 FF AF // Water box 2 collision data

struct WaterBoxCollision { 
     s16 id; // id that is used to link to the visual part of water box.
     s16 x1; // x coordinate of first end-point 
     s16 z1; // z coordinate of first end-point 
     s16 x2; // x coordinate of second end-point 
     s16 z2; // z coordinate of second end-point 
     s16 y;  // y coordinate representing how tall the water box should be

The id also defines what the water box will do. If the id is smaller than 0x32, then it will be water. If the id is equal to 0x32 or 0xF0, then it will be toxic haze. If it's greater than 0x32 and is not a toxic haze value like 0xF0, then it will have no effect on Mario. The lava box inside the volcano in LLL is actually just a normal water-box that you can't touch due to an invisible lava-collision floor. If you raise the height of the water box, then you can freely swim around inside the volcano.

[Image: Ywyl5Nc.png]

Setting up the visual part

Now comes the more complicated part of water boxes. Water boxes are drawn from one or more geo layout 0x18 commands that use the asm function 0x802D104C.

[ 18 00 XX XX 80 2D 10 4C ] 
XXXX = Hard-coded parameter, which is used to get a segmented address to the visual data (from function 0x802D0C84)

Spoiler: Parameters to choose from
0x0400 = 07026E24
0x0401 = 07026E34
0x0501 = 07016708
0x0600 = 070790F0
0x0612 = 07079100
0x0701 = 0702B900
0x0702 = 0702B950
0x0801 = 07012778
0x0851 = 070127C8
0x1001 = 0700FA70
0x1101 = 07018748
0x1102 = 07018778
0x1201 = 0700D2CC
0x1202 = 0701139C
0x1205 = 0700D304
0x1301 = 0700E31C
0x1302 = 0700E39C
0x1601 = 07011738
0x2202 = 07028780
0x2301 = 0700FCB4
0x2302 = 0700FD00
0x2401 = 07011E08
0x2601 = 07006E6C
0x3601 = 07017124

00454DC4 / 0E0007E4 [ 18 00 16 01 80 2D 10 4C ] //  Loads the water boxes in the castle grounds level

// 1601 = 07011738
0000 0000 070116F8 // Water box 1
0001 0000 07011718 // Water box 2
FFFF // End of list of water boxes

struct WaterBox { 
     s16 id; // id that is used to link to the collision of water box.
     s16 _0x02;
     u32 quad_seg_ptr; // Segmented pointer to the water box visual data. (which I refer to as "struct WaterBoxQuad")

struct WaterBoxQuad {
     s16 visibilty; // -1 = Make all water boxes in list invisible, 0 = invisible, 1 = visible
     s16 _0x02;
     s16 rotation_speed; // negative values make it rotate the opposite way.
     s16 scale; // Number of repeats in texture
     s16 x1; // X position of vertex 1
     s16 z1; // Z position of vertex 1
     s16 x2; // X position of vertex 2
     s16 z2; // Z position of vertex 2
     s16 x3; // X position of vertex 3
     s16 z3; // Z position of vertex 3
     s16 x4; // X position of vertex 4
     s16 z4; // Z position of vertex 4
     u16 rotation_direction; // 0x00 = clockwise, 0x01 = counter-clockwise. (Useless?)
     u8 _0x1A;
     u8 transparency // 0x00 = fully transparent, 0xff = fully opague
     u16 texture_id // 0 = water, 1 = mist, 2 = JRB water, 4 = lava, etc.
     u16 _0x1E;

Here you will see some familiar options if you've used water boxes in skelux's level editor tool. You can change the rotation, texture, scale, and even transparency of the texture on the quad.

You can modify the look of the castle grounds water by changing the texture_id value from 0 (water) to 2 (JRB water), but if you try to change it to the mist texture then it will look weird. Why is that?

[Image: 6LGKsbN.png] [Image: FWTqIY0.png]

The reason for the weird color texture comes from the fact your trying to render a color image (RGBA5551) using a grayscale texture (IA16). The information gets interpreted wrong and it comes out looking like a mess.

Remember those hard-coded values I mentioned above? Those also determine if the image is going to be a grayscale texture or a colored texture. The code that determines this is under the function 0x802D0F28. Basically, if the hard-coded value is equal to 0x0702, 0x0851, or 0x1205, then the texture should be a grayscale texture. Otherwise it will just be a color texture.

This does make it a huge pain to add in water boxes for our custom levels, but frauber did come up with a solution to somewhat help the issue.

Changes made with the SM64 Editor and custom levels

Instead of using a bunch of presets that return specific segmented addresses, custom levels use 3 new presets for all of their water boxes.

0x5000 = 19001800 // Water
0x5001 = 19001850 // Toxic Haze
0x5002 = 190018A0 // Mist

This simple hack makes it easy to add in water boxes into custom levels. You can find list for the WaterBoxQuad data starting at 19001C00. 

However this does cause the issue that if you add more than 9 water boxes, then you will start overwriting the data that is meant for the toxic haze. Be careful when you're making your amazing water level.

Variables, Functions, and other Segmented-Pointers

0x80361184 - Pointer to the level's water collision data. You can adjust the height of a water box in-game here.

0x802D0C84 - function that gets a segmented address to water box list from hard-coded parameter
0x802D0F28 - function that determines if the water box texture should be RGBA5551 or IA16 based on hard-coded parameter
0x802D104C - Geo layout 0x18 function to draw water box quads
0x803833B8 - function that parses the water box data from level script command 0x2E 

Segmented Pointers:
0x020175F0 - Start of water box RGBA5551 fast3d display list.
0x02017630 - Start of water box IA16 fast3d display list.
0x02017670 - End of water box fast3d display list.
(This post was last modified: 04-04-2017, 07:36 PM by David.)

Nice finds! I hope one day someone can hack the waterbox into a collision type like SM64DS works, it'll be way easier to use.
(This post was last modified: 03-04-2017, 08:46 AM by Nutta.)
Gone for a while.

Thank you so much for this! Now I can have chocolate water in level 3 of SSP!
If you like well-modeled and fun to play content, check out my current Super Mario 64 hack, Superstar Plumber!
It's Greeny approved!

Water boxes
Users browsing this thread: 1 Guest(s)