Vertical Movement
Vertical movement behaves much like horizontal movement, where a positive speed
(Player_Y_Speed)
represents downwards movement and a negative speed represents upwards movement. Unlike with
horizontal movement,
Mario's subspeed (Player_Y_MoveForce) is applied to his subpixel value, as vertical
movement would
be jarring otherwise.
Gravity
Mario's gravity is only set under 4 different conditions:
- When going through a screen transition, Mario's downwards gravity is set to 0x28
- When Mario is above bounds in a water area, Mario's downwards gravity is set to 0x18
- When Mario lands on a spring, his upwards gravity is set to 0x70. In SMB2J, his downwards gravity is also set to 0x70.
- When Mario jumps or swims (bouncing off a spring does not count, however jumping off a spring does count), his upwards and downwards gravity is set following this algorithm:
if Player_State == 0 or (SwimmingFlag != 0 and (JumpSwimTimer != 0 or Player_Y_Speed >= 0)) then /* If Mario is on the ground, or Mario is swimming and either JumpSwimTimer is set or his speed is nonnegative */
JumpSwimTimer := 32 /* Reset timer */
y_register := 0
Player_YMF_Dummy := 0 /* Reset y subpixel */
JumpOrigin_Y_Position := Player_Y_Position /* Used for an edge case at the very beginning of Mario's jump where Player_Y_Speed < 0 and A_B_Buttons & PreviousA_B_Buttons & 0b10000000 == 0 */
Player_State := 1
for i := 0; i < 4 do
if Player_XSpeedAbsolute < [9, 16, 25, 28][i] then
break
end
y_register := y_register + 1
end
if SwimmingFlag != 0 then /* If Mario is swimming */
y_register := 5
if Whirlpool_Flag != 0 then /* If Mario is in a whirlpool */
y_register := y_register + 1
end
end
VerticalForce := JumpMForceData[y_register] /* [0x20, 0x20, 0x1e, 0x28, 0x28, 0x0d, 0x04] for Mario, [0x18, 0x18, 0x18, 0x22, 0x22, 0x0d, 0x04] for Luigi */
VerticalForceDown := FallMForceData[y_register] /* [0x70, 0x70, 0x60, 0x90, 0x90, 0x0a, 0x09] for Mario, [0x42, 0x42, 0x3e, 0x5d, 0x5d, 0x0a, 0x09] for Luigi */
Player_Y_MoveForce := InitMForceData[y_register] /* [0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00] */
Player_Y_Speed := PlayerYSpdData[y_register] /* [0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfe, 0xff] */
if SwimmingFlag != 0 and Player_Y_Position < 20 then /* Check if above bounds in water areas */
Player_Y_Speed := 0
end
end
Note that upwards and downwards gravity are stored in VerticalForce and
VerticalForceDown respectively. Only VerticalForce is ever applied to
Mario's speed
and subspeed. VerticalForceDown is copied to VerticalForce when Mario is
in the air
and either his speed is greater or equal to zero, or the A button has been released.
Low Gravity
Since Mario's downwards gravity is set to a low value (0x28) through screen transitions, he appears to fall very slowly. Since bouncing on enemies does not set his gravity, this is used in the SMB1 A Button Challenge TAS to cross large gaps in 1-1 and 8-2 without jumping.
Speed
Mario's speed is set in the following conditions:
- When Mario jumps, his speed is set to
PlayerYSpdData[y_register], and his subspeed is set toInitMForceData[y_register](see pseudocode above for exact values). - When Mario bumps a soft block, his vertical speed is set to 0 if the block does not break, or -2 if it does. His subspeed is not changed.
- When Mario bumps a hard block (including when the bump timer has not reset yet, as all blocks are hard) or the bottom of a moving platform, his speed is set to 1. His subspeed is not changed. Note that all blocks in water areas are hard.
- When Mario dies onscreen, his speed is set to -4 and his gravity is set and frozen to 0x28. His subspeed is not changed.
- In SMB1, if you bounce off a Cheep Cheep, Bullet Bill, Podoboo, Hammer Bro, Lakitu, or a Blooper Mario's speed is set to -3. Any other enemy will set his speed to -4. His subspeed is not changed.
- In SMB2J, if you bounce off a Red Parakoopa or a Flying Green Parakoopa (ones that fly in a fixed path rather than bounce on the ground), Mario's speed is set to -8. Any other enemy will set his speed to -6. His subspeed is not changed.
- When Mario lands on anything, his speed and subspeed is reset to 0.
- When Mario is climbing, his speed is set to -1 and his subspeed is set to 0x20 when climbing up, or 1 and 0xff when climbing down.
- When Mario bounces on a red spring, his speed is set to -12 if A is held, and -7 otherwise. His subspeed is not explicitly reset however it is always reset beforehand when he lands on the spring. In SMB2J, when Mario bounces on a green spring, his speed is set to -32 if A is held, and -7 otherwise.
Speed Cap
The vertical speed cap for all sprite objects (including Mario) is implemented poorly. It checks for
whether the
object's speed and subspeed both exceed their respective intended caps (SprObject_Y_Speed[x_register] >= $02
and SprObject_Y_MoveForce[x_register] >= 0x80), forgetting to account for when it's speed is
above
the cap, but it's subspeed is below the cap (SprObject_Y_Speed[x_register] > $02
and
SprObject_Y_MoveForce[x_register] < 0x80). This allows Mario (and all other sprite
objects) to exceed
the intended speed cap, with precise subspeed manipulation (e.g. differing jump heights, ceiling
bonks, enemy bounces).
This is generally useless on NTSC, however it can be used in the PAL version to clip into the floor.
