Flight
A platformer move that keeps a character rising or aloft past a jump's arc, usually for a limited time.
On this page
Flight lets a character keep rising or stay aloft after a jump. In Super Mario Bros. 2 the Princess hovers for up to 60 frames1. In Super Mario Bros. 3 a run fills the P-meter, and a jump with the meter full gives a raccoon or tanooki Mario a timed flight2,3. Out of flight time, the same tail slows a fall4. In Sonic 3 & Knuckles, Tails flies for 480 frames5, and Knuckles glides at 4 to 24 px/frame across, about 0.5 down6. Banjo-Kazooie’s Feathery Flap, once per time in the air, lifts Banjo briefly and then caps his fall far below the usual cap7. In a decompilation that doesn’t yet match, Super Mario Sunshine’s hover nozzle eases Mario toward a target height, 160 above the start by default, closed 0.75% an update8, where the Princess’s float cycles her speed up, still, and down1.
- HoverSuper Mario Bros. 2 (1988). The Princess hovers for up to 60 frames with the button held.1
- Held heightSuper Mario Sunshine (2002). FLUDD's hover nozzle eases Mario toward 160 units above where it started, by default, until the spray's timer runs out, the pumping stops, or the tank empties.8
- Run-upSuper Mario Bros. 3 (1988). A full P-meter at take-off gives the Raccoon and Tanooki suits about 4¼ seconds of flight.2,3,9,4
- FlapSonic 3 & Knuckles (1994), Tails. Tails flaps for a few seconds, each press lifting him.5
- Slowed fallBanjo-Kazooie (1998). The Feathery Flap: one A press per time in the air, a 280 units/s lift and a fall capped at −399.9, for up to 2.5 s.7
- Steady glideSonic 3 & Knuckles (1994), Knuckles. Knuckles glides, falling slowly while his speed builds.6
Games
| Game | Year | How | Note |
|---|---|---|---|
| Super Mario Bros. 2 | 1988 | Hover | the Princess hovers for up to 60 frames with the button held |
| Mega Man 6 | 1993 | Held height | the Jet adaptor lifts him to a set height while A is held, until its meter runs out |
| Super Mario Sunshine | 2002 | Held height | FLUDD's hover nozzle eases Mario toward 160 units above where it started, by default, until the spray's timer runs out, the pumping stops, or the tank empties |
| Super Mario Bros. 3 | 1988 | Run-up | a full P-meter at take-off gives the Raccoon and Tanooki suits about 4¼ seconds of flight |
| Sonic 3 & Knuckles | 1994 | Flap | Tails · Tails flaps for a few seconds, each press lifting him |
| Banjo-Kazooie | 1998 | Slowed fall | the Feathery Flap: one A press per time in the air, a 280 units/s lift and a fall capped at −399.9, for up to 2.5 s |
| Sonic 3 & Knuckles | 1994 | Steady glide | Knuckles · Knuckles glides, falling slowly while his speed builds |
Every claim about this mechanic, by game (11)
References
- ^ abcThe Princess's
Floating Timeis$3C; the other three have 0. With the button held once her rise has slowed to-$04or less, each frame sets her vertical speed fromFloatingYVelocity, cycling up, still, down, still, until the timer runs out. Letting go ends the float for that jump. Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, a jump with A held floats for 60 frames, holding each speed of the cycle for 8 frames, and then falls.VerifiedSMB2 DiscombobulatedHow we know
346PrincessStats: ⋮ 360 .db $3C ; Floating Time
src/prg-a-b.asm lines 346–360 at b73415e · upstream ↗ 2619 LDA GravityWithJumpButton 2620 LDY PlayerYVelocity 2621 CPY #$FC 2622 BMI PlayerGravity_Falling ⋮ 2624 LDY JumpFloatTimer 2625 BEQ PlayerGravity_Falling ⋮ 2627 DEC JumpFloatTimer ⋮ 2634 LDA FloatingYVelocity, Y 2635 STA PlayerYVelocity 2636 RTS ⋮ 2639 LDY PlayerYVelocity ⋮ 2648 STA PlayerYVelocity ⋮
src/prg-0-1.asm lines 2619–2656 at b73415e · upstream ↗ 2662FloatingYVelocity: 2663 .db $FC 2664 .db $00 2665 .db $04 2666 .db $00
src/prg-0-1.asm lines 2662–2666 at b73415e · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-26.
- ^ abThe P-meter,
Player_Power, is seven bits. Mario runs, for the meter, on a frame he is on the ground and not sliding, with B held and his speed already$28or more. Each timePlayer_PMeterCntreaches 0, a running frame adds a step and sets it to 8, and any other frame takes one away and sets it to 24; at 0 steps the counter stays 0, so the next run adds one at once. A full meter,$7F, takes 7 steps, and each running frame at full sets the counter to 16, so the meter stays full 16 frames past the last one. WhilePlayer_FlyTimeis counting, none of this runs (flight-time). Measured in Mesen from power-on as Raccoon Mario at World 1-1's start, with Right and B held from rest the first step comes the frame after he reaches$28, then one every 8 frames to full; with B let go, it drops 16 frames later and then every 24.VerifiedSouthbird's SMB3 disassemblyHow we know
2346PRG008_AB62: 2347 LDY #PLAYER_TOPWALKSPEED ⋮ 2349 BIT <Pad_Holding 2350 BVC PRG008_AB83 ; If Player is NOT holding 'B', jump to PRG008_AB83 ⋮ 2352 ; Player is holding B... ⋮ 2354 LDA <Player_InAir 2355 ORA Player_Slide 2356 BNE PRG008_AB78 ; If Player is mid air or sliding, jump to PRG008_AB78 ⋮ 2358 LDA <Temp_Var3 2359 CMP #PLAYER_TOPRUNSPEED 2360 BMI PRG008_AB78 ; If Player's X Velocity magnitude is less than PLAYER_TOPRUNSPEED, jump to PRG008_AB78 ⋮ 2362 ; Player is going fast enough while holding B on the ground; flag running! ⋮
PRG/prg008.asm lines 2346–2375 at 09b1bd8 · upstream ↗ 981Player_PowerUpdate: 982 LDY Player_FlyTime 983 BEQ PRG008_A4E4 ; If Player is not flying (or at least high-speed jumping), jump to PRG008_A4E4 ⋮ 985 CPY #$ff 986 BEQ Sound_FullPowerRing ; If Player_FlyTime = $FF (P-Wing active), jump to Sound_FullPowerRing ⋮ 988 LDA <Counter_1 989 AND #$01 990 BEQ PRG008_A4D5 ; Every other tick, jump to PRG008_A4D5 ⋮ 992 DEY 993 STY Player_FlyTime ; Player_FlyTime-- ⋮ 995PRG008_A4D5: 996 TYA ; Y (Player_FlyTime) -> A ⋮
PRG/prg008.asm lines 981–1058 at 09b1bd8 · upstream ↗ 378 ; Decrement several adjacent counters! 379 LDX #$07 ; X = 7 ⋮ 381PRG008_A1DE: 382 LDA Event_Countdown,X 383 BEQ PRG008_A1E6 ; If counter is = 0, jump to PRG008_A1E6 ⋮ 385 DEC Event_Countdown,X ; Otherwise, decrement it! ⋮ 387PRG008_A1E6: 388 DEX ; X-- 389 BPL PRG008_A1DE ; While X >= 0, loop!
PRG/prg008.asm lines 378–389 at 09b1bd8 · upstream ↗ 1545 ; NOTE: Event_Countdown and the following 7 are all decremented together! 1546 Event_Countdown: .ds 1 ⋮ 1548 Player_TailCount: .ds 1 ; Determines display frame of tail wag 1549 Player_InAir_OLD: .ds 1 ; Stores backup of Player_InAir 1550 Player_FireCount: ; Player shoots fireball/hammer, sets sprite frame (shared with Player_FrogHopCnt) 1551 Player_FrogHopCnt: .ds 1 ; Counter used for frog hopping along the ground (shared with Player_FireCount) ⋮ 1553 .ds 1 ; $0514 unused ⋮ 1555 Player_PMeterCnt: .ds 1 ; Tick counter used to count when to increase/decrease Power Meter
smb3.asm lines 1545–1555 at 09b1bd8 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-26.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-26.
- ^ abA jump with the meter full and no flight time left sets
Player_FlyTimeto$80, which counts down every other frame, about 256 frames; when it reaches 0 the meter empties ($FF, the P-Wing's value, never counts down). In the Raccoon or Tanooki suit, the suits with the flight bit inPowerUp_Ability, each press of A in the air starts a 16-frame wag. During a wag, unless he is rising faster than-$18, his vertical speed is set to-$18while the timer is$0For more, to-$10from$0Eto$08, and to 0 from$07to$01; since the timer ticks every other frame, those two stages last 14 frames each. At 0 the tail only slows a fall (tail-wag). Measured in Mesen from power-on as Raccoon Mario at World 1-1's start, a jump at full speed with A pressed every 4 frames sets the timer to$80, climbs at-$18, then for 14 frames at-$10and 14 at 0, and the timer and meter run out 255 frames after the take-off.VerifiedSouthbird's SMB3 disassemblyrevisedHow we know
2621 LDA Player_Power 2622 CMP #$7f 2623 BNE PRG008_AC9E ; If Player is not at max power, jump to PRG008_AC9E ⋮ 2625 LDA Player_FlyTime 2626 BNE PRG008_AC9E ; If Player still has flight time left, jump to PRG008_AC9E ⋮ 2628 LDA #$80 2629 STA Player_FlyTime ; Otherwise, Player_FlyTime = $80
PRG/prg008.asm lines 2621–2629 at 09b1bd8 · upstream ↗ 981Player_PowerUpdate: 982 LDY Player_FlyTime 983 BEQ PRG008_A4E4 ; If Player is not flying (or at least high-speed jumping), jump to PRG008_A4E4 ⋮ 985 CPY #$ff 986 BEQ Sound_FullPowerRing ; If Player_FlyTime = $FF (P-Wing active), jump to Sound_FullPowerRing ⋮ 988 LDA <Counter_1 989 AND #$01 990 BEQ PRG008_A4D5 ; Every other tick, jump to PRG008_A4D5 ⋮ 992 DEY 993 STY Player_FlyTime ; Player_FlyTime-- ⋮ 995PRG008_A4D5: 996 TYA ; Y (Player_FlyTime) -> A ⋮
PRG/prg008.asm lines 981–999 at 09b1bd8 · upstream ↗ 2673 BEQ PRG008_ACD9 ; If Player_WagCount = 0, jump to PRG008_ACD9 ⋮ 2675 DEC <Player_WagCount ; Otherwise, $F0-- ⋮ 2677PRG008_ACD9: 2678 LDA Player_Kuribo 2679 BNE PRG008_ACEF ; If Player is wearing Kuribo's shoe, jump to PRG008_ACEF ⋮ 2681 LDX <Player_Suit ⋮ 2683 LDA PowerUp_Ability,X ; Get "ability" flags for this power up 2684 AND #$01 2685 BEQ PRG008_ACEF ; If this power up does not have flight, jump to PRG008_ACEF ⋮ 2687 LDY <Temp_Var1 ; Y = $80 if Player was pressing 'A' when this all began 2688 BEQ PRG008_ACEF ; And if he wasn't, jump to PRG008_ACEF ⋮ 2690 LDA #$10 ⋮
PRG/prg008.asm lines 2673–2730 at 09b1bd8 · upstream ↗ 558PowerUp_Ability: 559 ; Small, Big, Fire, Leaf, Frog, Tanooki, Hammer 560 .byte $00, $00, $00, $01, $02, $01, $02
PRG/prg000.asm lines 558–560 at 09b1bd8 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-26.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-26.
- ^ abOut of flight time, a wag of A with the Raccoon or Tanooki tail caps Mario's fall at
PLAYER_TAILWAG_YVEL,$10, and leaves a rise or a slower fall alone. Measured in Mesen from power-on as Raccoon Mario at World 1-1's start, wagging every 4 frames after a flight runs out, his fall levels off at$10, 1 px a frame.VerifiedSouthbird's SMB3 disassemblyHow we know
2683 LDA PowerUp_Ability,X ; Get "ability" flags for this power up 2684 AND #$01 2685 BEQ PRG008_ACEF ; If this power up does not have flight, jump to PRG008_ACEF ⋮ 2687 LDY <Temp_Var1 ; Y = $80 if Player was pressing 'A' when this all began 2688 BEQ PRG008_ACEF ; And if he wasn't, jump to PRG008_ACEF ⋮ 2690 LDA #$10 2691 STA <Player_WagCount ; Otherwise, Player_WagCount = $10
PRG/prg008.asm lines 2683–2691 at 09b1bd8 · upstream ↗ 2720PRG008_AD0E: 2721 LDA <Player_YVel 2722 BMI PRG008_AD1A ; If Player's Y velocity < 0 (moving upward), jump to PRG008_AD1A ⋮ 2724 CMP #PLAYER_TAILWAG_YVEL 2725 BLT PRG008_AD1A ; If Player's Y velocity < PLAYER_TAILWAG_YVEL, jump to PRG008_AD1A ⋮ 2727 LDY #PLAYER_TAILWAG_YVEL ; Y = PLAYER_TAILWAG_YVEL ⋮ 2729PRG008_AD18: 2730 STY <Player_YVel ; Set appropriate Y velocity
PRG/prg008.asm lines 2720–2730 at 09b1bd8 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-26.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-26.
- ^ abTails flies for 480 frames, a count of 240 that drops every other frame; flying adds
$8gravity a frame, and while time remains each press lifts him$20a frame for up to 30 frames, until he rises faster than 1 px/frame.Codesonicretro/skdisasmHow we know
28704 move.b #1,double_jump_flag(a0) 28705 move.b #(8*60)/2,double_jump_property(a0)
sonic3k.asm lines 28703–28705 at 73de97c · upstream ↗ 27634 andi.b #1,d0 27635 beq.s loc_14836 27636 tst.b double_jump_property(a0) 27637 beq.s loc_14836 27638 subq.b #1,double_jump_property(a0) ⋮ 27643 cmpi.w #-$100,y_vel(a0) 27644 blt.s loc_14858 27645 subi.w #$20,y_vel(a0) 27646 addq.b #1,double_jump_flag(a0) 27647 cmpi.b #$20,double_jump_flag(a0) ⋮ 27661 cmpi.w #-$100,y_vel(a0) ⋮ 27663 tst.b double_jump_property(a0) ⋮
sonic3k.asm lines 27632–27674 at 73de97c · upstream ↗ 27614 jsr (MoveSprite_TestGravity2).lsonic3k.asm lines 27610–27614 at 73de97c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abKnuckles's glide starts at 4 px/frame and gains
$4a frame to a cap of 24 px/frame, and its fall settles near 0.5 px/frame,$20added below$80and taken above.Codesonicretro/skdisasmrevisedHow we know
32606 addi.w #$200,y_vel(a0) 32607 bpl.s loc_17898 32608 move.w #0,y_vel(a0) ⋮ 32610loc_17898: 32611 moveq #0,d1 32612 move.w #$400,d0 32613 move.w d0,ground_vel(a0)
sonic3k.asm lines 32600–32613 at 73de97c · upstream ↗ 31643 cmpi.w #$400,d0 31644 bhs.s .mediumSpeed ⋮ 31648 addq.w #8,d0 ⋮ 31654 cmpi.w #$1800,d0 31655 bhs.s .applySpeed ⋮ 31663 addq.w #4,d0
sonic3k.asm lines 31642–31663 at 73de97c · upstream ↗ 31723 cmpi.w #$80,y_vel(a0) 31724 blt.s .fallingSlow 31725 subi.w #$20,y_vel(a0) 31726 bra.s .fallingFast ⋮ 31731 addi.w #$20,y_vel(a0)
sonic3k.asm lines 31723–31731 at 73de97c · upstream ↗ 30749 andi.b #button_A_mask|button_B_mask|button_C_mask,d0 30750 bne.s .continueGliding ⋮ 30763 asr.w x_vel(a0) 30764 asr.w x_vel(a0)
sonic3k.asm lines 30748–30764 at 73de97c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abWith the Feathery Flap learned, A pressed during a jump or a fall starts it, once per time in the air: the flag it sets clears only on stable ground, while climbing, or in water, and a peck in the air blocks it. It stops Banjo's rise (vertical speed 0, gravity −1100 units/s²); when the opening animation reaches 0.9 of its length, it sets him rising at 280 units/s with his fall capped at −399.9, against the usual cap of −4000. A let go in the first 0.67 s of the flap, counted from its start through the opening animation by
D_8037D308(the atlas's reading of that unnamed variable as elapsed time), does nothing; after that, A up restores the usual gravity and cap. A 2.5-second timer ends the flap in any case. OnceD_8037D301, which counts the frames the flap animation passes 0.9 of its length from the lift on (the atlas reads it as a loop count), reaches 4, holding A scales the target horizontal speed to 0.35 of what the stick gives. Super Mario 64'sact_jumpchecks B and Z but not A; its second jump comes from a press during a landing (sm64/double-jump).Codebanjo.decomp/banjo-kazooie · n64decomp/sm64revisedHow we know
40int bainput_should_feathery_flap(void){ 41 return bakey_pressed(BUTTON_A) && can_feathery_flap();
src/core2/bainput.c lines 40–42 at e8d31fa · upstream ↗ 53bool can_feathery_flap(void){ 54 return baflag_isFalse(BA_FLAG_12_HAS_FLAPPED) 55 && baflag_isFalse(BA_FLAG_5_HAS_PECKED) 56 && ability_hasLearned(ABILITY_7_FEATHERY_FLAP);
src/core2/playerutils.c lines 53–56 at e8d31fa · upstream ↗ 187 if(player_isStable() || bsclimb_inSet(bs_getState())){ 188 baflag_clear(BA_FLAG_5_HAS_PECKED); 189 baflag_clear(BA_FLAG_12_HAS_FLAPPED); ⋮ 192 if(player_inWater()){ 193 baflag_clear(BA_FLAG_5_HAS_PECKED); 194 baflag_clear(BA_FLAG_12_HAS_FLAPPED);
src/core2/code_D9B0.c lines 187–195 at e8d31fa · upstream ↗ 146 if(bainput_should_feathery_flap()) 147 sp34 = BS_10_BFLAP;
src/core2/bs/jump.c lines 146–147 at e8d31fa · upstream ↗ 225 if(bainput_should_feathery_flap() && baflag_isFalse(BA_FLAG_5_HAS_PECKED)) 226 sp2C = BS_10_BFLAP;
src/core2/bs/jump.c lines 225–226 at e8d31fa · upstream ↗ 13const f32 D_80364A10 = 280.0f; 14const f32 D_80364A14 = -1100.0f; 15const f32 D_80364A18 = -399.9f;
src/core2/bs/bFlap.c lines 13–15 at e8d31fa · upstream ↗ 33 baphysics_set_vertical_velocity(0.0f); 34 baphysics_set_gravity(D_80364A14); 35 modelAppendages_setKazooiesUpperHalfVisibility(TRUE); 36 baflag_set(BA_FLAG_12_HAS_FLAPPED); 37 batimer_set(0, 2.5f);
src/core2/bs/bFlap.c lines 33–37 at e8d31fa · upstream ↗ 55void func_802A2810(void) { ⋮ 58 if (anctrl_isAt(plyrMvPtr, 0.9f)) { 59 D_8037D301++;
src/core2/bs/bFlap.c lines 55–60 at e8d31fa · upstream ↗ 86void func_802A2900(void){ 87 D_8037D304 = D_8037D308; 88 D_8037D308 += time_getDelta();
src/core2/bs/bFlap.c lines 86–89 at e8d31fa · upstream ↗ 113 func_802B6FA8(); 114 switch(D_8037D300){ 115 case 0: ⋮ 119 if(anctrl_isAt(sp18, 0.9f)){ ⋮ 126 baphysics_set_vertical_velocity(D_80364A10); 127 baphysics_set_gravity(D_80364A14); 128 baphysics_set_terminal_velocity(D_80364A18); 129 D_8037D300 = 1; ⋮ 138 if(0.67 <= D_8037D308){ 139 D_8037D300 = 2; ⋮ 148 if(D_8037D301 == 4) { 149 D_8037D300 = 3; ⋮
src/core2/bs/bFlap.c lines 113–182 at e8d31fa · upstream ↗ 10f32 baphysics_default_gravity = -2700.0f; //defaultGravity 11f32 baphysics_default_terminal_velocity = -4000.0f;
src/core2/ba/physics.c lines 10–11 at e8d31fa · upstream ↗ 446s32 act_jump(struct MarioState *m) { 447 if (check_kick_or_dive_in_air(m)) { ⋮ 451 if (m->input & INPUT_Z_PRESSED) { 452 return set_mario_action(m, ACT_GROUND_POUND, 0);
src/game/mario_actions_airborne.c lines 446–453 at 9921382 · upstream ↗ 108s32 check_kick_or_dive_in_air(struct MarioState *m) { 109 if (m->input & INPUT_B_PRESSED) { 110 return set_mario_action(m, m->forwardVel > 28.0f ? ACT_DIVE : ACT_JUMP_KICK, 0);
src/game/mario_actions_airborne.c lines 108–110 at 9921382 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abIn Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, FLUDD's hover nozzle holds Mario up through the status the code calls
MARIO_STATUS_ROCKET.rocketCheck, which the jumps, the wall kick, standing, and running call, enters it, unless Mario is already in it or inMARIO_STATUS_ROCKET_LANDING, when he has FLUDD, the current nozzle'smRocketTypeparameter is 1, his upper body is inUPPER_STATE_PUMPING, and the nozzle is spraying (canSpray, a name a decompilers' comment calls fabricated), and sets a target heightmHoverHeight(default 160) above him; standing or running, the callers set it above the floor instead. The status's entry code has a voice for the hover, rocket, and turbo nozzles, and the height-holding code inrocketingruns only for the hover. Each updaterocketingsets his vertical speed to the gap to the target times the parametermAccelRate(default 0.03) and multiplies his forward speed bymBrake(default 0.95), the stick adding forward speed or turning him, and thenjumpProcessmoves him a quarter of his velocity: with the defaults he closes 0.75% of the gap each update (computed), and any rise or fall he carried in is dropped at once. The hover is a trigger nozzle (TNozzleTrigger). While Mario pumps, and in water only with a full tank, each update adds 150 times R's analog reading tomInsidePressure, and every update takes awaymInsidePressureDec(default 100); when the pressure passesmInsidePressureMax(default 4500) while the spray is idle and the nozzle'smRumbleOnChargeis false, the spray starts with a timer ofmTriggerTimeupdates (withmRumbleOnChargetrue, an A press with R held starts it instead). An empty tank sets the spray back to idle; the timer running out or the pumping stopping sets it to the state the code callsSPRAY_STATE_DEAD, which returns to idle only once R reads 0. Without a spray,rocketingends inMARIO_STATUS_ROCKET_LANDING. On each update it sprays, each of the nozzle's emitters asks the water manager for drops, betweenmNumMinandmNumby the pressure, and the tank, which holdsmAmountMax(default 2100), losesmDecRatefor each drop accepted. Which nozzles havemRocketType1, the timer, and the tank are data in each nozzle's file, NozzleTrgHover.prm for the hover. Banjo-Kazooie's Feathery Flap, a lift of 280 units/s and a fall capped at −399.9 units/s for up to 2.5 s, slows a fall where the hover holds a height (banjo-kazooie/feathery-flap).Code notesdoldecomp/sms · banjo.decomp/banjo-kazooierevisedHow we know
947 Object(NonMatching, "Player/MarioJump.cpp"), ⋮ 949 PCHObject(NonMatching, "Player/MarioMove.cpp"), 950 Object(NonMatching, "Player/MarioPhysics.cpp"), ⋮ 952 PCHObject(NonMatching, "Player/MarioRun.cpp"), ⋮ 956 Object(NonMatching, "Player/MarioWait.cpp"), ⋮ 959 PCHObject(NonMatching, "Player/WaterGun.cpp"), ⋮ 964 PCHObject(NonMatching, "Player/MarioInit.cpp"),
configure.py lines 947–964 at d2cc8f5 · upstream ↗ 880BOOL TMario::rocketCheck() ⋮ 883 if (mStatus == MARIO_STATUS_ROCKET) 884 bVar2 = false; 885 if (mStatus == MARIO_STATUS_ROCKET_LANDING) 886 bVar2 = false; ⋮ 888 if (checkFlag(MARIO_FLAG_HAS_FLUDD)) { 889 if (mWaterGun->getCurrentNozzle()->mRocketType.get() != 1) 890 bVar2 = false; ⋮ 892 if (!isUpperState(UPPER_STATE_PUMPING)) 893 bVar2 = false; ⋮ 895 if (!mWaterGun->canSpray()) 896 bVar2 = false; ⋮
src/Player/MarioJump.cpp lines 880–904 at d2cc8f5 · upstream ↗ 118 if (rocketCheck()) { 119 unk314 120 = mFloorPosition.y + mWaterGun->mWatergunParams.mHoverHeight.get(); 121 return changePlayerStatus(MARIO_STATUS_ROCKET, 0, false);
src/Player/MarioWait.cpp lines 118–121 at d2cc8f5 · upstream ↗ 697 if (rocketCheck()) { 698 unk314 699 = mFloorPosition.y + mWaterGun->mWatergunParams.mHoverHeight.get(); 700 return changePlayerStatus(MARIO_STATUS_ROCKET, 0, false);
src/Player/MarioRun.cpp lines 697–700 at d2cc8f5 · upstream ↗ 451 if (rocketCheck())src/Player/MarioJump.cpp line 451 at d2cc8f5 · upstream ↗ 19 , PARAM_INIT(mHoverHeight, 160.0f)include/Player/WaterGun.hpp line 19 at d2cc8f5 · upstream ↗ 238 // TODO: get rid of this -- it's real name is isEmitting() and it 239 // wasn't stripped in MarioRun.cpp 240 // //Fabricated 241 bool canSpray() const ⋮ 243 if (mCurrentWater == 0) 244 return false; ⋮ 248 if (triggerNozzle->getSprayState() 249 == TNozzleTrigger::SPRAY_STATE_ACTIVE) 250 return true;
include/Player/WaterGun.hpp lines 238–250 at d2cc8f5 · upstream ↗ 573 case MARIO_STATUS_ROCKET: { ⋮ 575 if ((int)mWaterGun->mCurrentNozzle == TWaterGun::Rocket) { ⋮ 579 if ((int)mWaterGun->mCurrentNozzle == TWaterGun::Turbo) ⋮ 581 if ((int)mWaterGun->mCurrentNozzle == TWaterGun::Hover) 582 startVoice(MSD_SE_MV21_JUMP_SMALL_01); 583 setPlayerJumpSpeed(0.0f, 10.0f);
src/Player/MarioMove.cpp lines 573–583 at d2cc8f5 · upstream ↗ 909BOOL TMario::rocketing() ⋮ 911 if (!checkFlag(MARIO_FLAG_HAS_FLUDD)) 912 return changePlayerStatus(MARIO_STATUS_ROCKET_LANDING, 0, 0); ⋮ 914 if (mWaterGun->getCurrentNozzle()->mRocketType.get() != 1) 915 return changePlayerStatus(MARIO_STATUS_ROCKET_LANDING, 0, 0); ⋮ 917 if (!isUpperState(UPPER_STATE_PUMPING) || !mWaterGun->canSpray()) 918 return changePlayerStatus(MARIO_STATUS_ROCKET_LANDING, 0, 0);
src/Player/MarioJump.cpp lines 909–918 at d2cc8f5 · upstream ↗ 920 if (mInput & 1) { 921 switch (mWaterGun->mCurrentNozzle) { 922 case TWaterGun::Hover: ⋮ 942 mForwardVel += mag * JMASCos(angleDiff) 943 * mDivingParams.mAccelControl.get(); ⋮ 952 s16 rotSp = mHoverParams.mRotSp.get(); 953 mFaceAngle.y 954 = mIntendedYaw 955 - IConverge((s16)(mIntendedYaw - mFaceAngle.y), 0, 956 rotSp, rotSp);
src/Player/MarioJump.cpp lines 920–959 at d2cc8f5 · upstream ↗ 971 switch (mWaterGun->getCurrentNozzleType()) { 972 case TWaterGun::Hover: 973 mVel.y = (unk314 - mPosition.y) * mHoverParams.mAccelRate.get(); 974 mForwardVel *= mHoverParams.mBrake.get(); 975 break; ⋮ 978 switch (jumpProcess(2)) {
src/Player/MarioJump.cpp lines 971–978 at d2cc8f5 · upstream ↗ 500 next.y = mPosition.y + 0.25f * mVel.y;src/Player/MarioPhysics.cpp line 500 at d2cc8f5 · upstream ↗ 45 , mHoverParams("/Mario/HHover.prm")src/Player/MarioInit.cpp line 45 at d2cc8f5 · upstream ↗ 916TMario::THHoverParams::THHoverParams(const char* prm) 917 : TParams(prm) 918 , PARAM_INIT(mRotSp, 0x80) 919 , PARAM_INIT(mAccelRate, 0.029999999f) 920 , PARAM_INIT(mBrake, 0.94999999f) ⋮ 922 TParams::load(mPrmPath);
src/Player/MarioInit.cpp lines 916–922 at d2cc8f5 · upstream ↗ 2375 stateMachine(); ⋮ 2387 gunExec();
src/Player/MarioMove.cpp lines 2375–2387 at d2cc8f5 · upstream ↗ 2300 mWaterGun->triggerPressureMovement(*unk108);src/Player/MarioMove.cpp line 2300 at d2cc8f5 · upstream ↗ 2316 } else if (mUpperState == UPPER_STATE_PUMPING) { 2317 mWaterGun->emit();
src/Player/MarioMove.cpp lines 2316–2317 at d2cc8f5 · upstream ↗ 1148 , mNozzleHover("hover_wg", "/Mario/WaterGun/NozzleTrgHover.prm", this)src/Player/WaterGun.cpp line 1148 at d2cc8f5 · upstream ↗ 1163 mNozzleList[Hover] = &mNozzleHover;src/Player/WaterGun.cpp line 1163 at d2cc8f5 · upstream ↗ 197 , PARAM_INIT(mAmountMax, 0x834)src/Player/WaterGun.cpp line 197 at d2cc8f5 · upstream ↗ 222 , PARAM_INIT(mInsidePressureDec, 100.0f) 223 , PARAM_INIT(mInsidePressureMax, 4500.0f) 224 , PARAM_INIT(mTriggerTime, 1)
src/Player/WaterGun.cpp lines 222–224 at d2cc8f5 · upstream ↗ 508void TNozzleTrigger::movement(const TMarioControllerWork& controllerWork) ⋮ 510 if (mFludd->getCurrentWater() <= 0) { 511 mSprayState = TNozzleTrigger::SPRAY_STATE_INACTIVE; ⋮ 517 if (mSprayState == TNozzleTrigger::SPRAY_STATE_ACTIVE) { 518 mSprayTimer -= 1; ⋮ 522 if (!isPumping || mSprayTimer <= 0) { 523 mSprayState = TNozzleTrigger::SPRAY_STATE_DEAD;
src/Player/WaterGun.cpp lines 508–527 at d2cc8f5 · upstream ↗ 529 if ((mRumbleOnCharge == true 530 && (controllerWork.mFrameInput & TMarioControllerWork::A) != 0 531 && (controllerWork.mInput & TMarioControllerWork::R) != 0) 532 && mSprayState == TNozzleTrigger::SPRAY_STATE_INACTIVE) { 533 mSprayState = TNozzleTrigger::SPRAY_STATE_ACTIVE; ⋮ 540 mSprayTimer = mTriggerTime.get();
src/Player/WaterGun.cpp lines 529–540 at d2cc8f5 · upstream ↗ 545 if (!mFludd->getMario()->isUpperState(TMario::UPPER_STATE_PUMPING)) 546 canSpray = false; ⋮ 548 if (mFludd->getMario()->checkFlag(MARIO_FLAG_IN_ANY_WATER) == true 549 && mFludd->getCurrentWater() < mAmountMax.get()) 550 canSpray = false; ⋮ 552 if (canSpray == true) { 553 mInsidePressure += 150.0f * controllerWork.mAnalogR;
src/Player/WaterGun.cpp lines 545–553 at d2cc8f5 · upstream ↗ 570 mInsidePressure -= mInsidePressureDec.get(); ⋮ 575 if (mInsidePressure > mInsidePressureMax.get()) { 576 mInsidePressure = mInsidePressureMax.get(); 577 if (!mRumbleOnCharge 578 && mSprayState == TNozzleTrigger::SPRAY_STATE_INACTIVE) { 579 mSprayState = TNozzleTrigger::SPRAY_STATE_ACTIVE; 580 mSprayTimer = mTriggerTime.get();
src/Player/WaterGun.cpp lines 570–580 at d2cc8f5 · upstream ↗ 595 if (mSprayState == TNozzleTrigger::SPRAY_STATE_DEAD) { 596 mInsidePressure = 0.0f; 597 if (controllerWork.mAnalogR == 0.0f) { 598 mSprayState = TNozzleTrigger::SPRAY_STATE_INACTIVE;
src/Player/WaterGun.cpp lines 595–598 at d2cc8f5 · upstream ↗ 605void TNozzleTrigger::emit(int param_1) ⋮ 607 if (mFludd->mCurrentWater > 0 608 && (u8)mSprayState == TNozzleTrigger::SPRAY_STATE_ACTIVE) { ⋮ 617 f32 pressure = triggerFill / insidePressureMax; ⋮ 619 mEmitNum += pressure * (emitNum - emitNumMin) + emitNumMin; ⋮ 646 u8 emittedWater = gpModelWaterManager->emitRequest(*emitInfo); ⋮ 649 if (emittedWater != 0) { 650 mFludd->depleteWater(emittedWater * mDecRate.get());
src/Player/WaterGun.cpp lines 605–650 at d2cc8f5 · upstream ↗ 1779 for (int i = 0; i < nozzleBmdData.getEmitterCount(currentNozzleType); ++i) 1780 currentNozzle->emit(i);
src/Player/WaterGun.cpp lines 1779–1780 at d2cc8f5 · upstream ↗ 13const f32 D_80364A10 = 280.0f; 14const f32 D_80364A14 = -1100.0f; 15const f32 D_80364A18 = -399.9f;
src/core2/bs/bFlap.c lines 13–15 at e8d31fa · upstream ↗ 126 baphysics_set_vertical_velocity(D_80364A10); 127 baphysics_set_gravity(D_80364A14); 128 baphysics_set_terminal_velocity(D_80364A18);
src/core2/bs/bFlap.c lines 126–128 at e8d31fa · upstream ↗ 180 batimer_decrement(0); 181 if(batimer_isZero(0))
src/core2/bs/bFlap.c lines 180–181 at e8d31fa · upstream ↗ 33 baphysics_set_vertical_velocity(0.0f); 34 baphysics_set_gravity(D_80364A14); 35 modelAppendages_setKazooiesUpperHalfVisibility(TRUE); 36 baflag_set(BA_FLAG_12_HAS_FLAPPED); 37 batimer_set(0, 2.5f);
src/core2/bs/bFlap.c lines 33–37 at e8d31fa · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^On the ground,
Player_JumpFlyFlutterclearsPlayer_FlyTimeunless the suit has the flight bit, so Raccoon and Tanooki Mario keep the rest of a flight through a landing, with the meter still full, and can take off again; for the other suits a full-meter jump's timer ends when they land.CodeSouthbird's SMB3 disassemblyHow we know
2631PRG008_AC9E: 2632 LDA <Player_InAir 2633 BNE PRG008_ACB3 ; If Player is mid air, jump to PRG008_ACB3 ⋮ 2635 LDY <Player_Suit 2636 LDA PowerUp_Ability,Y ; Get "ability" flags for this power up 2637 AND #$01 2638 BNE PRG008_AD1A ; If power up has flight ability, jump to PRG008_AD1A ⋮ 2640 LDA #$00 2641 STA Player_FlyTime ; Otherwise, Player_FlyTime = 0 :( 2642 JMP PRG008_AD1A ; Jump to PRG008_AD1A
PRG/prg008.asm lines 2631–2642 at 09b1bd8 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-26.
Checked by a second AI model, 2026-10-26.
Sources
Code
- Xkeeper and kmck. 2023. “Super Mario Bros. 2, Discombobulated: a disassembly for asm6f (Xkeeper0/smb2).” Commit b73415e. Xkeeper0/smb2 @ b73415e · licence, all uses
- Southbird. 2025. “smb3: Super Mario Bros. 3 disassembly for NESASM (captainsouthbird/smb3).” Commit 09b1bd8. captainsouthbird/smb3 @ 09b1bd8 · licence, all uses
- Sonic Retro contributors. 2026. “skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm).” Commit 73de97c. sonicretro/skdisasm @ 73de97c · licence, all uses
- banjo.decomp. 2026. “banjo-kazooie: a decompilation of Banjo-Kazooie (banjo.decomp/banjo-kazooie).” Commit e8d31fa. banjo.decomp/banjo-kazooie @ e8d31fa · licence, all uses
- n64decomp. 2023. “sm64: a decompilation of Super Mario 64 (n64decomp/sm64).” Commit 9921382. n64decomp/sm64 @ 9921382 · licence, all uses
- doldecomp. 2026. “sms: a decompilation of Super Mario Sunshine (doldecomp/sms).” Commit d2cc8f5. doldecomp/sms @ d2cc8f5 · licence, all uses