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 to InitMForceData[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.