Swim with Water Bombs
Discovered by LogitechSDAZ
Trick Description
It's possible to swim underwater with a water bomb in Link's hands. This leads to two interesting glitches: Replenishing the air meter without surfacing and rocketing to the surface of a body of water. Replenishing air underwater makes it possible to beat Morpheel and Zant's Lakebed phase without ever obtaining the Zora Armor.
How To
Replenishing the air meter (all versions)
- Equip the Iron Boots and sink to the bottom of a body of water.
- Press X or Y to pull out a water bomb and quickly open up the item wheel before Link holds the bomb over his head.
- Assign an item over the Iron Boots button to force them to un-equip, then hold the control stick in any direction.
- Close the item wheel and continue holding the control stick to keep Link moving, as stopping would cause the bomb to fall out of Link's hands with no other effects.
- Link will now be swimming with the water bomb. To replenish the air meter, drop the water bomb with A. Dropping the bomb with any other button will not replenish the air meter.
It is also possible to swim with a water bomb without holding any direction on the control stick. In this case, the player would need to leave the control stick neutral until dropping the water bomb with A in order to avoid Link automatically dropping it with no effect on the air meter.
Rocket Link (all versions)
Performing the above trick but pressing A to drop the water bomb immediately after Link pulls it out will cause Link to teleport to the surface of the body of water he is in.
Explanation
Investigated by Maddie
"The following is the code for whether the air meter is visible:
if (!i_checkNoResetFlg0(FLG0_UNK_100) || (i_checkModeFlg(MODE_SWIMMING) && mWaterY > lit_7808 + current.pos.y))
{
hide_timer = false;
} else {
hide_timer = true;
}
I'm not sure what FLG0_UNK_100 is entirely but it seems to be turned off when link is sucked by morpheel for example, which makes sense because you cant see the air meter and it doesn't go down during that cutscene but your air doesn't refill during it (the same flag is also used in other places however, seems like it might be some flag to stop the air meter from going down without refilling it). Anyway, the important part is the logic on the right, i_checkModeFlg(MODE_SWIMMING) && mWaterY > lit_7808 + current.pos.y) stating links mode flag must have the MODE_SWIMMING bit set and link must be a certain distance underwater for the timer to be able to appear and go down, otherwise link is overwater and the timer can refill.
My theory had been that dropping the waterbomb causes link to enter a non swimming state (like some dropping state) for a single frame allowing his air to refill. I tested this theory with memory watches and found:
before dropping: mode flags are 0x00040104 (MODE_DISABLE_ITEMS, MODE_UNK_100, MODE_SWIMMING) 0f after dropping the waterbomb mode flags are 0x00100001 (MODE_IDLE, MODE_GRAB_PLACE) 1f after drop: mode flags are 0x00001006 (MODE_JUMP, MODE_DISABLE_ITEMS, MODE_UNK_1000) 2f after drop: mode flags are 0x00040104 (MODE_DISABLE_ITEMS, MODE_UNK_100, MODE_SWIMMING)
So it turns out there's actually 2 frames that the meter is being hidden there. The next important code is this bit which just shows us that if the timer is hidden, oxygen should be refilled (fun fact in this same code is the bug that causes bad air involving field_0x2fbe).
if (dComIfGp_getOxygenShowFlag()) {
if (checkZoraWearAbility()) {
offOxygenTimer();
} else if (hide_timer) {
s32 max = dComIfGp_getMaxOxygen();
dComIfGp_setOxygenCount(max);
if (field_0x2fbe < 90) {
field_0x2fbe++;
} else {
offOxygenTimer();
}
} else if (!checkEventRun()) {
dComIfGp_setOxygenCount(-1);
}
}
It shows that if the timer is shown but should be hidden (hide_timer is true, which was set above due to the fact MODE_SWIMMING is off) to refill the air (dComIfGp_setOxygenCount(max))
So why is Link removed from a swimming state? Well when you press A to drop the waterbomb link is forced to execute proc PROC_GRAB_THROW (0x06F)
During any proc execution this line is run mModeFlg = m_procInitTable[i_procID].m_mode which updates links mode flags from a lookup table based on the proc id. It just sures out that position 0x06F in that table corresponds to a proc init struct with m_mode 0x00100001 (MODE_IDLE, MODE_GRAB_PLACE)
Theoretically if we could swim with rocks they would work too
tl;dr air refill with water bombs is caused by dropping the bombs make the game set links state in such a way the air meter thinks link is no longer swimming for 2 frames and refills his air"