Air control
How much the player can change a character's horizontal motion while it is airborne.
On this page
Air control is how far the player can steer a character in mid-air. Three games span the range, from a jump fixed at take-off to one steered against its own momentum. The lab runs each game’s rules frame by frame, checked against its cartridge; play it, or pick a preset.
- FixedCastlevania (1986). The jump goes the way the d-pad pointed at take-off, and the d-pad does nothing in the air.1,2Castlevania II: Simon's Quest (1987). The jump keeps the direction held at take-off, as in Castlevania.3Castlevania III: Dracula's Curse (1989), Trevor, Sypha, and Alucard. The direction is set at take-off and can't be changed in the air.4
- LatchedCastlevania III: Dracula's Curse (1989), Grant. He can steer in the air, and keeps drifting when the d-pad is let go.5
- DirectMega Man (1987). Hold a direction and he moves at full speed; let go and he stops.6Mega Man 2 (1988). The d-pad moves him at full speed in the air, and he turns and stops at once.7,8Mega Man 3 (1990). A held direction moves him at walking speed in the air.9Castlevania: Symphony of the Night (1997). A held direction moves him at full speed at once; let go and he drifts to a stop.10
- Stops on releaseSuper Metroid (1994). In a normal jump, a held direction accelerates Samus to 1.25 px/frame, and letting go stops her base speed.11
- MomentumSuper Mario World (1990). The d-pad pushes against the speed Mario carries, and with it released he keeps that speed.12,13Super Castlevania IV (1991). The d-pad steers him gradually in the air, and he drifts on when let go.14Sonic the Hedgehog 2 (1992). The d-pad speeds him up either way in the air, twice as fast as on the ground, and near the top of a jump air drag slows him.15,16Sonic 3 & Knuckles (1994). The old steering and drag, but a Sonic faster than his top speed keeps that speed in the air.17,18
- DampedCeleste (2018). Steering takes 0.65 of the ground's rates, and released, Madeline's speed falls toward 0.19
Prince of Persia fixes a jump as Castlevania does2: its control routine reads no input during a jump’s frames20. Quake III Arena steers with its ground rule at an acceleration of 121 in place of 1022, adding to the speed carried until its component along the wish direction reaches the full wish speed21. Super Mario World’s held direction likewise adds to the speed carried, up to Mario’s top speed12.
Castlevania II: Simon’s Quest keeps Castlevania’s fixed jump: the take-off sets 1 px/frame toward a held direction, and the jumping state reads only B, for the whip3,2. Castlevania III: Dracula’s Curse sets the same take-off speed for every character but Grant, although the atlas hasn’t traced every routine its jumping state calls for a Left or Right read4. A held direction sets Grant’s speed to 1 px/frame in the air, and he keeps moving when it’s let go5. Super Castlevania IV lets Simon steer: a held side adds 0.25 px/frame² up to 1.25 px/frame, and the speed coasts when let go14. Castlevania: Symphony of the Night sets Alucard’s speed to 1.5 px/frame toward a held direction at once, and every jumping frame first slows it by 1/16 px/frame toward 010.
In the air, a held direction moves Mega Man 3’s hero at his walking speed, 1.30 px/frame ($01.$4C)9, on every frame9. Sonic the Hedgehog 2 keeps Sonic the Hedgehog’s air steering and drag15,16,23,24. In Sonic 3 & Knuckles, a Sonic already faster than the top speed keeps his speed in the air, where Sonic and Sonic 2 pulled him down to it17.
#Quirks
- Super Mario World’s turn overshoots zero, and the game reads only the speed’s high byte, so reversing from a full run takes 29 frames25.
- Super Mario Bros. keeps a released jump’s speed26, but a jump keeps Mario’s take-off facing27, so steering back brakes at the plain rate until he moves the other way; from a run he crosses zero only 50 frames into the jump28. Compare the two in the lab’s Mario line.
- Castlevania’s press frame still walks Simon 1 px before the jump fixes his direction29.
- Sonic the Hedgehog keeps his speed in the air, except near the top of a jump, where drag takes ×31/32 a frame near the top of a jump24,24; a held jump from top speed lands at 6 → 3.41 px/frame30,30. A jump from a roll locks the d-pad31.
- Celeste doesn’t coast: with the d-pad released in the air, Madeline’s speed falls toward 0 at the air rate, ×0.65 of the ground’s19.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Castlevania | 1986 | Fixed | the jump goes the way the d-pad pointed at take-off, and the d-pad does nothing in the air |
| Castlevania II: Simon's Quest | 1987 | Fixed | the jump keeps the direction held at take-off, as in Castlevania |
| Castlevania III: Dracula's Curse | 1989 | Fixed | Trevor, Sypha, and Alucard · the direction is set at take-off and can't be changed in the air |
| Prince of Persia | 1989 | Fixed | the control routine reads no input during a jump's frames |
| Castlevania III: Dracula's Curse | 1989 | Latched | Grant · he can steer in the air, and keeps drifting when the d-pad is let go |
| Mega Man | 1987 | Direct | hold a direction and he moves at full speed; let go and he stops |
| Mega Man 2 | 1988 | Direct | the d-pad moves him at full speed in the air, and he turns and stops at once |
| Mega Man 3 | 1990 | Direct | a held direction moves him at walking speed in the air |
| Metroid II: Return of Samus | 1991 | Direct | 1 px/frame toward a held direction in a plain jump, none without |
| Mega Man 6 | 1993 | Direct | the d-pad sets the speed in the air on every frame |
| Castlevania: Symphony of the Night | 1997 | Direct | a held direction moves him at full speed at once; let go and he drifts to a stop |
| Super Metroid | 1994 | Stops on release | in a normal jump, a held direction accelerates Samus to 1.25 px/frame, and letting go stops her base speed |
| Super Mario Bros. | 1985 | Momentum | a held direction speeds him toward it, let go he keeps his speed, and he faces the way he jumped |
| Metroid | 1986 | Momentum | a running jump steers by acceleration and a somersault keeps its speed; a standing jump moves 1 px/frame only while held |
| Super Mario Bros. 3 | 1988 | Momentum | a held direction speeds Mario up in the air as on the ground, and let go he keeps his speed |
| Super Mario World | 1990 | Momentum | the d-pad pushes against the speed Mario carries, and with it released he keeps that speed |
| Sonic the Hedgehog | 1991 | Momentum | the d-pad speeds him up either way in the air, twice as fast as on the ground, and near the top of a jump air drag slows him |
| Super Castlevania IV | 1991 | Momentum | the d-pad steers him gradually in the air, and he drifts on when let go |
| Sonic the Hedgehog 2 | 1992 | Momentum | the d-pad speeds him up either way in the air, twice as fast as on the ground, and near the top of a jump air drag slows him |
| Sonic 3 & Knuckles | 1994 | Momentum | the old steering and drag, but a Sonic faster than his top speed keeps that speed in the air |
| Quake | 1996 | Momentum | the move keys push against the speed carried, but only up to 30 along the wish direction, with no friction in the air |
| Quake II | 1997 | Momentum | the move keys push against the speed carried at a tenth of the ground acceleration, up to the full wish speed along the wish direction |
| Quake III Arena | 1999 | Momentum | the move keys push against the speed carried at a tenth of the ground acceleration, up to the full wish speed along the wish direction |
| Celeste | 2018 | Damped | steering takes 0.65 of the ground's rates, and released, Madeline's speed falls toward 0 |
Every claim about this mechanic, by game (51)
References
- ^In Simon's standing state, the frame A goes down starts a jump, unless a block is over his head (ceiling-takeoff); the take-off code points his arc at a fixed table and copies the d-pad's Left and Right bits into his direction.Code“Castlevania (USA) (Rev 1)”revised
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $9366-$9381, the dispatch on Simon's state; state 0 (standing) runs $9380, state 1 (jumping) $9482; bank 6 $9401-$943B: A pressed this frame, a ceiling check, the table pointer from $9B8D, state 1, then direction = facing | (held Right/Left). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcMeasured in the game, a jump keeps the direction held at take-off, 1 px per frame that way or none, whatever the d-pad does in the air.Verified“Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $9401-$943B; take-off copies the held Right/Left bits into Simon's direction; bank 6 $9479-$9481: horizontal speed $3D/$3E = 0/1, 1 px per frame; bank 6 $948E-$9496, where the jumping state sets that speed and moves Simon each frame. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Castlevania (USA) (Rev 1) (SHA-1
4e3ef47de86a…). 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-20.
Checked by a second AI model, 2026-10-21.
- ^ abIn Simon's Quest the take-off sets Simon's horizontal speed to 1 px/frame toward a held Left or Right, or 0, and the jumping state reads only B, for the whip, so the jump keeps its direction as in Castlevania.Code“Castlevania II - Simon's Quest (USA)” · “Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 3 $8905-$8928: held Right ($F7 bit 0) sets X speed $6D.$6C = 1.0, Left −1.0 and facing left, neither 0; bank 3 $89CD-$8A0D, the jumping state: a new B press ($F5 AND $40) goes to the whip; the rest is the vertical speed. We don't reproduce the bytes.
In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's take-off copying the held Left and Right into Simon's direction (castlevania/jump-start). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abIn Dracula's Curse the take-off shared by every character but Grant (the state tables the disassembly labels Trevor's, Sypha's, and Alucard's all point at it; Grant's has its own) sets the horizontal speed to 1 px/frame toward a held Left or Right, or 0, as in Castlevania.Codevinheim3/castlevania3-disasm · “Castlevania (USA) (Rev 1)”
How we know
3740playerState06_jumpStart_exceptGrant: ⋮ 3743B28_1622: lda wJoy1ButtonsPressed ; a5 28 3744B28_1624: sta $10 ; 85 10 ⋮ 3753B28_1637: lda $10 ; a5 10 3754B28_1639: lsr a ; 4a 3755B28_163a: bcs B28_1644 ; b0 08 ⋮ 3757B28_163c: lsr a ; 4a 3758B28_163d: bcs B28_164f ; b0 10 ⋮ 3761B28_163f: lda #$00 ; a9 00 3762B28_1641: tay ; a8 3763B28_1642: beq B28_1658 ; f0 14 ⋮ 3768B28_1649: lda #$01 ; a9 01 ⋮
code/playerStateProcessing_b1c.s lines 3740–3781 at 3272648 · upstream ↗ 345@setButtonVars: 346 lda wTempJoy1ButtonsPressedPass1, x 347 tay ⋮ 355 sty wJoy1ButtonsPressed, x
code/bank1f.s lines 344–356 at 3272648 · upstream ↗ 1826B28_0a91: ldy wCurrPlayer.w ; ac 4e 05 ⋮ 1836B28_0a9c: jsr processAlucardState ; 20 a8 a5 ⋮ 1840B28_0aa2: jsr processTrevorState ; 20 7b 93 ⋮ 1849B28_0ab0: jsr processSyphaState ; 20 fc 9b ⋮ 1853B28_0ab6: jsr processGrantState ; 20 3b 9c
code/playerStateProcessing_b1c.s lines 1826–1854 at 3272648 · upstream ↗ 3242processTrevorState: ⋮ 3249 .dw playerState06_jumpStart_exceptGrant
code/playerStateProcessing_b1c.s lines 3242–3249 at 3272648 · upstream ↗ 4751processSyphaState: ⋮ 4758 .dw playerState06_jumpStart_exceptGrant
code/playerStateProcessing_b1c.s lines 4751–4758 at 3272648 · upstream ↗ 918processAlucardState: ⋮ 926 .dw playerState06_jumpStart_exceptGrant
code/playerStateProcessing_b1d.s lines 918–926 at 3272648 · upstream ↗ 4784processGrantState: ⋮ 4791 .dw playerState06_jumpStart_grant
code/playerStateProcessing_b1c.s lines 4784–4791 at 3272648 · upstream ↗ In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's take-off copying the held Left and Right into Simon's direction (castlevania/jump-start). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abIn the air, a held Left or Right sets Grant's horizontal speed to 1 px/frame that way and turns him; with neither held the code leaves the speed as it was, so he keeps moving, until a wall stops him.Codevinheim3/castlevania3-disasm
How we know
5156playerState06_jumpStart_grant:code/playerStateProcessing_b1c.s lines 5156–5172 at 3272648 · upstream ↗ 5261playerState08_jumping_0c_grant: ⋮ 5292; left held ⋮ 5309; right held ⋮ 5326; nothing above pressed/held
code/playerStateProcessing_b1c.s lines 5261–5329 at 3272648 · upstream ↗ 5344; nothing above pressed/heldcode/playerStateProcessing_b1c.s lines 5344–5380 at 3272648 · upstream ↗ sta wEntityHorizSpeed.w
code/playerStateProcessing_b1d.s#L1-L4 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Off ice, Mega Man never accelerates. Each frame his animation picks a speed from
special_object_xcoord_speed_table, 0 standing, 0.125 px/frame on the first step, 1.375 running, 0.5 sliding to a stop, 0 landing, and 0.5625 when hit; any other animation, such as the jump, moves at 1.3125 with a direction held and 0 without.Codelsmmega/mm1revisedHow we know
1_ice_tsa_move: 2 LDY #$00 3 LDA aobject_pointer 4 LDX #$08 ⋮ 6@loop: 7 CMP @special_object_id_table, X 8 BEQ @yes 9 DEX 10 BPL @loop 11 LDA z:zjoy1_pressed 12 AND #left_button | right_button 13 BEQ @regular ⋮
engine/ice_tsa.asm lines 1–22 at b606a84 · upstream ↗ 146@special_object_id_table: 147 .BYTE $00 148 .BYTE $03 149 .BYTE $06 150 .BYTE $0C 151 .BYTE $0F 152 .BYTE $12 153 .BYTE $13 154 .BYTE $14 155 .BYTE $6E ⋮ 157@special_object_id_index_xcoord_speed_table: 158 .BYTE $00 ⋮
engine/ice_tsa.asm lines 146–166 at b606a84 · upstream ↗ 1special_object_xcoord_speed_table: 2;fraction, integer 3 .BYTE $00 | $00 4 .BYTE $00 | $20 5 .BYTE $01 | $20 6 .BYTE $00 | $80 7 .BYTE $01 | $00 8 .BYTE $04 | $00 9 .BYTE $05 | $10 10 .BYTE $01 | $50 11 .BYTE $01 | $60 12 .BYTE $00 | $90
data/special_xcoord_speed_table.asm lines 1–12 at b606a84 · upstream ↗ 22_write_special_object_xcoord_speed_continue: 23 LDA special_object_xcoord_speed_table, Y 24 PHA 25 AND #%11110000 26 STA aobject_xcoord_speed_fraction, X 27 PLA 28 AND #%00001111 29 STA aobject_xcoord_speed, X
home/write_special_object_xcoord_speed.asm lines 22–29 at b606a84 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-26.
Revised after a check by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-26.
- ^Each airborne frame,
_run_megaman_jumpingzeroes Mega Man's horizontal speed, then sets it to the jumping state's 1.3125 px/frame ($01.$50) toward a held Left or Right.Codelsmmega/mm2How we know
160_run_megaman_jumping: 161 JSR _check_shoot_on_ladder 162 LDA #$00 163 STA aobject_xcoord_speed_fraction 164 STA aobject_xcoord_speed 165 LDA z:zjoy1_pressed 166 AND #left_button | right_button 167 BNE @horizontal_jumping
engine/run_megaman.asm lines 160–167 at 94f0bf3 · upstream ↗ 197@horizontal_jumping: 198 JSR _turn_megaman 199 JSR _megaman_status_parameter
engine/run_megaman.asm lines 197–199 at 94f0bf3 · upstream ↗ 222megaman_status_xcoord_speed_table: ⋮ 228 .BYTE $01 229 .BYTE $01 ⋮ 235megaman_status_xcoord_speed_fraction_table: ⋮ 241 .BYTE $60 242 .BYTE $50
engine/turn_megaman.asm lines 222–246 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^Measured in the game, Mega Man moves 1.3125 px/frame in the air, turns around on the frame the other direction is pressed, and stops on the frame the d-pad is let go.Verifiedlsmmega/mm2revised
How we know
162 LDA #$00 163 STA aobject_xcoord_speed_fraction 164 STA aobject_xcoord_speed 165 LDA z:zjoy1_pressed 166 AND #left_button | right_button 167 BNE @horizontal_jumping ⋮ 192 LDA #$00 ⋮ 197@horizontal_jumping: 198 JSR _turn_megaman 199 JSR _megaman_status_parameter
engine/run_megaman.asm lines 160–202 at 94f0bf3 · upstream ↗ 72_megaman_status_parameter: 73 LDX z:zmegaman_status 74 LDA megaman_status_xcoord_speed_table, X 75 STA aobject_xcoord_speed 76 LDA megaman_status_xcoord_speed_fraction_table, X 77 STA aobject_xcoord_speed_fraction
engine/turn_megaman.asm lines 72–77 at 94f0bf3 · upstream ↗ 222megaman_status_xcoord_speed_table: ⋮ 228 .BYTE $01 229 .BYTE $01 ⋮ 235megaman_status_xcoord_speed_fraction_table: ⋮ 241 .BYTE $60 242 .BYTE $50
engine/turn_megaman.asm lines 222–246 at 94f0bf3 · 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-25.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-25.
- ^ abcMega Man 3 drops Mega Man 2's slow step speed but keeps a pause. Before each frame's state runs, the prelude sets the speed to
$01.$4C(1.30 px/frame) unless he is sliding. From standing, a held direction moves him by it at once and starts the turning animation ($0D); while that animation is on its first frame the ground state doesn't move him, and once it advances he walks at the same 1.30. In the air a held direction moves him at 1.30 on every frame.Codeplasticsmoke/megaman3-disassembly-ca65 · lsmmega/mm2revisedHow we know
636prelude_check_slide_speed: lda ent_xvel ; if X speed whole == $02 (slide speed): 637 cmp #$02 ; slide speed? 638 bne prelude_reset_walk_speed ; no → reset to walk speed 639 lda player_state ; load current player state 640 cmp #PSTATE_SLIDE ; check if sliding 641 beq prelude_setup_per_frame ; sliding, keep slide speed 642prelude_reset_walk_speed: lda #$4C ; reset walk speed to $01.4C 643 sta ent_xvel_sub ; store walk sub-pixel speed 644 lda #$01 ; walk speed whole = $01 645 sta ent_xvel ; store walk whole speed
src/fixed/game_loop.asm lines 636–645 at 58ca1c3 · upstream ↗ 115player_ground_turning_anim: lda #$0D ; OAM $0D = turning animation 116 jsr reset_sprite_anim ; set turning animation 117 lda shoot_anim_timer ; check if shooting 118 beq player_ground_move_facing ; not shooting, move facing 119 jsr shoot_oam_advance_variant ; update shoot animation variant 120player_ground_move_facing: lda player_facing ; move in facing direction 121 jmp player_ground_move_horizontal ; move in facing direction ⋮ 125player_ground_walk_handler: lda joy1_held ; D-pad L/R held? 126 and #$03 ; mask L/R bits 127 beq player_ground_idle ; no → idle 128 sta player_facing ; update facing direction
src/fixed/player_ground.asm lines 115–128 at 58ca1c3 · upstream ↗ 94 cmp #$0D ; $0D/$0E/$0F = turning/special anims 95 beq player_ground_special_anim ; OAM $0D → check if anim complete ⋮ 100player_ground_special_anim: lda ent_anim_state ; check animation state 101 bne player_ground_walk_handler ; → normal walk handler 102 beq player_ground_slide_weapon ; anim done → slide/crouch check
src/fixed/player_ground.asm lines 94–102 at 58ca1c3 · upstream ↗ 210 lda ent_anim_state,x ; ent_anim_state = current frame index 211 and #$7F ; (bit 7 preserved) 212 inc ent_anim_state,x ; advance to next frame ⋮ 216 lda #$00 ; reached end: loop back to frame 0 217 sta ent_anim_state,x ; reset to frame 0
src/fixed/sprites.asm lines 210–217 at 58ca1c3 · upstream ↗ 360player_airborne_walk_shoot: lda joy1_held ; D-pad L/R held? 361 and #$03 ; mask L/R bits 362 beq player_airborne_shoot_check ; no → skip walk 363 sta player_facing ; update facing direction 364 jsr player_ground_move_horizontal ; move L/R with collision
src/fixed/player_ground.asm lines 360–364 at 58ca1c3 · upstream ↗ 259move_sprite_right: lda ent_x_sub,x ; load X subpixel position 260 clc ; X subpixel += X subpixel speed 261 adc ent_xvel_sub,x ; add X subpixel velocity 262 sta ent_x_sub,x ; store new X subpixel 263 lda ent_x_px,x ; load X pixel position 264 adc ent_xvel,x ; add X pixel velocity + carry 265 sta ent_x_px,x ; store new X pixel
src/fixed/movement.asm lines 259–265 at 58ca1c3 · upstream ↗ 222megaman_status_xcoord_speed_table: 223 .BYTE $00 224 .BYTE $00 225 .BYTE $00 226 .BYTE $00 227 .BYTE $00 ⋮ 230 .BYTE $00 231 .BYTE $00 232 .BYTE $00 233 .BYTE $00 ⋮ 235megaman_status_xcoord_speed_fraction_table: 236 .BYTE $00 ⋮
engine/turn_megaman.asm lines 222–243 at 94f0bf3 · 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.
Checked by a second AI model, 2026-10-26.
- ^ abIn Symphony of the Night's jump a held direction sets Alucard's horizontal speed to 1.5 px/frame that way at once, turning him if needed, and every jumping frame first slows it by 1/16 px/frame toward 0, so a released d-pad fades the speed out; Castlevania's take-off fixes Simon's direction for the whole jump.CodeXeeynamo/sotn-decomp · “Castlevania (USA) (Rev 1)”
How we know
580 DecelerateX(FIX(1.0 / 16)); ⋮ 597 walkResult = CheckMoveDirection(); 598 if (walkResult != 0) { ⋮ 603 SetSpeedX(FIX(1.5));
src/dra/71830.c lines 579–603 at 2be55ee · upstream ↗ 3void DecelerateX(s32 amount) {src/decelerate.h lines 3–15 at 2be55ee · upstream ↗ 101s32 CheckMoveDirection(void) { ⋮ 106 if (g_Player.padPressed & PAD_RIGHT) { 107 PLAYER.facingLeft = 0; ⋮ 114 if (g_Player.padPressed & PAD_RIGHT) {
src/dra/6DF70.c lines 101–115 at 2be55ee · upstream ↗ In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's take-off copying the held Left and Right into Simon's direction (castlevania/jump-start). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^In a normal jump with no acceleration mode set, holding neither left nor right sets Samus's base horizontal speed to 0 that frame; held, the speed table's jumping row accelerates her at 0.75 px/frame² to 1.25 px/frame.CodeInsaneFirebat/sm_disassembly
How we know
LDA.W SamusXAccelerationMode BNE .XMovement LDA.B DP_Controller1Input BIT.W #$0100 BNE .XMovement BIT.W #$0200 BNE .XMovement STZ.B DP_Temp12 STZ.B DP_Temp14 STZ.W SamusXBaseSpeed STZ.W SamusXBaseSubSpeed
src/bank_90.asm#L2807-L2819 · upstream ↗ 5195; ________________________________________________________________ X acceleration ⋮ 5201 dd wordSwap($00C0*!SPF*$100),wordSwap($0140*!SPF*$100), wordSwap($0080*!SPF*$100) ; 2: Normal jumping
src/bank_90.asm lines 5195–5201 at 7af131e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abHolding a direction in the air accelerates Mario by
MarioAccel_'s 1.5/16 px/frame each frame up to his top speed, or by 5/16 (2.5/16 without Y) while he still moves the other way.CodeSMWDisXHow we know
9699 dw $FE80,$FE80,$0180,$0180 ;!bank_00.asm line 9699 at 30643c7 · upstream ↗ 9717 dw $FD80,$FB00,$0280,$0500 ;!bank_00.asm line 9717 at 30643c7 · upstream ↗ 10061 LDA.B PlayerXSpeed+1 10062 BEQ CODE_00D713 10063 EOR.W MarioAccel_+1,X 10064 BPL CODE_00D713 ⋮ 10072 + TXA 10073 CLC 10074 ADC.B #$90 10075 TAX
bank_00.asm lines 10061–10075 at 30643c7 · upstream ↗ 10107CODE_00D742: 10108 LDA.B PlayerXSpeed+1 10109 SEC 10110 SBC.W DATA_00D535,Y ⋮ 10115 LDA.W MarioAccel_,X
bank_00.asm lines 10107–10123 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^In the air with neither Left nor Right held, Mario's horizontal routine returns before friction, so he keeps his speed.CodeSMWDisX
How we know
9998 LDA.B byetudlrHold 9999 AND.B #$03 10000 BNE CODE_00D6B1
bank_00.asm lines 9998–10000 at 30643c7 · upstream ↗ 10021 + JMP CODE_00D764bank_00.asm line 10021 at 30643c7 · upstream ↗ 10125CODE_00D764: 10126 JSR CODE_00D968 10127 LDA.B PlayerInAir 10128 BNE Return00D7A4
bank_00.asm lines 10125–10128 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abIn Super Castlevania IV's jump a held Left or Right adds 0.25 px/frame² toward that side, up to 1.25 px/frame, and with neither held the speed is left as it is, where Castlevania's take-off fixes the direction for the whole jump.Code“Super Castlevania IV (USA)” · “Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Super Castlevania IV (USA)”): $00:A3FA-$A409, state 4 calling $A8DE each frame; $00:A8DE-$A94C: Right held adds $0000.$4000 to X speed $055A.$0558, capped at 1.25; Left adds $FFFF.$C000, capped at −1.25; neither, return. We don't reproduce the bytes.
In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's take-off copying the held Left and Right into Simon's direction (castlevania/jump-start). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abIn the air
Sonic_ChgJumpDiradds twice the acceleration,$18, either way and still caps at the top speed even when Sonic was already faster, as Sonic 1 does.Codesonicretro/s2disasm · sonicretro/s1disasmrevisedHow we know
37205 move.w (Sonic_acceleration).w,d5 37206 asl.w #1,d5 ⋮ 37219 move.w d1,d0 ; limit speed in air going left, even if Sonic was already going faster (speed limit/cap) ⋮ 37228 move.w d6,d0 ; limit speed in air going right, even if Sonic was already going faster (speed limit/cap)
s2.asm lines 37204–37228 at 4ef457c · upstream ↗ 956 move.w d1,d0 ; cap leftward X-speed to maximum ⋮ 966 move.w d6,d0 ; cap rightward X-speed to maximum
_incObj/01 Sonic.asm lines 940–966 at 15dfa3a · 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.
- ^ abSonic 2 keeps Sonic 1's air drag;
Sonic_JumpPeakDecelerateis instruction for instruction Sonic 1'sSonic_AirDrag, taking X speed shifted right 5 bits while Y speed is from −$400to −1.Codesonicretro/s2disasm · sonicretro/s1disasmHow we know
37242 cmpi.w #-$400,y_vel(a0) ; is Sonic moving faster than -$400 upwards? ⋮ 37246 asr.w #5,d1 ; d1 = x_velocity / 32 ⋮ 37251 sub.w d1,d0 ; reduce x velocity by d1 ⋮ 37260 sub.w d1,d0 ; reduce x velocity by d1
s2.asm lines 37241–37264 at 4ef457c · upstream ↗ 987 cmpi.w #-$400,obVelY(a0) ; is Sonic moving faster than -$400 upwards? ⋮ 992 asr.w #5,d1 ; divide that copy by $20
_incObj/01 Sonic.asm lines 986–1013 at 15dfa3a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abIn the air
Sonic_ChgJumpDirstill adds$18a frame, but a Sonic already faster than the top speed keeps his speed; Sonic 1 and Sonic 2 pulled him down to it.Codesonicretro/skdisasm · sonicretro/s2disasm · sonicretro/s1disasmrevisedHow we know
23134 sub.w d5,d0 ; add acceleration to the left ⋮ 23139 add.w d5,d0 ; remove this frame's acceleration change 23140 cmp.w d1,d0 ; compare speed with top speed 23141 ble.s loc_11682 ; if speed was already greater than the maximum, branch 23142 move.w d1,d0
sonic3k.asm lines 23129–23155 at 73de97c · upstream ↗ 20850 add.w d5,d0 ; remove this frame's acceleration change 20851 cmp.w d1,d0 ; compare speed with top speed 20852 ble.s loc_126F2 ; if speed was already greater than the maximum, branch
s3.asm lines 20845–20866 at 73de97c · upstream ↗ 37219 move.w d1,d0 ; limit speed in air going left, even if Sonic was already going faster (speed limit/cap)s2.asm lines 37214–37219 at 4ef457c · upstream ↗ 951 sub.w d5,d0 ; increase leftward movement speed ⋮ 954 cmp.w d1,d0 ; is new speed exceeding maximum? 955 bgt.s .notleft ; if not, branch 956 move.w d1,d0 ; cap leftward X-speed to maximum
_incObj/01 Sonic.asm lines 951–956 at 15dfa3a · 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.
- ^Sonic 3 & Knuckles keeps Sonic 1's air drag, X speed less X speed shifted right 5 bits while Y speed is from −
$400to −1.Codesonicretro/skdisasm · sonicretro/s1disasmrevisedHow we know
23170 cmpi.w #-$400,y_vel(a0) ; is Sonic moving faster than -$400 upwards? ⋮ 23174 asr.w #5,d1 ; d1 = x_velocity / 32 ⋮ 23178 sub.w d1,d0 ; reduce x velocity by d1 ⋮ 23188 sub.w d1,d0 ; reduce x velocity by d1
sonic3k.asm lines 23169–23193 at 73de97c · upstream ↗ 987 cmpi.w #-$400,obVelY(a0) ; is Sonic moving faster than -$400 upwards? ⋮ 992 asr.w #5,d1 ; divide that copy by $20 ⋮ 995 sub.w d1,d0 ; slightly reduce speed (air drag)
_incObj/01 Sonic.asm lines 986–995 at 15dfa3a · 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.
- ^ abIn the air both running rates are multiplied by
AirMult, 0.65, so steering, stopping, and turning take 650 px/s², and slowing from above the cap 260 px/s².CodeNoelFB/CelesteHow we know
33 private const float AirMult = .65f;Source/Player/Player.cs line 33 at 1b0ce45 · upstream ↗ 2884 float mult = onGround ? 1 : AirMult;Source/Player/Player.cs line 2884 at 1b0ce45 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^
GENCTRL, which turns the player's input into moves, picks its branch by the frame the kid shows (standing, starting a run, running, starting a jump up, hanging, turning, or crouching). The frames of the standing and running jumps, 16 to 44, match none of them, and it returns without reading the joystick, so a jump can't be steered once it starts.Codejmechner/Prince-of-Persia-Apple-IIHow we know
689:cont ldx CharPosn ;previous frame # ⋮ 691 cpx #15 692 beq :standing ⋮ 694 cpx #48 695 beq :turning ⋮ 697 cpx #50 698 bcc :0 699 cpx #53 700 bcc :standing ;turn7-8-9/crouch ⋮ 702 cpx #4 703 bcc :starting ;run4-5-6 ⋮ 705 cpx #67 ⋮
01 POP Source/Source/CTRL.S lines 689–718 at 2524355 · upstream ↗ 720:1 cpx #109 ;crouching? 721 beq :crouching ⋮ 723]rts rts
01 POP Source/Source/CTRL.S lines 720–723 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abIn the air, Quake III's
PM_AirMoveruns friction (no ground friction, which needs the walking flag), builds a flat wish velocity, and calls the samePM_Accelerateas the ground withpm_airaccelerate1: the push is 1 × step time × wish speed (2.56 units/s per 8 ms step at 320), and it stops only when the velocity's component along the wish direction reaches the full wish speed. Quake's air rule is the reverse: a push ten times as strong (10 × 320 × frame time), cut off when that component reaches 30 (quake/air-accelerate). An#elsebranch left out by#if 1would push the velocity toward the wish velocity instead, commented "proper way (avoids strafe jump maxspeed bug), but feels bad". The figures leave out the roundingtrap_SnapVectorapplies to the velocity after each step, engine code the atlas hasn't read.Codeid-Software/Quake-III-Arena · id-Software/QuakerevisedHow we know
40float pm_airaccelerate = 1.0f;code/game/bg_pmove.c line 40 at dbe4ddb · upstream ↗ 610 PM_Friction(); ⋮ 628 wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; ⋮ 630 wishvel[2] = 0; ⋮ 633 wishspeed = VectorNormalize(wishdir); 634 wishspeed *= scale; ⋮ 636 // not on ground, so little effect on velocity 637 PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
code/game/bg_pmove.c lines 610–637 at dbe4ddb · upstream ↗ 197 if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {code/game/bg_pmove.c line 197 at dbe4ddb · upstream ↗ 2015 trap_SnapVector( pm->ps->velocity );code/game/bg_pmove.c line 2015 at dbe4ddb · upstream ↗ 240static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { 241#if 1 ⋮ 246 currentspeed = DotProduct (pm->ps->velocity, wishdir); 247 addspeed = wishspeed - currentspeed; 248 if (addspeed <= 0) { 249 return; ⋮ 251 accelspeed = accel*pml.frametime*wishspeed; 252 if (accelspeed > addspeed) { 253 accelspeed = addspeed; ⋮ 259#else 260 // proper way (avoids strafe jump maxspeed bug), but feels bad ⋮ 267 VectorSubtract( wishVelocity, pm->ps->velocity, pushDir ); ⋮
code/game/bg_pmove.c lines 240–275 at dbe4ddb · upstream ↗ 212 wishspd = VectorNormalize (wishveloc); 213 if (wishspd > 30) 214 wishspd = 30; 215 currentspeed = DotProduct (velocity, wishveloc); 216 addspeed = wishspd - currentspeed; ⋮ 220 accelspeed = sv_accelerate.value*wishspeed * host_frametime; 221 if (accelspeed > addspeed) 222 accelspeed = addspeed;
WinQuake/sv_user.c lines 212–224 at bf4ac42 · 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.
- ^Quake III's
PM_WalkMoveruns friction and thenPM_Acceleratewithpm_accelerate10, which is Quake's rule (Quake III'sPM_Acceleratecomment says "q2 style"): if the speed along the wish direction is under the wish speed, it adds 10 × step time × wish speed along that direction, no more than the shortfall. The full wish speed is the player'sspeed, set before each move fromg_speed(320, × 1.3 with Haste). Computed, not measured: since 10 outpaces the friction of 6, a run settles at exactly 320, as Quake's does at 10 against 4; at 8 ms steps it reaches 320 from rest in 19 steps (0.15 s) and stops from 320 in 45 (0.36 s). These figures leave out the roundingtrap_SnapVectorapplies to the velocity after each step, engine code the atlas hasn't read.Codeid-Software/Quake-III-Arena · id-Software/QuakerevisedHow we know
39float pm_accelerate = 10.0f;code/game/bg_pmove.c line 39 at dbe4ddb · upstream ↗ 240static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { 241#if 1 242 // q2 style ⋮ 246 currentspeed = DotProduct (pm->ps->velocity, wishdir); 247 addspeed = wishspeed - currentspeed; 248 if (addspeed <= 0) { 249 return; ⋮ 251 accelspeed = accel*pml.frametime*wishspeed; 252 if (accelspeed > addspeed) { 253 accelspeed = addspeed; ⋮ 257 pm->ps->velocity[i] += accelspeed*wishdir[i];
code/game/bg_pmove.c lines 240–258 at dbe4ddb · upstream ↗ 720 PM_Friction ();code/game/bg_pmove.c line 720 at dbe4ddb · upstream ↗ 772 if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { 773 accelerate = pm_airaccelerate; 774 } else { 775 accelerate = pm_accelerate; ⋮ 778 PM_Accelerate (wishdir, wishspeed, accelerate);
code/game/bg_pmove.c lines 772–778 at dbe4ddb · upstream ↗ 142 { &g_speed, "g_speed", "320", 0, 0, qtrue },code/game/g_main.c line 142 at dbe4ddb · upstream ↗ 2015 trap_SnapVector( pm->ps->velocity );code/game/bg_pmove.c line 2015 at dbe4ddb · upstream ↗ 843 client->ps.speed = g_speed.value; ⋮ 851 if ( client->ps.powerups[PW_HASTE] ) { 852 client->ps.speed *= 1.3;
code/game/g_active.c lines 843–853 at dbe4ddb · upstream ↗ 195 currentspeed = DotProduct (velocity, wishdir); 196 addspeed = wishspeed - currentspeed; ⋮ 199 accelspeed = sv_accelerate.value*host_frametime*wishspeed; 200 if (accelspeed > addspeed) 201 accelspeed = addspeed;
WinQuake/sv_user.c lines 195–201 at bf4ac42 · upstream ↗ 167cvar_t sv_maxspeed = {"sv_maxspeed", "320", false, true}; 168cvar_t sv_accelerate = {"sv_accelerate", "10"};
WinQuake/sv_user.c lines 167–168 at bf4ac42 · 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 running game, in the air the d-pad adds
$18, twice the ground acceleration, to Sonic's X speed each frame either way, with no separate deceleration, up to the top speed.Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Air State”How we know
939Sonic_JumpDirection: 940 move.w (v_sonspeedmax).w,d6 ; get Sonic's current top speed 941 move.w (v_sonspeedacc).w,d5 ; get Sonic's current acceleration... 942 asl.w #1,d5 ; ...doubled ⋮ 951 sub.w d5,d0 ; increase leftward movement speed ⋮ 963 add.w d5,d0 ; increase rightward movement speed ⋮ 970 move.w d0,obVelX(a0) ; update Sonic's horizontal speed
_incObj/01 Sonic.asm lines 939–970 at 15dfa3a · upstream ↗ there is no distinction for deceleration in the air, either
Air Acceleration · archived copy ↗ Measured by a script. 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-25.
Checked by a second AI model, 2026-10-25.
- ^ abcIn the running game, while Sonic rises no faster than 4 px/frame (Y speed −
$400to −1 before that frame's gravity), each frame subtracts his X speed shifted right 5 bits, about 1/32: an X speed of$400written in by the probe was dragged at Y speeds −$400and −1, and not at −$401or 0.Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Air State”How we know
986Sonic_AirDrag: 987 cmpi.w #-$400,obVelY(a0) ; is Sonic moving faster than -$400 upwards? 988 blo.s .return ; if yes, branch (skip air drag) ⋮ 992 asr.w #5,d1 ; divide that copy by $20 993 beq.s .return ; if result is zero, branch 994 bmi.s .jumpingleftward ; if speed is negative, branch 995 sub.w d1,d0 ; slightly reduce speed (air drag) ⋮ 1007 sub.w d1,d0 ; slightly reduce speed (air drag)
_incObj/01 Sonic.asm lines 986–1013 at 15dfa3a · upstream ↗ Y Speed must be negative and Y Speed must be more than -4
Air Drag · archived copy ↗ Measured by a script. 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-25.
Checked by a second AI model, 2026-10-25.
- ^In the air Mario's horizontal speed follows the ground's code except that a released d-pad keeps the speed and the cap index never reaches 2 unless he left at full P-meter; a frame-by-frame model of these rules reproduces every probed frame.VerifiedSMWDisXrevised
How we know
10061 LDA.B PlayerXSpeed+1 10062 BEQ CODE_00D713 10063 EOR.W MarioAccel_+1,X 10064 BPL CODE_00D713 ⋮ 10073 CLC 10074 ADC.B #$90 10075 TAX
bank_00.asm lines 10061–10075 at 30643c7 · upstream ↗ 10088 BMI CODE_00D737 10089 LDA.B PlayerInAir 10090 BNE CODE_00D732 ⋮ 10095CODE_00D732: 10096 CMP.B #$0C 10097 BNE CODE_00D737 10098CODE_00D736: 10099 INY
bank_00.asm lines 10083–10101 at 30643c7 · upstream ↗ 10108 LDA.B PlayerXSpeed+1 10109 SEC 10110 SBC.W DATA_00D535,Y 10111 BEQ CODE_00D76B 10112 EOR.W DATA_00D535,Y 10113 BPL CODE_00D76B ⋮ 10122 ADC.B PlayerXSpeed
bank_00.asm lines 10107–10123 at 30643c7 · upstream ↗ 10126 JSR CODE_00D968 10127 LDA.B PlayerInAir 10128 BNE Return00D7A4
bank_00.asm lines 10125–10128 at 30643c7 · upstream ↗ 9983 LDA.B #$0B 9984 LDY.W PlayerPMeter 9985 CPY.B #con($70,$70,$70,$40,$68) 9986 BCC CODE_00D67D ⋮ 9992CODE_00D67D: 9993 STA.B PlayerInAir
bank_00.asm lines 9983–9993 at 30643c7 · 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-25.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-25.
- ^
LRAirrunsImposeFrictiononly while Left or Right is held, so in the air a held direction accelerates Mario toward it up to the cap and a released d-pad keeps his speed.CodeXkeeper0/smb1How we know
4783LRAir: 4784 LDA Left_Right_Buttons ; check left/right controller bits (check for jumping/falling) 4785 BEQ JSMove ; if not pressing any, skip 4786 JSR ImposeFriction ; otherwise process horizontal movement 4787JSMove: 4788 JSR MovePlayerHorizontally ; do a sub to move player horizontally
src/prg.asm lines 4783–4788 at 1cc3c92 · upstream ↗ 4748FallingSub: 4749 LDA VerticalForceDown 4750 STA VerticalForce ; dump vertical movement force for falling into main one 4751 JMP LRAir ; movement force, then skip ahead to process left/right movement
src/prg.asm lines 4748–4751 at 1cc3c92 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^On the ground
OnGroundStateSubturns Mario toward a held Left or Right before friction runs; the jumping and falling routines change his facing only while he swims.CodeXkeeper0/smb1How we know
4735OnGroundStateSub: 4736 JSR GetPlayerAnimSpeed ; do a sub to set animation frame timing 4737 LDA Left_Right_Buttons 4738 BEQ GndMove ; if left/right controller bits not set, skip instruction 4739 STA PlayerFacingDir ; otherwise set new facing direction 4740GndMove:
src/prg.asm lines 4735–4740 at 1cc3c92 · upstream ↗ 4771 LDA SwimmingFlag ; if swimming flag not set, 4772 BEQ LRAir ; branch ahead to last part ⋮ 4779LRWater: 4780 LDA Left_Right_Buttons ; check left/right controller bits (check for swimming) 4781 BEQ LRAir ; if not pressing any, skip 4782 STA PlayerFacingDir ; otherwise set facing direction accordingly 4783LRAir: 4784 LDA Left_Right_Buttons ; check left/right controller bits (check for jumping/falling)
src/prg.asm lines 4771–4784 at 1cc3c92 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Because a jump keeps Mario's take-off facing, steering back slows him at the plain rate until he moves the other way, then at double the rate (
$1A0from a run).VerifiedXkeeper0/smb1How we know
5042 LDA PlayerFacingDirsrc/prg.asm lines 5042–5047 at 1cc3c92 · upstream ↗ 4779LRWater: ⋮ 4783LRAir:
src/prg.asm lines 4771–4784 at 1cc3c92 · 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-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^The standing state moves Simon before it checks A, so the press frame walks at 1 px/frame; the take-off then fixes the jump's direction from the d-pad held on that frame, and the jumping state moves him 1 px/frame that way or not at all.Verified“Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $93D9-$93E3, the move before the jump check; bank 6 $9401-$943B: the take-off writes held Left/Right into $3C; bank 6 $9479-$9481, the jumping state's speed, 1 px/frame. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Castlevania (USA) (Rev 1) (SHA-1
4e3ef47de86a…). 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.
- ^ abIn the running game, on flat ground, a held jump from top speed with the d-pad released is dragged on 18 frames and lands at
$369(3.41 px/frame) to the right but −$35Eto the left.Verifiedsonicretro/s1disasmrevisedHow we know
_incObj/01 Sonic.asm#L986-L1013 · upstream ↗ 5gravity: equ $38 ; gravity constant used by many objects_incObj/sub ObjectFall & SpeedToPos.asm line 5 at 15dfa3a · upstream ↗ Measured by a script. 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-25.
Revised after a check by a second AI model, 2026-10-25.
- ^In the running game, on flat ground, after a jump from a roll the d-pad does nothing in the air, neither steering Sonic nor turning him, and air drag still runs.Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Rolling”
How we know
1248 btst #status_rolling_bit,obStatus(a0) ; is Sonic already in a ball state? 1249 bne.s .rolljump ; if so, branch
_incObj/01 Sonic.asm lines 1248–1249 at 15dfa3a · upstream ↗ 1263 bset #status_rolljumping_bit,obStatus(a0) ; set Roll-Jump flag_incObj/01 Sonic.asm lines 1262–1263 at 15dfa3a · upstream ↗ 944 btst #status_rolljumping_bit,obStatus(a0) ; is Roll-Jump flag set? 945 bne.s Sonic_RollJumpLock ; if yes, prevent midair direction change
_incObj/01 Sonic.asm lines 944–945 at 15dfa3a · upstream ↗ 974Sonic_RollJumpLock: ⋮ 986Sonic_AirDrag:
_incObj/01 Sonic.asm lines 974–986 at 15dfa3a · upstream ↗ In Sonic 1, 2, 3, and Knuckles, you can't control the Player's trajectory through the air with the buttons if you jump while rolling.
Rolling Jump · archived copy ↗ Measured by a script. 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-25.
Checked by a second AI model, 2026-10-25.
Sources
Code
- 1987. “Castlevania (USA) (Rev 1).” · licence, all uses
- Mechner, Jordan. 2024. “Prince of Persia Apple II source code (jmechner/Prince-of-Persia-Apple-II).” Commit 2524355. jmechner/Prince-of-Persia-Apple-II @ 2524355 · licence, all uses
- Software, id. 2012. “Quake III Arena: the GPL source release (id-Software/Quake-III-Arena, 1.32b).” Commit dbe4ddb. id-Software/Quake-III-Arena @ dbe4ddb · licence, all uses
- Software, id. 2012. “Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld).” Commit bf4ac42. id-Software/Quake @ bf4ac42 · licence, all uses
- IsoFrieze, kaizoman666, mikeyk, and loveemu. 2026. “SMWDisX: Super Mario World disassembly (IsoFrieze/SMWDisX).” Commit 30643c7. IsoFrieze/SMWDisX @ 30643c7 · licence, all uses
- 1988. “Castlevania II - Simon's Quest (USA).” · licence, all uses
- vinheim3. 2020. “castlevania3-disasm: a disassembly of Castlevania III: Dracula's Curse.” Commit 3272648. vinheim3/castlevania3-disasm @ 3272648 · licence, all uses
- 1991. “Super Castlevania IV (USA).” · licence, all uses
- Xeeynamo and sotn-decomp contributors. 2026. “sotn-decomp: a decompilation of Castlevania: Symphony of the Night.” Commit 2be55ee. Xeeynamo/sotn-decomp @ 2be55ee · licence, all uses
- plasticsmoke. 2026. “Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke).” Commit 58ca1c3. plasticsmoke/megaman3-disassembly-ca65 @ 58ca1c3 · licence, all uses
- lsmmega. 2026. “mm2: Mega Man 2 disassembly (lsmmega/mm2).” Commit 94f0bf3. lsmmega/mm2 @ 94f0bf3 · licence, all uses
- Sonic Retro contributors. 2026. “s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm).” Commit 4ef457c. sonicretro/s2disasm @ 4ef457c · licence, all uses
- Sonic Retro contributors. 2026. “s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm).” Commit 15dfa3a. sonicretro/s1disasm @ 15dfa3a · licence, all uses
- Sonic Retro contributors. 2026. “skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm).” Commit 73de97c. sonicretro/skdisasm @ 73de97c · licence, all uses
- doppelganger and Xkeeper. 2022. “smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1).” Commit 1cc3c92. Xkeeper0/smb1 @ 1cc3c92 · licence, all uses
- Thorson, Maddy and Noel Berry. 2021. “Celeste: released class files (NoelFB/Celeste).” Commit 1b0ce45. NoelFB/Celeste @ 1b0ce45 · licence, all uses
Secondary
- Sonic Retro contributors. n.d. “Sonic Physics Guide: Air State.” Sonic Retro. original · archived · licence, all uses
- Sonic Retro contributors. n.d. “Sonic Physics Guide: Rolling.” Sonic Retro. original · archived · licence, all uses