On this page
  1. Related
  2. Games
  3. References
  4. Sources

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

GameYearHowNote
Super Mario Bros. 21988Hoverthe Princess hovers for up to 60 frames with the button held
Mega Man 61993Held heightthe Jet adaptor lifts him to a set height while A is held, until its meter runs out
Super Mario Sunshine2002Held heightFLUDD'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. 31988Run-upa full P-meter at take-off gives the Raccoon and Tanooki suits about 4¼ seconds of flight
Sonic 3 & Knuckles1994FlapTails · Tails flaps for a few seconds, each press lifting him
Banjo-Kazooie1998Slowed fallthe 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 & Knuckles1994Steady glideKnuckles · Knuckles glides, falling slowly while his speed builds
Every claim about this mechanic, by game (11)
Super Mario Bros. 2 1988The Princess's Floating Time is $3C; the other three have 0. With the button held once her rise has slowed to -$04 or less, each frame sets her vertical speed from FloatingYVelocity, 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.Verified
Super Mario Bros. 3 1988The 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 $28 or more. Each time Player_PMeterCnt reaches 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. While Player_FlyTime is 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.Verified
A jump with the meter full and no flight time left sets Player_FlyTime to $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 in PowerUp_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 -$18 while the timer is $0F or more, to -$10 from $0E to $08, and to 0 from $07 to $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 -$10 and 14 at 0, and the timer and meter run out 255 frames after the take-off.Verified
On the ground, Player_JumpFlyFlutter clears Player_FlyTime unless 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.Code
Out 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.Verified
Mega Man 6 1993With the Jet adaptor ($9B 1), holding A in the air while not rising and with jet energy left starts the jet. It slows his fall by 1/8 px/frame each frame until he would rise, holds him still for 10 frames, then lifts him from 2 px/frame, faster each frame, and holds him at 84 px ($54) above where he stopped; the d-pad steers him at 1 px/frame. Letting go of A, or running out of energy, drops him back into the fall.Code
The jet's energy $9C drains by 1 every 4 frames the jet runs, and the jet stops when it goes below 0, so a full meter of 20 steps (0 to 19) lasts 80 frames (computed). It refills by 1 every other frame up to 19, from empty in 40 frames (computed), while the jet's frame counter $9D is 0, which landing sets, and the buster is the weapon in hand.Code
Sonic 3 & Knuckles 1994Tails flies for 480 frames, a count of 240 that drops every other frame; flying adds $8 gravity a frame, and while time remains each press lifts him $20 a frame for up to 30 frames, until he rises faster than 1 px/frame.Code
Knuckles's glide starts at 4 px/frame and gains $4 a frame to a cap of 24 px/frame, and its fall settles near 0.5 px/frame, $20 added below $80 and taken above.Code
Banjo-Kazooie 1998With 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. Once D_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's act_jump checks B and Z but not A; its second jump comes from a press during a landing (sm64/double-jump).Code
Super Mario Sunshine 2002In 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 in MARIO_STATUS_ROCKET_LANDING, when he has FLUDD, the current nozzle's mRocketType parameter is 1, his upper body is in UPPER_STATE_PUMPING, and the nozzle is spraying (canSpray, a name a decompilers' comment calls fabricated), and sets a target height mHoverHeight (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 in rocketing runs only for the hover. Each update rocketing sets his vertical speed to the gap to the target times the parameter mAccelRate (default 0.03) and multiplies his forward speed by mBrake (default 0.95), the stick adding forward speed or turning him, and then jumpProcess moves 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 to mInsidePressure, and every update takes away mInsidePressureDec (default 100); when the pressure passes mInsidePressureMax (default 4500) while the spray is idle and the nozzle's mRumbleOnCharge is false, the spray starts with a timer of mTriggerTime updates (with mRumbleOnCharge true, 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 calls SPRAY_STATE_DEAD, which returns to idle only once R reads 0. Without a spray, rocketing ends in MARIO_STATUS_ROCKET_LANDING. On each update it sprays, each of the nozzle's emitters asks the water manager for drops, between mNumMin and mNum by the pressure, and the tank, which holds mAmountMax (default 2100), loses mDecRate for each drop accepted. Which nozzles have mRocketType 1, 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 notes

References

  1. ^ abcThe Princess's Floating Time is $3C; the other three have 0. With the button held once her rise has slowed to -$04 or less, each frame sets her vertical speed from FloatingYVelocity, 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 Discombobulated
    How 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.

    In the claim ledger

  2. ^ 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 $28 or more. Each time Player_PMeterCnt reaches 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. While Player_FlyTime is 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 disassembly
    How 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.

    In the claim ledger

  3. ^ abA jump with the meter full and no flight time left sets Player_FlyTime to $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 in PowerUp_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 -$18 while the timer is $0F or more, to -$10 from $0E to $08, and to 0 from $07 to $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 -$10 and 14 at 0, and the timer and meter run out 255 frames after the take-off.VerifiedSouthbird's SMB3 disassemblyrevised
    How 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.

    In the claim ledger

  4. ^ 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 disassembly
    How 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.

    In the claim ledger

  5. ^ abTails flies for 480 frames, a count of 240 that drops every other frame; flying adds $8 gravity a frame, and while time remains each press lifts him $20 a frame for up to 30 frames, until he rises faster than 1 px/frame.Codesonicretro/skdisasm
    How 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).l
    
    sonic3k.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.

    In the claim ledger

  6. ^ abKnuckles's glide starts at 4 px/frame and gains $4 a frame to a cap of 24 px/frame, and its fall settles near 0.5 px/frame, $20 added below $80 and taken above.Codesonicretro/skdisasmrevised
    How 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.

    In the claim ledger

  7. ^ 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. Once D_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's act_jump checks B and Z but not A; its second jump comes from a press during a landing (sm64/double-jump).Codebanjo.decomp/banjo-kazooie · n64decomp/sm64revised
    How 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.

    In the claim ledger

  8. ^ 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 in MARIO_STATUS_ROCKET_LANDING, when he has FLUDD, the current nozzle's mRocketType parameter is 1, his upper body is in UPPER_STATE_PUMPING, and the nozzle is spraying (canSpray, a name a decompilers' comment calls fabricated), and sets a target height mHoverHeight (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 in rocketing runs only for the hover. Each update rocketing sets his vertical speed to the gap to the target times the parameter mAccelRate (default 0.03) and multiplies his forward speed by mBrake (default 0.95), the stick adding forward speed or turning him, and then jumpProcess moves 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 to mInsidePressure, and every update takes away mInsidePressureDec (default 100); when the pressure passes mInsidePressureMax (default 4500) while the spray is idle and the nozzle's mRumbleOnCharge is false, the spray starts with a timer of mTriggerTime updates (with mRumbleOnCharge true, 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 calls SPRAY_STATE_DEAD, which returns to idle only once R reads 0. Without a spray, rocketing ends in MARIO_STATUS_ROCKET_LANDING. On each update it sprays, each of the nozzle's emitters asks the water manager for drops, between mNumMin and mNum by the pressure, and the tank, which holds mAmountMax (default 2100), loses mDecRate for each drop accepted. Which nozzles have mRocketType 1, 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-kazooierevised
    How 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.

    In the claim ledger

  9. ^On the ground, Player_JumpFlyFlutter clears Player_FlyTime unless 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 disassembly
    How 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.

    In the claim ledger

Sources

Code