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

The atlas reads Super Mario Sunshine through the doldecomp decompilation, C++ that builds five versions, the Japanese one by default. Names and comments quoted here are the decompilers’. Nearly all of Mario’s code and FLUDD’s is decompiled but doesn’t yet match the game’s own, and the claims say so. Most movement constants are named parameters with a default in the code, which a file on the disc can replace1. The atlas hasn’t read those files, so the numbers here are the defaults.

A jump takes off at 42 plus a quarter of Mario’s forward speed, the same take-off as Super Mario 642,3. Letting go of A while he rises faster than 20 multiplies his upward speed by 0.75 on each update, where Super Mario 64 divides it by 4 each frame2. The status numbers carry over too: the jump’s ends in 0x880 in both games, and the bit that lets a release cut the rise is the same2. Each update moves Mario only a quarter of his velocity, so a speed moves him a quarter as far per update as it does per frame in Super Mario 641.

The triple jump follows a landing from a double jump, a backflip, or a spin jump, and takes off by default at 70 plus a quarter of the speed, where Super Mario 64’s is a flat 694. The wall jump keeps Super Mario 64’s take-off of 62 up and 24 forward, but a wall hit holds Mario on the wall until he presses A or reaches the floor, with no 7-frame window5,6.

FLUDD’s hover nozzle eases Mario toward a height above where the hover began, 160 units by default, closing a set fraction of the gap each update. It lasts until the spray’s timer runs out, the pumping stops, or the tank empties7. Banjo-Kazooie’s Feathery Flap slows a fall instead8.

Mechanics

MechanicKindHow
JumpSpeed from the run42 plus a quarter of the forward speed, Super Mario 64's take-off, with each update moving Mario a quarter of his velocity
GravityOne gravitya parameter, 0.8 an update by default, down to −75, with a lighter one in a spin jump's descent
Variable jump heightRelease cutwith A up while Mario rises faster than 20, in a status without bits 0x1000 and 0x20000, each update multiplies the rise by 0.75 in place of the gravity; the triple jump can't be cut
Triple jumpLanding chaina press within 15 updates of landing from a double jump, a backflip, or a spin jump starts it at 20 forward or more, by default at 70 plus a quarter of the speed
Wall jumpWall slidea wall hit above 16 forward holds Mario on the wall, sliding ever faster after 10 updates, and A at any point kicks him off at 62 up and 24 forward
FlightHeld 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
Every claim about this game, by concept (5)
FlightIn 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
GravityIn the doldecomp decompilation of Super Mario Sunshine, most of Mario's movement constants are named parameters (TParamRT), each built with a default in the code, in sets that each name a file, such as /Mario/Jump.prm. TParams::load, in a file configure.py marks as matching the game's code, reads the set's file from the scene's /map/params folder if it is there and from the params archive if not, and a record whose key and name match a parameter replaces that parameter's default; the rest keep theirs. The values the game plays with are data on the disc, which the atlas hasn't read, so the numbers in these claims are the code's defaults. The jump set's gravity, mGravity, defaults to 0.8. In the jumping states, jumpProcess in the decompilers' Player code, which doesn't yet match, moves Mario by a quarter of his velocity in one step per update. Then fallProcess subtracts mGravity from his vertical speed, except in a dive (the dive set's own gravity, with a cap of its own), in a spin jump's descent (mSpinJumpGravity, default 0.6), and when a release cuts the rise (sms/jump); in every case it then caps the fall at −75. Super Mario 64 also moves Mario a quarter of his velocity at a time, but in four steps a frame (sm64/units).Code notes
JumpIn Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, a press that starts a jump through changePlayerJumping first goes to a miss jump if isJumpMiss is true, then to a spin jump if considerRotateJumpStart reads the stick's recent turning as a spin, and otherwise to the status it asks for. For the single jump, MARIO_STATUS_JUMP, setStatusToJumping sets Mario's vertical speed to 42 plus a quarter of his forward speed and multiplies the forward speed by 0.8, constants in the code rather than parameters, and the same take-off as Super Mario 64's single jump (sm64/jump-speed). On two kinds of floor, which the code tells apart only as isThing2 and isThing3, the speed is replaced or added to and the jump becomes MARIO_STATUS_FORCE_JUMP; on Yoshi it is multiplied by the parameter mJumpYoshiMult, and while isSinking() is true both speeds are scaled by a factor from the mGraffitoParams set. When the new jumping status carries the bit the code calls MARIO_STATUS_FLAG_UNK2000000 (0x2000000), as the single jump, the double jump, and the wall kick do, setStatusToJumping sets bit 0x100 of unk78, and it clears that bit for any other jumping status (other code clears it too). While that bit is set, the status has neither bit 0x1000 nor 0x20000, A isn't held, and Mario rises faster than 20, fallProcess multiplies his vertical speed by 0.75 on each update in place of the gravity. Super Mario 64 divides it by 4 on each frame when A isn't held and Mario rises faster than 20, if its MARIO_UNKNOWN_08 flag is set, the action is neither intangible nor invulnerable, and the action has ACT_FLAG_CONTROL_JUMP_HEIGHT, the same bit, 0x02000000 (sm64/jump-release). The status numbers line up too: Sunshine's single jump is 0x2000000 | 0x800 | 0x080 (computed 0x2000880), and Super Mario 64's ACT_JUMP is 0x03000880.Code notes
Triple jumpIn Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, the double jump, the backflip (MARIO_STATUS_BACK_JUMP), the spin jump, and the jumps the code calls trample and wireJumping all land in MARIO_STATUS_SEC_JUMP_SLIP. Its jumpSlipEvents counts updates and ends the landing on the 16th, before reading A, so a press on one of the first 15 (computed) goes to changePlayerJumping, which can still turn it into a miss or spin jump (sms/jump): the triple jump, MARIO_STATUS_ULTRA_JUMP, if the forward speed is at least the parameter mTriJumpEnableSp (default 20), and a single jump if not. The single jump and the wall kick land in MARIO_STATUS_JUMP_SLIP instead, where a press makes a double jump only at a forward speed of at least mSecJumpEnableSp (default 20). The triple jump takes off at mUltraJumpForce plus mUltraJumpSpeedMult times the forward speed (defaults 70 and 0.25) and multiplies the forward speed by mUltraJumpXZMult (default 0.8); its status lacks the bit that lets a release cut the rise. Super Mario 64's triple jump starts from the double jump's 4-frame landing at a forward speed above 20, takes off at 69 whatever the speed, and can't be cut either (sm64/triple-jump, sm64/jump-release).Code notes
Wall jumpIn Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, when jumpProcess reports a wall to jumpingBasic during a jump, Mario is knocked back if his forward speed is above the parameter mClashSpeed (default 50) outside the wire roll jump, stops on Yoshi, stops on a wall marked isNoWallJump, and catches a fence (isFence). Otherwise, at a forward speed above 16, he turns about (after playerRefrection) and, against a wall, holds on in MARIO_STATUS_WALL_SLIDE. There stayWall adds 1 to the status timer each update, capped at 60, and 1 more while it is below 20, so he hangs still for 10 updates and then slides down at half the timer: −10.5 on the 11th update, then 0.5 faster each update to −30 (computed). An A press on any update on the wall kicks: startJumpWall turns him about and enters MARIO_STATUS_WALL_JUMP, whose take-off in setStatusToJumping is 62 up and 24 forward, constants in the code; the 52 that startJumpWall writes first is overwritten. Landing or losing the wall ends the hold. Super Mario 64 kicks at the same 62 up and at least 24 forward, and its act_air_hit_wall also writes a 52 that the kick's take-off overwrites, but it holds Mario only 2 frames and then bonks him away, with A still working for 5 more: 7 frames in all (sm64/wall-kick). With no wall to hold, Sunshine bonks him the way Super Mario 64 does: back down at 38 or faster, and at −8 if faster than 8.Code notes

References

  1. ^ abIn the doldecomp decompilation of Super Mario Sunshine, most of Mario's movement constants are named parameters (TParamRT), each built with a default in the code, in sets that each name a file, such as /Mario/Jump.prm. TParams::load, in a file configure.py marks as matching the game's code, reads the set's file from the scene's /map/params folder if it is there and from the params archive if not, and a record whose key and name match a parameter replaces that parameter's default; the rest keep theirs. The values the game plays with are data on the disc, which the atlas hasn't read, so the numbers in these claims are the code's defaults. The jump set's gravity, mGravity, defaults to 0.8. In the jumping states, jumpProcess in the decompilers' Player code, which doesn't yet match, moves Mario by a quarter of his velocity in one step per update. Then fallProcess subtracts mGravity from his vertical speed, except in a dive (the dive set's own gravity, with a cap of its own), in a spin jump's descent (mSpinJumpGravity, default 0.6), and when a release cuts the rise (sms/jump); in every case it then caps the fall at −75. Super Mario 64 also moves Mario a quarter of his velocity at a time, but in four steps a frame (sm64/units).Code notesdoldecomp/sms · n64decomp/sm64revised
    How we know
    314Matching = True                   # Object matches and should be linked
    315NonMatching = False               # Object does not match and should not be linked
    
    configure.py lines 314–315 at d2cc8f5 · upstream ↗
    879            Object(Matching, "System/Params.cpp"),
    
    configure.py line 879 at d2cc8f5 · upstream ↗
    950            Object(NonMatching, "Player/MarioPhysics.cpp"),
    
    configure.py line 950 at d2cc8f5 · upstream ↗
    964            PCHObject(NonMatching, "Player/MarioInit.cpp"),
    
    configure.py line 964 at d2cc8f5 · upstream ↗
    8#define PARAM_INIT(member, defaultValue)                                       \
    9	member(this, defaultValue, JDrama::TNameRef::calcKeyCode(#member), #member)
    
    include/System/ParamInst.hpp lines 8–9 at d2cc8f5 · upstream ↗
    12	if (mHead != nullptr) {
    13		s32 length = stream.readS32();
    14		for (int i = 0; i < length; i++) {
    15			u16 keyCode = stream.read16b();
    ⋮
    21				if (keyCode == param->keyCode && !strcmp(buffer, param->name)) {
    22					param->load(stream);
    23					break;
    ⋮
    26			if (param == nullptr) {
    27				s32 end = stream.read32b();
    28				stream.skip(end);
    
    src/System/Params.cpp lines 12–29 at d2cc8f5 · upstream ↗
    54	if (mSceneArc != nullptr && mSceneArc->becomeCurrent(SceneParamsDir)) {
    55		resource = mSceneArc->getResource(filename);
    ⋮
    64		if (mArc != nullptr) {
    65			mArc->becomeCurrent("/");
    66			void* resource2 = mArc->getResource(filename);
    
    src/System/Params.cpp lines 54–66 at d2cc8f5 · upstream ↗
    5static const char SceneParamsDir[] = "/map/params";
    
    src/System/Params.cpp line 5 at d2cc8f5 · upstream ↗
    544TMario::TJumpParams::TJumpParams()
    545    : TParams("/Mario/Jump.prm")
    546    , PARAM_INIT(mGravity, 0.8f)
    547    , PARAM_INIT(mSpinJumpGravity, 0.6f)
    
    src/Player/MarioInit.cpp lines 544–547 at d2cc8f5 · upstream ↗
    498	Vec next;
    499	next.x  = mPosition.x + 0.25f * mVel.x;
    500	next.y  = mPosition.y + 0.25f * mVel.y;
    501	next.z  = mPosition.z + 0.25f * mVel.z;
    502	int ret = checkGroundAtJumping(next, param_1);
    ⋮
    509	fallProcess();
    
    src/Player/MarioPhysics.cpp lines 498–509 at d2cc8f5 · upstream ↗
    464void TMario::fallProcess()
    ⋮
    466	if (mStatus == MARIO_STATUS_DIVE) {
    467		mVel.y -= mDivingParams.mGravity.get();
    468		if (mVel.y < -75.0f)
    469			mVel.y = -75.0f;
    470	} else {
    471		if (isFallCancel()) {
    472			mVel.y *= 0.75f;
    473		} else if ((mStatus == MARIO_STATUS_LEFT_ROTATE_JUMP
    474		            || mStatus == MARIO_STATUS_RIGHT_ROTATE_JUMP)
    475		           && mVel.y < 0.0f) {
    476			mVel.y -= mJumpParams.mSpinJumpGravity.get();
    ⋮
    
    src/Player/MarioPhysics.cpp lines 464–485 at d2cc8f5 · upstream ↗
    618    for (i = 0; i < 4; i++) {
    619        intendedPos[0] = m->pos[0] + m->vel[0] / 4.0f;
    620        intendedPos[1] = m->pos[1] + m->vel[1] / 4.0f;
    621        intendedPos[2] = m->pos[2] + m->vel[2] / 4.0f;
    
    src/game/mario_step.c lines 618–621 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

  2. ^ abcIn Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, a press that starts a jump through changePlayerJumping first goes to a miss jump if isJumpMiss is true, then to a spin jump if considerRotateJumpStart reads the stick's recent turning as a spin, and otherwise to the status it asks for. For the single jump, MARIO_STATUS_JUMP, setStatusToJumping sets Mario's vertical speed to 42 plus a quarter of his forward speed and multiplies the forward speed by 0.8, constants in the code rather than parameters, and the same take-off as Super Mario 64's single jump (sm64/jump-speed). On two kinds of floor, which the code tells apart only as isThing2 and isThing3, the speed is replaced or added to and the jump becomes MARIO_STATUS_FORCE_JUMP; on Yoshi it is multiplied by the parameter mJumpYoshiMult, and while isSinking() is true both speeds are scaled by a factor from the mGraffitoParams set. When the new jumping status carries the bit the code calls MARIO_STATUS_FLAG_UNK2000000 (0x2000000), as the single jump, the double jump, and the wall kick do, setStatusToJumping sets bit 0x100 of unk78, and it clears that bit for any other jumping status (other code clears it too). While that bit is set, the status has neither bit 0x1000 nor 0x20000, A isn't held, and Mario rises faster than 20, fallProcess multiplies his vertical speed by 0.75 on each update in place of the gravity. Super Mario 64 divides it by 4 on each frame when A isn't held and Mario rises faster than 20, if its MARIO_UNKNOWN_08 flag is set, the action is neither intangible nor invulnerable, and the action has ACT_FLAG_CONTROL_JUMP_HEIGHT, the same bit, 0x02000000 (sm64/jump-release). The status numbers line up too: Sunshine's single jump is 0x2000000 | 0x800 | 0x080 (computed 0x2000880), and Super Mario 64's ACT_JUMP is 0x03000880.Code notesdoldecomp/sms · n64decomp/sm64revised
    How we know
    949            PCHObject(NonMatching, "Player/MarioMove.cpp"),
    950            Object(NonMatching, "Player/MarioPhysics.cpp"),
    
    configure.py lines 949–950 at d2cc8f5 · upstream ↗
    764int TMario::changePlayerJumping(u32 param_1, u32 param_2)
    ⋮
    766	if (isJumpMiss()) {
    767		setMissJumping();
    768	} else {
    769		if (considerRotateJumpStart())
    770			return 1;
    ⋮
    772		changePlayerStatus(param_1, param_2, false);
    
    src/Player/MarioMove.cpp lines 764–772 at d2cc8f5 · upstream ↗
    420void TMario::setPlayerJumpSpeed(f32 speed_mult, f32 force)
    ⋮
    422	mVel.y = (mForwardVel * speed_mult) + force;
    
    src/Player/MarioMove.cpp lines 420–423 at d2cc8f5 · upstream ↗
    434	switch (status) {
    435	case MARIO_STATUS_JUMP:
    436	case 0x89C:
    437		setPlayerJumpSpeed(0.25f, 42.0f);
    438		mForwardVel *= 0.8f;
    ⋮
    441			if (mGroundPlane->isThing2()) {
    442				mVel.y     = 0.01f * mGroundPlane->getActiveJumpPower();
    443				nextStatus = MARIO_STATUS_FORCE_JUMP;
    ⋮
    445			} else if (mGroundPlane->isThing3()) {
    446				mVel.y += -unkBC + getGroundJumpPower();
    ⋮
    453				nextStatus = MARIO_STATUS_FORCE_JUMP;
    
    src/Player/MarioMove.cpp lines 434–456 at d2cc8f5 · upstream ↗
    647	if (isSinking()) {
    648		f32 scale = ((mGraffitoParams.mSinkJumpRateMax.get()
    ⋮
    653		mVel.y *= scale;
    654		mForwardVel *= scale;
    
    src/Player/MarioMove.cpp lines 647–654 at d2cc8f5 · upstream ↗
    663	if (onYoshi()) {
    664		mVel.y *= mYoshiParams.mJumpYoshiMult.get();
    ⋮
    670	if (nextStatus & MARIO_STATUS_FLAG_UNK2000000)
    671		unk78 |= 0x100;
    672	else
    673		unk78 &= ~0x100;
    
    src/Player/MarioMove.cpp lines 663–673 at d2cc8f5 · upstream ↗
    1482	if (mGamePad->checkMeaning(TMarioGamePad::MEANING_A))
    1483		mInput |= 0x80;
    
    src/Player/MarioMove.cpp lines 1482–1483 at d2cc8f5 · upstream ↗
    450BOOL TMario::isFallCancel()
    ⋮
    452	if (!(unk78 & 0x100 ? true : false))
    453		return false;
    ⋮
    455	if (mStatus & 0x21000)
    456		return false;
    ⋮
    458	if (!(mInput & 0x80) && mVel.y > 20.0f)
    459		return true;
    
    src/Player/MarioPhysics.cpp lines 450–459 at d2cc8f5 · upstream ↗
    471		if (isFallCancel()) {
    472			mVel.y *= 0.75f;
    
    src/Player/MarioPhysics.cpp lines 471–472 at d2cc8f5 · upstream ↗
    7	MARIO_STATUS_FLAG_JUMPING     = 0x800,
    
    include/Player/MarioStatus.hpp line 7 at d2cc8f5 · upstream ↗
    17	MARIO_STATUS_FLAG_UNK2000000  = 0x2000000,
    
    include/Player/MarioStatus.hpp line 17 at d2cc8f5 · upstream ↗
    26	MARIO_STATUS_TYPE_JUMPING  = 0x080,
    
    include/Player/MarioStatus.hpp line 26 at d2cc8f5 · upstream ↗
    119	MARIO_STATUS_JUMP = MARIO_STATUS_FLAG_UNK2000000 | MARIO_STATUS_FLAG_JUMPING
    120	                    | MARIO_STATUS_TYPE_JUMPING | 0x0, // 0x2000880
    121	MARIO_STATUS_SECOND_JUMP = MARIO_STATUS_FLAG_UNK2000000
    122	                           | MARIO_STATUS_FLAG_JUMPING
    ⋮
    130	MARIO_STATUS_WALL_JUMP = MARIO_STATUS_FLAG_UNK2000000
    131	                         | MARIO_STATUS_FLAG_JUMPING
    
    include/Player/MarioStatus.hpp lines 119–133 at d2cc8f5 · upstream ↗
    821        case ACT_JUMP:
    822        case ACT_HOLD_JUMP:
    ⋮
    824            set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f);
    825            m->forwardVel *= 0.8f;
    
    src/game/mario.c lines 821–825 at 9921382 · upstream ↗
    763static void set_mario_y_vel_based_on_fspeed(struct MarioState *m, f32 initialVelY, f32 multiplier) {
    ⋮
    766    m->vel[1] = initialVelY + get_additive_y_vel_for_jumps() + m->forwardVel * multiplier;
    
    src/game/mario.c lines 763–766 at 9921382 · upstream ↗
    519u32 should_strengthen_gravity_for_jump_ascent(struct MarioState *m) {
    520    if (!(m->flags & MARIO_UNKNOWN_08)) {
    521        return FALSE;
    ⋮
    524    if (m->action & (ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)) {
    525        return FALSE;
    ⋮
    528    if (!(m->input & INPUT_A_DOWN) && m->vel[1] > 20.0f) {
    529        return (m->action & ACT_FLAG_CONTROL_JUMP_HEIGHT) != 0;
    
    src/game/mario_step.c lines 519–529 at 9921382 · upstream ↗
    559    } else if (should_strengthen_gravity_for_jump_ascent(m)) {
    560        m->vel[1] /= 4.0f;
    
    src/game/mario_step.c lines 559–560 at 9921382 · upstream ↗
    165#define ACT_FLAG_CONTROL_JUMP_HEIGHT         /* 0x02000000 */ (1 << 25)
    
    include/sm64.h line 165 at 9921382 · upstream ↗
    256#define ACT_JUMP                       0x03000880 // (0x080 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
    
    include/sm64.h line 256 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

  3. ^A single jump sets Mario's vertical speed to 42 plus a quarter of his forward speed, in units per frame, and multiplies the forward speed by 0.8.Coden64decomp/sm64
    How we know
    763static void set_mario_y_vel_based_on_fspeed(struct MarioState *m, f32 initialVelY, f32 multiplier) {
    ⋮
    766    m->vel[1] = initialVelY + get_additive_y_vel_for_jumps() + m->forwardVel * multiplier;
    
    src/game/mario.c lines 763–766 at 9921382 · upstream ↗
    821        case ACT_JUMP:
    822        case ACT_HOLD_JUMP:
    ⋮
    824            set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f);
    825            m->forwardVel *= 0.8f;
    
    src/game/mario.c lines 821–826 at 9921382 · 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

  4. ^In Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, the double jump, the backflip (MARIO_STATUS_BACK_JUMP), the spin jump, and the jumps the code calls trample and wireJumping all land in MARIO_STATUS_SEC_JUMP_SLIP. Its jumpSlipEvents counts updates and ends the landing on the 16th, before reading A, so a press on one of the first 15 (computed) goes to changePlayerJumping, which can still turn it into a miss or spin jump (sms/jump): the triple jump, MARIO_STATUS_ULTRA_JUMP, if the forward speed is at least the parameter mTriJumpEnableSp (default 20), and a single jump if not. The single jump and the wall kick land in MARIO_STATUS_JUMP_SLIP instead, where a press makes a double jump only at a forward speed of at least mSecJumpEnableSp (default 20). The triple jump takes off at mUltraJumpForce plus mUltraJumpSpeedMult times the forward speed (defaults 70 and 0.25) and multiplies the forward speed by mUltraJumpXZMult (default 0.8); its status lacks the bit that lets a release cut the rise. Super Mario 64's triple jump starts from the double jump's 4-frame landing at a forward speed above 20, takes off at 69 whatever the speed, and can't be cut either (sm64/triple-jump, sm64/jump-release).Code notesdoldecomp/sms · n64decomp/sm64revised
    How we know
    947            Object(NonMatching, "Player/MarioJump.cpp"),
    ⋮
    949            PCHObject(NonMatching, "Player/MarioMove.cpp"),
    ⋮
    952            PCHObject(NonMatching, "Player/MarioRun.cpp"),
    ⋮
    964            PCHObject(NonMatching, "Player/MarioInit.cpp"),
    
    configure.py lines 947–964 at d2cc8f5 · upstream ↗
    341BOOL TMario::secJumping()
    ⋮
    357	jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, anim, 3);
    
    src/Player/MarioJump.cpp lines 341–357 at d2cc8f5 · upstream ↗
    378BOOL TMario::backJumping()
    ⋮
    390		jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, 0xF7, 0);
    391	else
    392		jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, ANIM_LAND, 0);
    
    src/Player/MarioJump.cpp lines 378–392 at d2cc8f5 · upstream ↗
    773BOOL TMario::trample()
    ⋮
    778	jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, mAnimationId, 3);
    
    src/Player/MarioJump.cpp lines 773–778 at d2cc8f5 · upstream ↗
    997BOOL TMario::rotateJumping()
    ⋮
    1007	jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, mAnimationId, 0);
    
    src/Player/MarioJump.cpp lines 997–1007 at d2cc8f5 · upstream ↗
    1021BOOL TMario::wireJumping()
    ⋮
    1035	jumpingBasic(MARIO_STATUS_SEC_JUMP_SLIP, mAnimationId, 3);
    
    src/Player/MarioJump.cpp lines 1021–1035 at d2cc8f5 · upstream ↗
    335		jumpingBasic(MARIO_STATUS_JUMP_SLIP, ANIM_JUMP, 3);
    
    src/Player/MarioJump.cpp line 335 at d2cc8f5 · upstream ↗
    454	jumpingBasic(MARIO_STATUS_JUMP_SLIP, ANIM_WJMP, 3);
    
    src/Player/MarioJump.cpp line 454 at d2cc8f5 · upstream ↗
    1538BOOL TMario::jumpSlipEvents(JumpSlipRecord* rec)
    ⋮
    1541		return changePlayerStatus(rec->mEndStatus, 0, false);
    ⋮
    1543	mStatusTimer++;
    ⋮
    1545	if (mStatusTimer >= rec->mMaxTimer)
    1546		return changePlayerStatus(rec->mEndStatus, 0, false);
    ⋮
    1548	if (mInput & 0x2) {
    1549		if (rec->mJumpStatus == MARIO_STATUS_SECOND_JUMP)
    1550			if (mForwardVel >= mJumpParams.mSecJumpEnableSp.get())
    1551				return changePlayerJumping(MARIO_STATUS_SECOND_JUMP, 0);
    ⋮
    1553		if (rec->mJumpStatus == MARIO_STATUS_ULTRA_JUMP)
    1554			if (mForwardVel >= mJumpParams.mTriJumpEnableSp.get())
    1555				return changePlayerJumping(MARIO_STATUS_ULTRA_JUMP, 0);
    ⋮
    
    src/Player/MarioRun.cpp lines 1538–1557 at d2cc8f5 · upstream ↗
    1599BOOL TMario::secJumpSlip()
    ⋮
    1601	static TMario::JumpSlipRecord param
    1602	    = { 0x10, MARIO_STATUS_SEC_JUMP_END, MARIO_STATUS_ULTRA_JUMP,
    
    src/Player/MarioRun.cpp lines 1599–1602 at d2cc8f5 · upstream ↗
    471	case MARIO_STATUS_ULTRA_JUMP:
    472		setPlayerJumpSpeed(mJumpParams.mUltraJumpSpeedMult.get(),
    473		                   mJumpParams.mUltraJumpForce.get());
    474		mForwardVel *= mJumpParams.mUltraJumpXZMult.get();
    
    src/Player/MarioMove.cpp lines 471–474 at d2cc8f5 · upstream ↗
    572    , PARAM_INIT(mSecJumpEnableSp, 20.0f)
    ⋮
    576    , PARAM_INIT(mTriJumpEnableSp, 20.0f)
    577    , PARAM_INIT(mUltraJumpForce, 70.0f)
    578    , PARAM_INIT(mUltraJumpSpeedMult, 0.25f)
    579    , PARAM_INIT(mUltraJumpXZMult, 0.8f)
    
    src/Player/MarioInit.cpp lines 572–579 at d2cc8f5 · upstream ↗
    124	MARIO_STATUS_ULTRA_JUMP
    125	= MARIO_STATUS_FLAG_JUMPING | MARIO_STATUS_TYPE_JUMPING | 0x2, // 0x882
    
    include/Player/MarioStatus.hpp lines 124–125 at d2cc8f5 · upstream ↗
    1874s32 act_double_jump_land(struct MarioState *m) {
    1875    if (common_landing_cancels(m, &sDoubleJumpLandAction, set_triple_jump_action)) {
    
    src/game/mario_actions_moving.c lines 1874–1875 at 9921382 · upstream ↗
    50struct LandingAction sDoubleJumpLandAction = {
    51    4, 5, ACT_FREEFALL, ACT_DOUBLE_JUMP_LAND_STOP, ACT_JUMP, ACT_FREEFALL, ACT_BEGIN_SLIDING,
    
    src/game/mario_actions_moving.c lines 50–51 at 9921382 · upstream ↗
    150    } else if (m->forwardVel > 20.0f) {
    151        return set_mario_action(m, ACT_TRIPLE_JUMP, 0);
    
    src/game/mario_actions_moving.c lines 150–151 at 9921382 · upstream ↗
    796        case ACT_TRIPLE_JUMP:
    797            set_mario_y_vel_based_on_fspeed(m, 69.0f, 0.0f);
    798            m->forwardVel *= 0.8f;
    
    src/game/mario.c lines 796–798 at 9921382 · upstream ↗
    258#define ACT_TRIPLE_JUMP                0x01000882 // (0x082 | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
    
    include/sm64.h line 258 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

  5. ^In Super Mario Sunshine, by the decompilers' Player code, which doesn't yet match, when jumpProcess reports a wall to jumpingBasic during a jump, Mario is knocked back if his forward speed is above the parameter mClashSpeed (default 50) outside the wire roll jump, stops on Yoshi, stops on a wall marked isNoWallJump, and catches a fence (isFence). Otherwise, at a forward speed above 16, he turns about (after playerRefrection) and, against a wall, holds on in MARIO_STATUS_WALL_SLIDE. There stayWall adds 1 to the status timer each update, capped at 60, and 1 more while it is below 20, so he hangs still for 10 updates and then slides down at half the timer: −10.5 on the 11th update, then 0.5 faster each update to −30 (computed). An A press on any update on the wall kicks: startJumpWall turns him about and enters MARIO_STATUS_WALL_JUMP, whose take-off in setStatusToJumping is 62 up and 24 forward, constants in the code; the 52 that startJumpWall writes first is overwritten. Landing or losing the wall ends the hold. Super Mario 64 kicks at the same 62 up and at least 24 forward, and its act_air_hit_wall also writes a 52 that the kick's take-off overwrites, but it holds Mario only 2 frames and then bonks him away, with A still working for 5 more: 7 frames in all (sm64/wall-kick). With no wall to hold, Sunshine bonks him the way Super Mario 64 does: back down at 38 or faster, and at −8 if faster than 8.Code notesdoldecomp/sms · n64decomp/sm64revised
    How we know
    947            Object(NonMatching, "Player/MarioJump.cpp"),
    ⋮
    949            PCHObject(NonMatching, "Player/MarioMove.cpp"),
    950            Object(NonMatching, "Player/MarioPhysics.cpp"),
    ⋮
    964            PCHObject(NonMatching, "Player/MarioInit.cpp"),
    
    configure.py lines 947–964 at d2cc8f5 · upstream ↗
    201	case 2:
    202		if (mStatus != MARIO_STATUS_WIRE_ROLL_JUMP
    203		    && mForwardVel > mDeParams.mClashSpeed.get()) {
    ⋮
    205			changePlayerDropping(MARIO_STATUS_JUMP_SHORT_BACK_DOWN, 0U);
    ⋮
    209		if (onYoshi()) {
    210			setPlayerVelocity(0.0f);
    ⋮
    213		if (mWallPlane != nullptr) {
    214			if (mWallPlane->isNoWallJump()) {
    ⋮
    216				setPlayerVelocity(0.0f);
    ⋮
    220		if (mWallPlane != nullptr) {
    221			if (mWallPlane->isFence()) {
    ⋮
    228				return changePlayerStatus(MARIO_STATUS_FENCE_JUMP_CATCH, 0, 0);
    ⋮
    
    src/Player/MarioJump.cpp lines 201–250 at d2cc8f5 · upstream ↗
    252			if (mForwardVel > 8.0f)
    253				setPlayerVelocity(-8.0f);
    254			return changePlayerStatus(MARIO_STATUS_LAND_SAFE_DOWN, 0, 0);
    
    src/Player/MarioJump.cpp lines 252–254 at d2cc8f5 · upstream ↗
    510    , PARAM_INIT(mClashSpeed, 50.0f)
    
    src/Player/MarioInit.cpp line 510 at d2cc8f5 · upstream ↗
    586BOOL TMario::stayWall()
    ⋮
    588	mStatusTimer += 1;
    589	if (mStatusTimer > 60)
    590		mStatusTimer = 60;
    ⋮
    592	if (mInput & 2)
    593		return startJumpWall();
    ⋮
    598	if (mStatusTimer < 20) {
    599		mStatusTimer += 1;
    600		mVel.set(0.0f, 0.0f, 0.0f);
    601	} else {
    602		mVel.y = -mStatusTimer * 0.5f;
    ⋮
    610	switch (jumpProcess(0)) {
    ⋮
    
    src/Player/MarioJump.cpp lines 586–620 at d2cc8f5 · upstream ↗
    16BOOL TMario::startJumpWall()
    ⋮
    25	mVel.y = 52.0f;
    26	mFaceAngle.y += 0x8000;
    27	if (mVel.y + (160.0f + mPosition.y) >= mFloorPosition.x)
    28		mVel.y = 1.0f;
    ⋮
    30	return changePlayerStatus(MARIO_STATUS_WALL_JUMP, 0, 0);
    
    src/Player/MarioJump.cpp lines 16–30 at d2cc8f5 · upstream ↗
    517	case MARIO_STATUS_WALL_JUMP:
    518		setPlayerJumpSpeed(0.0f, 62.0f);
    519		mForwardVel = 24.0f;
    
    src/Player/MarioMove.cpp lines 517–519 at d2cc8f5 · upstream ↗
    733	switch (status & MARIO_STATUS_TYPE_MASK) {
    ⋮
    737	case MARIO_STATUS_TYPE_JUMPING:
    738		status = setStatusToJumping(status, arg);
    
    src/Player/MarioMove.cpp lines 733–738 at d2cc8f5 · upstream ↗
    1479	if (mGamePad->checkFrameMeaning(TMarioGamePad::MEANING_A))
    1480		mInput |= 0x2;
    
    src/Player/MarioMove.cpp lines 1479–1480 at d2cc8f5 · upstream ↗
    1314    if (++(m->actionTimer) <= 2) {
    1315        if (m->input & INPUT_A_PRESSED) {
    1316            m->vel[1] = 52.0f;
    1317            m->faceAngle[1] += 0x8000;
    1318            return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
    ⋮
    1320    } else if (m->forwardVel >= 38.0f) {
    1321        m->wallKickTimer = 5;
    ⋮
    1327        return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0);
    ⋮
    1329        m->wallKickTimer = 5;
    ⋮
    1334        if (m->forwardVel > 8.0f) {
    1335            mario_set_forward_vel(m, -8.0f);
    ⋮
    1337        return set_mario_action(m, ACT_SOFT_BONK, 0);
    
    src/game/mario_actions_airborne.c lines 1314–1337 at 9921382 · upstream ↗
    1147s32 check_wall_kick(struct MarioState *m) {
    1148    if ((m->input & INPUT_A_PRESSED) && m->wallKickTimer != 0 && m->prevAction == ACT_AIR_HIT_WALL) {
    1149        m->faceAngle[1] += 0x8000;
    1150        return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
    
    src/game/mario_actions_airborne.c lines 1147–1151 at 9921382 · upstream ↗
    1407    if (m->wallKickTimer > 0) {
    1408        m->wallKickTimer--;
    
    src/game/mario.c lines 1407–1409 at 9921382 · upstream ↗
    828        case ACT_WALL_KICK_AIR:
    829        case ACT_TOP_OF_POLE_JUMP:
    830            set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
    831            if (m->forwardVel < 24.0f) {
    832                m->forwardVel = 24.0f;
    
    src/game/mario.c lines 828–833 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

  6. ^A jump that hits a wall at a forward speed above 16 turns Mario around and holds him in ACT_AIR_HIT_WALL. A press on its first 2 frames kicks off the wall. On the 3rd he bonks away, wallKickTimer is set to 5 and counts down once a frame, and A still kicks while it is nonzero: 7 frames in all. The kick takes off at 62 units/frame up and at least 24 forward.Coden64decomp/sm64revised
    How we know
    388        case AIR_STEP_HIT_WALL:
    ⋮
    391            if (m->forwardVel > 16.0f) {
    ⋮
    396                m->faceAngle[1] += 0x8000;
    ⋮
    399                    set_mario_action(m, ACT_AIR_HIT_WALL, 0);
    
    src/game/mario_actions_airborne.c lines 388–399 at 9921382 · upstream ↗
    1314    if (++(m->actionTimer) <= 2) {
    1315        if (m->input & INPUT_A_PRESSED) {
    ⋮
    1318            return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
    ⋮
    1320    } else if (m->forwardVel >= 38.0f) {
    1321        m->wallKickTimer = 5;
    ⋮
    1327        return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0);
    1328    } else {
    1329        m->wallKickTimer = 5;
    ⋮
    1337        return set_mario_action(m, ACT_SOFT_BONK, 0);
    
    src/game/mario_actions_airborne.c lines 1314–1337 at 9921382 · upstream ↗
    1156s32 act_backward_air_kb(struct MarioState *m) {
    1157    if (check_wall_kick(m)) {
    1158        return TRUE;
    
    src/game/mario_actions_airborne.c lines 1156–1158 at 9921382 · upstream ↗
    1247s32 act_soft_bonk(struct MarioState *m) {
    1248    if (check_wall_kick(m)) {
    1249        return TRUE;
    
    src/game/mario_actions_airborne.c lines 1247–1249 at 9921382 · upstream ↗
    1147s32 check_wall_kick(struct MarioState *m) {
    1148    if ((m->input & INPUT_A_PRESSED) && m->wallKickTimer != 0 && m->prevAction == ACT_AIR_HIT_WALL) {
    1149        m->faceAngle[1] += 0x8000;
    1150        return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
    
    src/game/mario_actions_airborne.c lines 1147–1151 at 9921382 · upstream ↗
    1407    if (m->wallKickTimer > 0) {
    1408        m->wallKickTimer--;
    
    src/game/mario.c lines 1407–1409 at 9921382 · upstream ↗
    1705        update_mario_inputs(gMarioState);
    ⋮
    1714        // The function can loop through many action shifts in one frame,
    ⋮
    1717        while (inLoop) {
    
    src/game/mario.c lines 1705–1717 at 9921382 · upstream ↗
    828        case ACT_WALL_KICK_AIR:
    829        case ACT_TOP_OF_POLE_JUMP:
    830            set_mario_y_vel_based_on_fspeed(m, 62.0f, 0.0f);
    831            if (m->forwardVel < 24.0f) {
    832                m->forwardVel = 24.0f;
    
    src/game/mario.c lines 828–834 at 9921382 · 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. ^In 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

  8. ^With 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

Sources

Code