Claim set · data/claims/s3k.yaml

Sonic 3 & Knuckles (sonicretro/skdisasm)

Game: Sonic 3 & Knuckles.

Sonic and Tails take off at $680 subpixels per frame (6.5 px/frame) and Knuckles at $600 (6 px/frame); underwater the speeds are $380 and $300. s3k/jump-speed

About: Sonic 3 & Knuckles Jump

Value
{
 "sonic": 1664,
 "knuckles": 1536,
 "sonicWater": 896,
 "knucklesWater": 768
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23342-L23350move.w #$680,d2 … move.w #$800,d2 ; set higher jump speed if super … move.w #$380,d2 ; set lower jump speed if underskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L28578-L28581move.w #$680,d2 btst #Status_Underwater,status(a0) … move.w #$380,d2skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L32494-L32497move.w #$600,d2 btst #Status_Underwater,status(a0) beq.s loc_1775C move.w #$300,d2Checked by claude, 2026-10-21 — read Sonic_Jump, Tails_Jump, and Knux_Jump at the pinned commit

As in the earlier games the speed goes along the ground's normal (L23352-L23362).

Cited by: Jump, Sonic 3 & Knuckles

MoveSprite adds $38 subpixels/frame to a falling player's speed, Sonic 1's and Sonic 2's gravity, and underwater the air modes take $28 back. s3k/gravity

About: Sonic 3 & Knuckles Gravity

Value: 56 1/256 px/frame²

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L36077-L36078move.w y_vel(a0),d0 ; load y speed addi.w #$38,y_vel(a0) ; increase vertical speed (apply gravity)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22442-L22449jsr (MoveSprite_TestGravity).l … subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10)s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/sub ObjectFall & SpeedToPos.asm#L5gravity: equ $38s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L30217addi.w #$38,y_vel(a0) ; increase vertical speed (apply gravity)Checked by claude, 2026-10-21 — read MoveSprite, MoveSprite_TestGravity, and Sonic_MdJump at the pinned commit

Cited by: Gravity, Sonic 3 & Knuckles

With no jump button held, Sonic_JumpHeight cuts a rise faster than 4 px/frame to exactly -$400 (-$200 underwater); a press once the rise is no faster than that starts a shield move instead. s3k/release-cap

About: Sonic 3 & Knuckles Variable jump height

Value: -1024 1/256 px/frame

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23404-L23415move.w #-$400,d1 … move.w #-$200,d1 ; Underwater-specific … cmp.w y_vel(a0),d1 ; is y speed greater than 4? (2 if underwater) ble.w Sonic_ShieldMoves ; if not, branch … move.w d1,y_vel(a0) ; cap jump heightChecked by claude, 2026-10-21 — read Sonic_JumpHeight at the pinned commit

Cited by: Sonic 3 & Knuckles, Variable jump height

Sonic_Init sets the top speed to $600, the acceleration to $C, and the deceleration to $80 subpixels, the values of Sonic 1 and Sonic 2. s3k/ground-speeds

About: Sonic 3 & Knuckles Running

Value
{
 "top": 1536,
 "accel": 12,
 "decel": 128
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21950-L21952move.w #$600,Max_speed-Max_speed(a4) move.w #$C,Acceleration-Max_speed(a4) move.w #$80,Deceleration-Max_speed(a4)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22902-L22908add.w d5,d0 cmp.w d6,d0 blt.s loc_114AA sub.w d5,d0 cmp.w d6,d0 bge.s loc_114AA move.w d6,d0s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L5-L7son_maxspeed: equ $600 ; Sonic's max speed son_acceleration: equ $C ; Sonic's acceleration son_deceleration: equ $80 ; Sonic's decelerations2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36232-L36234move.w #$600,(Sonic_top_speed).w ; set Sonic's top speed move.w #$C,(Sonic_acceleration).w ; set Sonic's acceleration move.w #$80,(Sonic_deceleration).w ; set Sonic's decelerations2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36998-L37004sub.w d5,d0 ; remove this frame's acceleration changeChecked by claude, 2026-10-21 — read Sonic_Init and the ground move-right routine at the pinned commit

As in Sonic 2, holding forward keeps a speed already above the top (s2disasm/forward-cap-kept).

Cited by: Running, Sonic 3 & Knuckles

In the air Sonic_ChgJumpDir still adds $18 a frame, but a Sonic already faster than the top speed keeps his speed; Sonic 1 and Sonic 2 pulled him down to it. s3k/air-keep-speed

About: Sonic 3 & Knuckles Air control

Value: 24 1/256 px/frame²

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23129-L23155sub.w d5,d0 ; add acceleration to the left … add.w d5,d0 ; remove this frame's acceleration change cmp.w d1,d0 ; compare speed with top speed ble.s loc_11682 ; if speed was already greater than the maximum, branch move.w d1,d0skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L20845-L20866 — Sonic 3 alone has the same checkadd.w d5,d0 ; remove this frame's acceleration change cmp.w d1,d0 ; compare speed with top speed ble.s loc_126F2 ; if speed was already greater than the maximum, branchs2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37214-L37219move.w d1,d0 ; limit speed in air going left, even if Sonic was already going faster (speed limit/cap)s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L951-L956sub.w d5,d0 ; increase leftward movement speed … cmp.w d1,d0 ; is new speed exceeding maximum? bgt.s .notleft ; if not, branch move.w d1,d0 ; cap leftward X-speed to maximumChecked by claude, 2026-10-21 — read Sonic_ChgJumpDir in sonic3k.asm and s3.asm and compared it with Sonic 2's at their pinned commits

Cited by: Air control, Sonic 3 & Knuckles, Sonic the Hedgehog 2

Sonic 3 & Knuckles keeps Sonic 1's air drag, X speed less X speed shifted right 5 bits while Y speed is from −$400 to −1. s3k/air-drag-same

About: Sonic 3 & Knuckles Air control

Value
{
 "shift": 5,
 "vyFrom": -1024,
 "vyTo": -1
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23169-L23193cmpi.w #-$400,y_vel(a0) ; is Sonic moving faster than -$400 upwards? … asr.w #5,d1 ; d1 = x_velocity / 32 … sub.w d1,d0 ; reduce x velocity by d1s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L986-L995cmpi.w #-$400,obVelY(a0) ; is Sonic moving faster than -$400 upwards? … asr.w #5,d1 ; divide that copy by $20 … sub.w d1,d0 ; slightly reduce speed (air drag)Checked by claude, 2026-10-21 — read Sonic_JumpPeakDecelerate at the pinned commit and compared it with s2disasm/air-drag-same

Sonic 3 & Knuckles has no grace window after a ledge: Sonic_Jump is called only from the grounded modes. s3k/no-coyote-time

About: Sonic 3 & Knuckles Coyote time

Value: 0 frames

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22328-L22330Sonic_MdNormal: bsr.w SonicKnux_Spindash bsr.w Sonic_Jumpskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22402-L22405Sonic_MdRoll: tst.b spin_dash_flag(a0) bne.s loc_10FEA bsr.w Sonic_Jumpskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22385-L22389 — Sonic_MdAir runs Sonic_JumpHeight and Sonic_ChgJumpDir, never Sonic_JumpChecked by claude, 2026-10-21 — searched sonic3k.asm for every call to Sonic_Jump; the other two (L21658, L21691) are the same two ground modes of the Competition-mode Sonic

Tails's and Knuckles's jump routines were not traced for this claim.

Cited by: Coyote time, Sonic 3 & Knuckles

The spin dash is Sonic 2's, with the same $200 a press to $800, the same 1/32 decay, and the same release speeds from $800 to $C00. s3k/spindash

About: Sonic 3 & Knuckles Spin dash

Value
[
 2048,
 2176,
 2304,
 2432,
 2560,
 2688,
 2816,
 2944,
 3072
]
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23740-L23743move.b spin_dash_counter(a0),d0 add.w d0,d0 move.w word_11CF2(pc,d0.w),ground_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23773-L23782word_11CF2: dc.w $800 dc.w $880skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23798-L23814lsr.w #5,d0 sub.w d0,spin_dash_counter(a0) … addi.w #$200,spin_dash_counter(a0) cmpi.w #$800,spin_dash_counter(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37688-L37697SpindashSpeeds: dc.w $800 ; 0 … dc.w $C00 ; 8s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37714-L37729lsr.w #5,d0 sub.w d0,spindash_counter(a0) … addi.w #$200,spindash_counter(a0) cmpi.w #$800,spindash_counter(a0)Checked by claude, 2026-10-21 — read SonicKnux_Spindash at the pinned commit and compared it with s2disasm/spindash-charge and spindash-speeds

Cited by: Sonic 3 & Knuckles, Sonic the Hedgehog 2, Spin dash

Unlike Sonic 1 and Sonic 2, a standing player slides on a slope whose push, sine × $20, is at least $D; the walking and rolling factors stay $20 and $50. s3k/slope-standing

About: Sonic 3 & Knuckles Slope physics

Value
{
 "walk": 32,
 "rollDown": 80,
 "standMin": 13
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23866-L23896muls.w #$20,d0 asr.l #8,d0 tst.w ground_vel(a0) beq.s loc_11DDC … loc_11DDC: move.w d0,d1 bpl.s loc_11DE2 neg.w d1 loc_11DE2: cmpi.w #$D,d1 blo.s locret_11DDA add.w d0,ground_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23914muls.w #$50,d0s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37763-L37764tst.w inertia(a0) beq.s return_1ADCAs1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L1334-L1335tst.w obInertia(a0) ; check Sonic's ground speed beq.s .return ; if he's standing still, branchChecked by claude, 2026-10-21 — read Player_SlopeResist and Player_RollRepel at the pinned commit and compared them with Sonic 2's

s3.asm has the same branch (L21460-L21468), so Sonic 3 alone slides too. With a sine of 1.0 as 256, $D needs a sine of at least 104/256, an angle of roughly 24° or more.

Cited by: Slope physics, Sonic 3 & Knuckles, Sonic the Hedgehog, Sonic the Hedgehog 2

Below $280 ground speed on a steep slope the player now slips, a $80 push along the slope and a 30-frame d-pad lock, and falls off only near walls and ceilings; Sonic 1 and 2 dropped him from any slope past 45°. s3k/slope-slip

About: Sonic 3 & Knuckles Slope physics

Value
{
 "minSpeed": 640,
 "lock": 30,
 "nudge": 128
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23953-L23983addi.b #$18,d0 cmpi.b #$30,d0 blo.s locret_11E6E … cmpi.w #$280,d0 bhs.s locret_11E6E move.w #30,move_lock(a0) move.b angle(a0),d0 addi.b #$30,d0 cmpi.b #$60,d0 blo.s loc_11E70 bset #Status_InAir,status(a0) … addi.w #$80,ground_vel(a0) … subi.w #$80,ground_vel(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37832-L37841addi.b #$20,d0 andi.b #$C0,d0 … clr.w inertia(a0) bset #status.player.in_air,status(a0)s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L1412-L1427addi.b #$20,d0 ; rotate it by 45 degrees andi.b #$C0,d0 ; snap to nearest multiple of 90 degrees … clr.w obInertia(a0) ; clear ground speed bset #status_in_air_bit,obStatus(a0) ; set in-air flag to detach Sonic from wallChecked by claude, 2026-10-21 — read Player_SlopeRepel at the pinned commit and compared it with Sonic 2's Sonic_SlopeRepel

Angles are bytes, $40 a quarter turn. Sonic 3 & Knuckles checks angles past $18 (about 34°) and drops the player only past $30 (about 68°); Sonic 2 drops him past $20 (45°) and zeroes his speed.

Cited by: Slope physics, Sonic 3 & Knuckles

Rolling keeps Sonic 2's numbers, friction of half the acceleration ($6), $20 more against the d-pad, and X speed clamped to $1000. s3k/roll-speeds

About: Sonic 3 & Knuckles Rolling

Value
{
 "friction": 6,
 "brake": 32,
 "xCap": 4096
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22962-L22969move.w Acceleration-Max_speed(a4),d5 asr.w #1,d5 … move.w #$20,d4skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23055-L23057cmpi.w #$1000,d1 ble.s loc_115F6 move.w #$1000,d1s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37057-L37059asr.w #1,d5 ; natural roll deceleration = 1/2 normal acceleration move.w #$20,d4s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37137-L37139cmpi.w #$1000,d1 ble.s + move.w #$1000,d1 ; limit Sonic's speed rolling rightChecked by claude, 2026-10-21 — read Sonic_RollSpeed at the pinned commit

Cited by: Rolling

Against objects the player is still a 16 px wide box whose half-height is his height radius minus 3, and ducking no longer shrinks it. s3k/hitbox

About: Sonic 3 & Knuckles Hitbox

Value
{
 "w": 16,
 "h": 32,
 "rollH": 22
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20679-L20689subi.w #8,d2 ; Subtract Obj_Sonic's x_radius-1 from x_pos (becomes player's left collision boundary) moveq #0,d5 move.b y_radius(a0),d5 subq.b #3,d5 ; Now player's collision height … ; Height is no longer reduced by ducking move.w #$10,d4 ; Player's collision widths2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L85229-L85250subi_.w #8,d2 … subq.b #3,d5 … move.w #$10,d4s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/Sonic ReactToItem.asm#L17-L41subq.w #sonic_react_width,d2 … subq.b #3,d5 … move.w #sonic_react_width*2,d4Checked by claude, 2026-10-21 — read TouchResponse at the pinned commit; Sonic_Init sets the height radius to `$13` (L21940)

Cited by: Hitbox

A hit throws the player up at -$400 and away from the object at $200 (half both underwater), the speeds of Sonic 1 and Sonic 2. s3k/hurt-knockback

About: Sonic 3 & Knuckles Knockback

Value
{
 "vy": -1024,
 "vx": 512,
 "waterVy": -512,
 "waterVx": 256
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21130-L21141move.w #-$400,y_vel(a0) move.w #-$200,x_vel(a0) … move.w #-$200,y_vel(a0) move.w #-$100,x_vel(a0) … neg.w x_vel(a0)s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/Sonic ReactToItem.asm#L394-L395move.w #-$400,obVelY(a0) ; bounce Sonic vertically move.w #-$200,obVelX(a0) ; bounce Sonic horizontallys2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L85678-L85679move.w #-$400,y_vel(a0) ; make Sonic bounce away from the object move.w #-$200,x_vel(a0)Checked by claude, 2026-10-21 — read HurtCharacter at the pinned commit

Cited by: Knockback

The invulnerability count is now a byte but still 120, set by the hit and again on landing, and still blinks the sprite. s3k/hurt-invulnerable

About: Sonic 3 & Knuckles Invincibility frames

Value: 120 frames

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21146move.b #120,invulnerability_timer(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24545move.b #2*60,invulnerability_timer(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22073-L22078move.b invulnerability_timer(a0),d0 beq.s loc_10CA6 subq.b #1,invulnerability_timer(a0) lsr.b #3,d0s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/Sonic ReactToItem.asm#L410move.w #2*60,flashtime(a0) ; set temporary invulnerability time to 2 secondss2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L85696move.w #$78,invulnerable_time(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38271move.w #$78,invulnerable_time(a0)Checked by claude, 2026-10-21 — read HurtCharacter, the landing code after a hit, and Sonic_Display at the pinned commit

Cited by: Invincibility frames

Hit without a shield, the player drops his rings, at most 32 as bouncing rings, and the count goes to 0; with no rings he dies. s3k/hurt-rings

About: Sonic 3 & Knuckles Rings as health

Value
{
 "scatterMax": 32
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21102-L21118move.w (Ring_count).w,d0 … btst #0,status_secondary(a0) bne.s loc_102DA … tst.w d0 beq.w loc_10350 … move.l #Obj_Bouncing_Ring,(a1)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L35603-L35606moveq #$20,d0 cmp.w d0,d5 blo.s loc_1A6A6 move.w d0,d5skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L35658move.w #0,(Ring_count).wChecked by claude, 2026-10-21 — read HurtCharacter and the bouncing-ring spawner at the pinned commit; bit 0 of status_secondary is Status_Shield

Cited by: Rings as health, Sonic 3 & Knuckles

A hit with any shield costs the shield, not the rings; HurtCharacter clears the shield bit and all three element bits together (`andi.b s3k/shield-loss

About: Sonic 3 & Knuckles Shields

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21110-L21124btst #0,status_secondary(a0) bne.s loc_102DA … loc_102DA: andi.b #$8E,status_secondary(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.constants.asm#L184-L190Status_Shield = 0 Status_Invincible = 1 Status_SpeedShoes = 2Checked by claude, 2026-10-21 — read HurtCharacter and the status bit equates at the pinned commit

Cited by: Sonic 3 & Knuckles

An elemental shield makes the player immune to each object whose shield_reaction byte names that element, and any shield deflects objects flagged for it at 8 px/frame. s3k/shield-immunity

About: Sonic 3 & Knuckles Shields

Value
{
 "deflectSpeed": 2048
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21039-L21083and.b shield_reaction(a1),d0 ; Does one of the player's shields grant immunity to this object?? … andi.b #1<<3,d0 ; Should the object be bounced away by a shield? … muls.w #-$800,d1Checked by claude, 2026-10-21 — read Touch_ChkHurt at the pinned commit

Which hazards carry which bits (fire, electric, water, projectile) is set object by object and was not surveyed.

Cited by: Shields, Sonic 3 & Knuckles

A second press during a jump, once the rise is no faster than 4 px/frame (2 underwater), uses the shield: fire dashes at 8 px/frame and stops the fall, lightning jumps again at -$580, and bubble stops dead and drops at 8 px/frame, then bounces at 7.5 px/frame on landing. s3k/shield-moves

About: Sonic 3 & Knuckles Shields

Value
{
 "fireX": 2048,
 "lightningY": -1408,
 "bubbleY": 2048,
 "bubbleBounce": 1920,
 "bubbleBounceWater": 1024
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23400-L23411Sonic_JumpHeight: tst.b jumping(a0) ; is Sonic jumping? beq.s Sonic_UpVelCap ; if not, branch … ble.w Sonic_ShieldMoves ; if not, branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23446-L23488move.w #$800,d0 … move.w #0,y_vel(a0) ; kill y-velocity … move.w #-$580,y_vel(a0) ; bounce Sonic up, creating the double jump effect … move.w #0,x_vel(a0) ; halt horizontal speed … move.w #$800,y_vel(a0) ; force Sonic downskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24436-L24441BubbleShield_Bounce: movem.l d1-d2,-(sp) move.w #$780,d2 btst #Status_Underwater,status(a0) beq.s loc_12246 move.w #$400,d2Checked by claude, 2026-10-21 — read Sonic_ShieldMoves through Sonic_BubbleShield and BubbleShield_Bounce at the pinned commit

Only Sonic gets the moves; Sonic_FireShield is skipped while he is invincible. The bounce goes along the ground's normal.

Cited by: Shields, Sonic 3 & Knuckles

With no shield, the press gives Sonic the insta-shield, which while active makes him invincible and widens his hit box to 48 × 48 px. s3k/insta-shield

About: Sonic 3 & Knuckles Shields

Value
{
 "w": 48,
 "h": 48
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23508-L23514btst #Status_Shield,status_secondary(a0) ; does Sonic have an S2 shield? (the elementals were already filtered out at this point) bne.s locret_11A14 ; if yes, branch move.b #1,(Shield+anim).w move.b #1,double_jump_flag(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20656-L20666cmpi.b #1,double_jump_flag(a0) ; Is the Insta-Shield currently in its 'attacking' mode? … bset #Status_Invincible,status_secondary(a0) ; Make the player invincible … move.w #$30,d4 ; Player's width move.w #$30,d5 ; Player's heightChecked by claude, 2026-10-21 — read Sonic_InstaShield and TouchResponse at the pinned commit

How many frames the attacking mode lasts is set by the shield object's animation and was not traced.

Cited by: Shields, Sonic 3 & Knuckles

Sonic 3 alone (s3.asm) has the same shield moves and insta-shield; its transformation check asks only for the seven Chaos Emeralds and 50 rings. s3k/sonic-3-alone

About: Sonic 3 & Knuckles Shields

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21122-L21184move.w #$800,d0 … move.w #-$580,y_vel(a0) … move.w #$800,y_vel(a0) … Sonic_CheckTransform: cmpi.w #7,(Chaos_emerald_count).wChecked by claude, 2026-10-21 — read Sonic_ShieldMoves in s3.asm at the pinned commit and compared it with sonic3k.asm L23432-L23518

Cited by: Sonic 3 & Knuckles

Tails flies for 480 frames, a count of 240 that drops every other frame; flying adds $8 gravity a frame, and while time remains each press lifts him $20 a frame for up to 30 frames, until he rises faster than 1 px/frame. s3k/tails-flight

About: Sonic 3 & Knuckles Flight

Value
{
 "frames": 480,
 "gravity": 8,
 "lift": 32,
 "liftFrames": 30,
 "liftUntil": -256
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L28703-L28705move.b #1,double_jump_flag(a0) move.b #(8*60)/2,double_jump_property(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L27632-L27674andi.b #1,d0 beq.s loc_14836 tst.b double_jump_property(a0) beq.s loc_14836 subq.b #1,double_jump_property(a0) … cmpi.w #-$100,y_vel(a0) blt.s loc_14858 subi.w #$20,y_vel(a0) addq.b #1,double_jump_flag(a0) cmpi.b #$20,double_jump_flag(a0) … move.b #2,double_jump_flag(a0) loc_1488C: addi.w #8,y_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L27610-L27614jsr (MoveSprite_TestGravity2).lChecked by claude, 2026-10-21 — read Tails_Test_For_Flight, Tails_FlyingSwimming, and Tails_Move_FlySwim at the pinned commit; MoveSprite_TestGravity2 moves without gravity, so the 8 is the only gravity in flight

A press sets the flag to 2; each lifting frame adds 1, and at $20 the lift stops (30 frames). Lifting frames skip the +8. With the count at 0 a press does nothing. Underwater, carrying Sonic, a press doesn't lift.

Cited by: Flight, Sonic 3 & Knuckles

Knuckles's glide starts at 4 px/frame and gains $4 a frame to a cap of 24 px/frame, and its fall settles near 0.5 px/frame, $20 added below $80 and taken above. s3k/knuckles-glide

About: Sonic 3 & Knuckles Flight

Value
{
 "start": 1024,
 "accel": 4,
 "cap": 6144,
 "fallTarget": 128,
 "fallStep": 32
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L32600-L32613addi.w #$200,y_vel(a0) bpl.s loc_17898 move.w #0,y_vel(a0) loc_17898: moveq #0,d1 move.w #$400,d0 move.w d0,ground_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L31642-L31663cmpi.w #$400,d0 bhs.s .mediumSpeed … addq.w #8,d0 … cmpi.w #$1800,d0 bhs.s .applySpeed … addq.w #4,d0skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L31723-L31731cmpi.w #$80,y_vel(a0) blt.s .fallingSlow subi.w #$20,y_vel(a0) bra.s .fallingFast … addi.w #$20,y_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L30748-L30764andi.b #button_A_mask|button_B_mask|button_C_mask,d0 bne.s .continueGliding … asr.w x_vel(a0) asr.w x_vel(a0)Checked by claude, 2026-10-21 — read Knux_Test_For_Glide, Knuckles_Move_Glide, and Knuckles_Glide at the pinned commit; Knux_Glide_Freespace moves with MoveSprite_TestGravity2, which adds no gravity

The start adds $200 to Y speed and stops any rise. Gliding needs the button held; letting go quarters the X speed and drops him. Turning holds the speed and swings the direction through a sine.

Cited by: Flight, Sonic 3 & Knuckles

With neither Left nor Right held, Sonic_Move takes the current acceleration off a standing or running Sonic's ground speed each frame, stopping at 0, as Sonic 2 does; that is $C out of water and without speed shoes (ground-speeds), and $C for Super Sonic. With the infinite-inertia flag some objects set (bit 7 of status_secondary), it skips the d-pad and the friction both. s3k/ground-friction

About: Sonic 3 & Knuckles Running

Value: 12 1/256 px/frame²

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22713-L22735loc_11306: … andi.b #button_left_mask|button_right_mask,d0 bne.s loc_11332 move.w ground_vel(a0),d0 … sub.w d5,d0 bcc.s loc_11320 move.w #0,d0 … add.w d5,d0 bcc.s loc_1132E …s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36826-L36846move.w inertia(a0),d0 ; get Sonic's current ground speed … sub.w d5,d0 ; reduce current rightward speed by acceleration … move.w #0,d0 ; reset speed to zero on sign change … add.w d5,d0 ; reduce current leftward speed by acceleration … move.w #0,d0 ; reset speed to zero on sign changeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22467-L22468tst.b status_secondary(a0) ; is bit 7 set? (Infinite inertia) bmi.w loc_11332 ; if so, branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22709-L22711tst.b (Super_Sonic_Knux_flag).w beq.s loc_11306 move.w #$C,d5Checked by claude, 2026-10-26 — read loc_11306 in Sonic_Move at the pinned commit; d5 holds the acceleration from the Max_speed block (Sonic_Move's first lines, L22463-L22465), which water and speed shoes change, or `$C` for Super Sonic

Sonic 3 & Knuckles keeps Sonic 2's skid bug: on flat ground, not mid-flip (flip_type not negative), a reversal skids (stopping animation, facing his motion) when the slowed speed is at least $400 moving right but only $301 moving left, because the angle read overwrites the speed's low byte. s3k/skid-threshold

About: Sonic 3 & Knuckles Running

Value
{
 "right": 1152,
 "left": 897
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22850-L22879loc_11430: sub.w d4,d0 … move.w #-$80,d0 … ; These three instructions partially overwrite the inertia value in … move.b angle(a0),d0 addi.b #$20,d0 andi.b #$C0,d0 … cmpi.w #$400,d0 …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22916-L22943loc_114B6: add.w d4,d0 … move.w #$80,d0 … move.b angle(a0),d0 addi.b #$20,d0 andi.b #$C0,d0 … cmpi.w #-$400,d0 bgt.s locret_11506 tst.b flip_type(a0) …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L38 — the build's FixBugs, 0, keeps the bugFixBugs = 0s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36966-L36974move.b angle(a0),d0 ; get Sonic's current angle (and partially overwrite d0...) … cmpi.w #$400,d0 ; has Sonic changed direction while being really fast? blt.s return_1A744 ; if not, don't play skidding animation/sound … bclr #status.player.x_flip,status(a0) ; clear X-flip flag (Sonic is now facing right)Checked by claude, 2026-10-26 — read sub_113F6 and sub_11482 at the pinned commit: d0's low byte becomes the angle + `$20` masked to `$C0`, 0 on flat ground, before `cmpi.w #$400,d0` (right) and `cmpi.w #-$400,d0` (left)

Moving left, the slowed speed with its low byte zeroed is at most −$400 once it is −$301 or less; before the frame, that is −$381 (897). Moving right it needs $400 after the $80 brake, $480 (1152) before.

On the ground the d-pad turns Sonic only when his ground speed is 0 or already that way, and a skid turns him to face his motion; rolling, the same, with no skid; in the air, Left or Right turns him at once unless he jumped from a roll. While the spin dash charges, the d-pad doesn't turn him. On the ground and rolling, the d-pad is skipped altogether while an object holds his controls: move_lock, the infinite-inertia flag (bit 7 of status_secondary), or, rolling, a negative spin_dash_flag (pinball mode). s3k/facing

About: Sonic 3 & Knuckles Running

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22822-L22828sub_113F6: move.w ground_vel(a0),d0 beq.s loc_113FE bpl.s loc_11430 loc_113FE: bset #Status_Facing,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22893-L22897sub_11482: move.w ground_vel(a0),d0 bmi.s loc_114B6 bclr #Status_Facing,status(a0) beq.s loc_1149Cskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23073-L23080sub_11608: move.w ground_vel(a0),d0 beq.s loc_11610 bpl.s loc_1161E loc_11610: bset #Status_Facing,status(a0) move.b #2,anim(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23127-L23133btst #Status_RollJump,status(a0) ; did Sonic jump from rolling? bne.s Sonic_Jump_ResetScr ; if yes, branch to skip midair control move.w x_vel(a0),d0 btst #button_left,(Ctrl_1_held_logical).w beq.s loc_11682 ; if not holding left, branch bset #Status_Facing,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23762-L23764btst #Status_Facing,status(a0) beq.s loc_11CDC neg.w ground_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22467-L22470tst.b status_secondary(a0) ; is bit 7 set? (Infinite inertia) bmi.w loc_11332 ; if so, branch tst.w move_lock(a0) bne.w loc_112EAskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22970-L22975tst.b spin_dash_flag(a0) bmi.w loc_115C6 tst.b status_secondary(a0) bmi.w loc_115C6 tst.w move_lock(a0) bne.s loc_1154EChecked by claude, 2026-10-26 — read Sonic_Move's and Sonic_RollSpeed's first lines, sub_113F6, sub_11482, sub_11608, sub_1162C, Sonic_ChgJumpDir, and the spin dash's release at the pinned commit; Status_Facing set is facing left (`bset` on Left, `bclr` on Right)

A balance turns him too (balance).

Standing, Sonic's floor and ceiling sensors sit 19 px above and below his center and 9 px to each side, a 19 × 39 px box; curled up, 14 and 7, 15 × 29 px; his wall sensors sit 10 px to either side. These are Sonic 2's sizes. s3k/collision-box

About: Sonic 3 & Knuckles Hitbox

Value
{
 "w": 19,
 "h": 39,
 "rollW": 15,
 "rollH": 29,
 "radius": {
  "w": 9,
  "h": 19,
  "rollW": 7,
  "rollH": 14,
  "push": 10
 }
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L21940-L21943move.b #$13,y_radius(a0) ; this sets Sonic's collision height (2*pixels) move.b #9,x_radius(a0) move.b #$13,default_y_radius(a0) move.b #9,default_x_radius(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23296-L23299move.b #$E,y_radius(a0) move.b #7,x_radius(a0) move.b #2,anim(a0) ; enter roll animation addq.w #5,y_pos(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20231addi.w #$A,d3skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20548subi.w #$A,d3s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37368-L37371move.b #$E,y_radius(a0) move.b #7,x_radius(a0) move.b #AniIDSonAni_Roll,anim(a0) ; use "rolling" animation addq.w #5,y_pos(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36226-L36227move.b #$13,y_radius(a0) ; this sets Sonic's collision height (2*pixels) move.b #9,x_radius(a0) ; this sets Sonic's Collision width (2*pixels)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L44376 — Sonic 2's CheckRightWallDistaddi.w #$A,d3s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L44567 — Sonic 2's CheckLeftWallDistsubi.w #$A,d3Checked by claude, 2026-10-26 — read Sonic_Init, Player_DoRoll, CheckRightWallDist, and CheckLeftWallDist at the pinned commit, and Sonic 2's Obj01_Init, Sonic_Roll, CheckRightWallDist, and CheckLeftWallDist

A sensor at center + radius tests the radius-th pixel out, so the box spans 2 × radius + 1 pixels.

With Down held, neither Left nor Right, and no infinite-inertia flag (bit 7 of status_secondary), Sonic curls into a roll at a ground speed of $100 or more either way, twice Sonic 2's $80; slower than that, unless he stands on an object, he crouches, where Sonic 2 and Sonic 3 alone crouch only from Sonic_Move's standstill branch. s3k/roll-start

About: Sonic 3 & Knuckles Rolling

Value: 256 1/256 px/frame

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23258-L23278SonicKnux_Roll: … andi.b #button_left_mask|button_right_mask,d0 ; is left/right being pressed? bne.s locret_1177E ; if yes, branch btst #button_down,(Ctrl_1_logical).w ; is down being pressed? … cmpi.w #$100,d0 ; is Sonic moving at $100 speed or faster? bhs.s Player_ChkRoll ; if so, branch btst #Status_OnObj,status(a0) … move.b #8,anim(a0) ; enter ducking animations2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37345-L37352mvabs.w inertia(a0),d0 cmpi.w #$80,d0 ; is Sonic moving at $80 speed or faster? blo.s Obj01_NoRoll ; if not, branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L20970-L20976 — Sonic 3 alone keeps Sonic 2's checkcmpi.w #$80,d0 ; is Sonic moving at $80 speed or faster? blo.s locret_127D0 ; if so, branchs2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36788-L36791 — Sonic 2's crouch, reached from Sonic_Move's standstill branchSonic_Duck: btst #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed? beq.s Obj01_ResetScr ; if not, branch move.b #AniIDSonAni_Duck,anim(a0) ; use "ducking" animationskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L20420-L20423 — Sonic 3 alone's crouch, in Sonic_Move's standstill branchloc_12362: btst #button_down,(Ctrl_1_held_logical).w beq.s loc_1238C move.b #8,anim(a0)Checked by claude, 2026-10-26 — read SonicKnux_Roll in sonic3k.asm, Sonic_Roll and Sonic_Move's standstill branch in s3.asm, and Sonic 2's Sonic_Roll and Sonic_Duck at their pinned commits

The crouch is animation 8, which a jump press turns into a spin dash (spindash-controls); with Down released, Player_ChkWalk sets animation 0 again. Holding Left or Right skips the routine, so a crouch already begun stays through a brake.

Cited by: Sonic 3 & Knuckles

Outside pinball mode (spin_dash_flag set on a roll) and without the infinite-inertia flag, a roll ends once friction and the d-pad leave the ground speed under $80 either way, and the speed left is kept; Sonic 2 and Sonic 3 alone unroll only at 0. Standing up moves his center 5 px up with normal gravity. In pinball mode a positive flag sets the speed to $400 in his facing direction instead, and a negative one skips the d-pad, friction, and this check. s3k/unroll

About: Sonic 3 & Knuckles Rolling

Value: 128 1/256 px/frame

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23007-L23028move.w ground_vel(a0),d0 … cmpi.w #$80,d0 bhs.s loc_115C6 … bclr #Status_Roll,status(a0) move.b y_radius(a0),d0 move.b default_y_radius(a0),y_radius(a0) … sub.b default_y_radius(a0),d0 … add.w d0,y_pos(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37097-L37106Sonic_CheckRollStop: tst.w inertia(a0) bne.s Obj01_Roll_ResetScr … bclr #status.player.rolling,status(a0) … subq.w #5,y_pos(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L20728-L20739tst.w ground_vel(a0) bne.s loc_12636 … bclr #Status_Roll,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22970-L22973tst.b spin_dash_flag(a0) bmi.w loc_115C6 tst.b status_secondary(a0) bmi.w loc_115C6skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23032-L23036loc_115B4: move.w #$400,ground_vel(a0) btst #Status_Facing,status(a0) beq.s loc_115C6 neg.w ground_vel(a0)Checked by claude, 2026-10-26 — read Sonic_RollSpeed in sonic3k.asm and s3.asm and Sonic 2's Sonic_CheckRollStop at their pinned commits

The check runs after the roll's friction, every rolling frame. spin_dash_flag stays 0 on a roll in the lab.

Cited by: Sonic 3 & Knuckles

Crouching (animation 8), a press of A, B, or C starts the spin dash's charge at 0; while Down stays held, each frame first takes 1/32 of the counter (rounded down) and a press adds $200, to $800; letting go of Down releases it, curling him (5 px down) and setting the ground speed from the counter's high byte (spindash; Super Sonic's table is faster), negated facing left. On the start, charge, and release frames he doesn't move, and the floor sensors still run. The charge's decay, step, and cap are Sonic 2's. s3k/spindash-controls

About: Sonic 3 & Knuckles Spin dash

Value
{
 "charge": 512,
 "max": 2048,
 "decayShift": 5
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23679-L23696SonicKnux_Spindash: tst.b spin_dash_flag(a0) bne.s loc_11C5E cmpi.b #8,anim(a0) … move.b (Ctrl_1_pressed_logical).w,d0 andi.b #button_A_mask|button_B_mask|button_C_mask,d0 … addq.l #4,sp move.b #1,spin_dash_flag(a0) move.w #0,spin_dash_counter(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23737-L23746move.b #0,spin_dash_flag(a0) … move.b spin_dash_counter(a0),d0 … move.w word_11CF2(pc,d0.w),ground_vel(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23770-L23771jsr (Play_SFX).l bra.s loc_11D5Eskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23796-L23822move.w spin_dash_counter(a0),d0 lsr.w #5,d0 sub.w d0,spin_dash_counter(a0) … addi.w #$200,spin_dash_counter(a0) cmpi.w #$800,spin_dash_counter(a0) … loc_11D5E: addq.l #4,sps2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37714-L37729lsr.w #5,d0 sub.w d0,spindash_counter(a0) … addi.w #$200,spindash_counter(a0) cmpi.w #$800,spindash_counter(a0)Checked by claude, 2026-10-26 — read SonicKnux_Spindash at the pinned commit and compared it with s2disasm/spindash-start and spindash-charge; `addq.l #4,sp` drops Sonic_MdNormal's return, so the rest of the mode (the move included) doesn't run, and loc_11D5E calls Player_LevelBound and Player_AnglePos itself

The crouch can begin while he still moves slower than $100 (roll-start), so a spin dash can start with ground speed left over; it stays until the release sets the speed.

Cited by: Sonic 3 & Knuckles

With room overhead (jump-headroom), a jump press adds the jump speed along the ground's normal, -$680 straight up on flat ground with normal gravity (jump-speed gives the underwater and Super speeds), keeps the X speed, and ends the frame: the jump frame moves nothing. Standing, the jump curls Sonic and moves his center 5 px down (up with reverse gravity); from a roll he keeps the standing size (roll-jump-size). s3k/takeoff

About: Sonic 3 & Knuckles Jump

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23353-L23366add.w d1,x_vel(a0) ; make Sonic jump (in X... this adds nothing on level ground) … add.w d0,y_vel(a0) ; make Sonic jump (in Y) bset #Status_InAir,status(a0) … addq.l #4,spskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23370-L23386move.b default_y_radius(a0),y_radius(a0) … btst #Status_Roll,status(a0) bne.s Sonic_RollJump move.b #$E,y_radius(a0) … bset #Status_Roll,status(a0) … sub.w d0,y_pos(a0)s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/01 Sonic.asm#L1224-L1236add.w d1,obVelX(a0) ; apply to X speed … add.w d0,obVelY(a0) ; apply to Y speed … addq.l #4,sp ; run in-air subroutines when we returnThe atlas reads this differently: Dropping the return address returns from Sonic_MdNormal itself, skipping the rest of the grounded routine, SpeedToPos included. The in-air routines run from the next frame. (s1disasm/jump-frame-no-move)Checked by claude, 2026-10-26 — read Sonic_Jump at the pinned commit; `addq.l #4,sp` drops the caller's return, so Sonic_Move and the move don't run on the press frame

A jump from a roll sets the roll-jump flag, and while it is set Sonic_ChgJumpDir skips the d-pad: no steering and no turning, though the air drag still runs. Landing clears it, as Sonic 2's Sonic_ResetOnFloor does; unlike Sonic 2, whose Sonic_JumpHeight only caps the rise, a jump press once his rise is no faster than 4 px/frame (2 underwater) clears it too (insta-shield-motion), as in Sonic 3 alone. s3k/roll-jump-lock

About: Sonic 3 & Knuckles Air control

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23392-L23393Sonic_RollJump: bset #Status_RollJump,status(a0) ; set the rolling+jumping flagskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23127-L23128btst #Status_RollJump,status(a0) ; did Sonic jump from rolling? bne.s Sonic_Jump_ResetScr ; if yes, branch to skip midair controls2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37207-L37208btst #status.player.rolljumping,status(a0) ; did Sonic jump from rolling? bne.s Obj01_Jump_ResetScr ; if yes, branch to skip midair controlskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24408 — Player_TouchFloorbclr #Status_RollJump,status(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38188-L38191 — Sonic 2's Sonic_ResetOnFloorbclr #status.player.in_air,status(a0) bclr #status.player.pushing,status(a0) bclr #status.player.rolljumping,status(a0) move.b #0,jumping(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37461-L37479 — Sonic 2's routine caps the rise and checks for Super Sonic, and touches no roll-jump flagSonic_JumpHeight: tst.b jumping(a0) ; is Sonic jumping? … move.w d1,y_vel(a0) ; immediately reduce Sonic's upward speed to d1 + tst.b y_vel(a0) ; is Sonic exactly at the height of his jump? beq.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rtsskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21115 — Sonic 3 alone's Sonic_ShieldMovesbclr #Status_RollJump,status(a0)Checked by claude, 2026-10-26 — read Sonic_Jump, Sonic_ChgJumpDir, Sonic_JumpHeight, and Player_TouchFloor at the pinned commit, and Sonic 2's Sonic_ChgJumpDir, Sonic_JumpHeight, and Sonic_ResetOnFloor; Sonic_Jump_ResetScr falls into Sonic_JumpPeakDecelerate

A jump from a roll resets Sonic's sensors to the standing size, 19 px below his center, while his ball stays drawn, so he lands 5 px higher than a standing jump would, and landing moves him by the difference, 0. Sonic 2 has the same order of instructions. s3k/roll-jump-size

About: Sonic 3 & Knuckles Jump

Value: 5 px

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23370-L23373move.b default_y_radius(a0),y_radius(a0) move.b default_x_radius(a0),x_radius(a0) btst #Status_Roll,status(a0) bne.s Sonic_RollJumpskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24381-L24388move.b y_radius(a0),d0 move.b default_y_radius(a0),y_radius(a0) … btst #Status_Roll,status(a0) … sub.b default_y_radius(a0),d0s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37431-L37435move.b #$13,y_radius(a0) move.b #9,x_radius(a0) endif btst #status.player.rolling,status(a0) bne.s Sonic_RollJumpChecked by claude, 2026-10-26 — read Sonic_Jump and Player_TouchFloor at the pinned commit and Sonic 2's Sonic_Jump

A jump press during a jump, once the rise is no faster than 4 px/frame (2 underwater) and before any shield move or insta-shield this jump, clears the roll-jump flag before the shield checks, so a roll jump gets its steering back. With no shield, not invincible, not Super, and short of turning Super (50 rings, Update_HUD_timer nonzero, and seven Super Emeralds, or seven Chaos Emeralds with Emeralds_converted_flag clear), the insta-shield follows and doesn't change his position or speed; with an elemental shield its move follows (shield-moves). Later presses do nothing until he lands. s3k/insta-shield-motion

About: Sonic 3 & Knuckles Shields

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23432-L23438Sonic_ShieldMoves: tst.b double_jump_flag(a0) ; is Sonic currently performing a double jump? bne.w locret_11A14 ; if yes, branch move.b (Ctrl_1_pressed_logical).w,d0 … bclr #Status_RollJump,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23446-L23481 — Sonic_FireShield, Sonic_LightningShield, and Sonic_BubbleShield, each passed without its shield; invincibility returns at onceskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23494-L23506Sonic_CheckTransform: cmpi.b #7,(Super_emerald_count).w ; does Sonic have all 7 Super Emeralds? bhs.s loc_119E8 ; if yes, branch cmpi.b #7,(Chaos_emerald_count).w ; does Sonic have all 7 Chaos Emeralds? blo.s Sonic_InstaShield ; if not, branch tst.b (Emeralds_converted_flag).w bne.s Sonic_InstaShield … cmpi.w #50,(Ring_count).w ; does Sonic have at least 50 rings? blo.s Sonic_InstaShield ; if not, perform Insta-Shield tst.b (Update_HUD_timer).w bne.s Sonic_Transformskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23508-L23514Sonic_InstaShield: … move.b #1,(Shield+anim).w move.b #1,double_jump_flag(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L34647-L34651cmpi.b #7,mapping_frame(a0) ; Has it reached then end of its animation? … move.b #2,double_jump_flag(a2) ; Mark attack as overskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24415-L24426tst.b double_jump_flag(a0) … loc_1222A: move.b #0,double_jump_flag(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23400-L23411Sonic_JumpHeight: tst.b jumping(a0) ; is Sonic jumping? beq.s Sonic_UpVelCap ; if not, branch move.w #-$400,d1 btst #Status_Underwater,status(a0) ; is Sonic underwater? beq.s loc_118D2 ; if not, branch move.w #-$200,d1 ; Underwater-specific loc_118D2: cmp.w y_vel(a0),d1 ; is y speed greater than 4? (2 if underwater) ble.w Sonic_ShieldMoves ; if not, branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21115 — Sonic 3 alone's Sonic_ShieldMovesbclr #Status_RollJump,status(a0)Checked by claude, 2026-10-26 — read Sonic_JumpHeight, Sonic_ShieldMoves through Sonic_InstaShield, Obj_InstaShield_Main, and Player_TouchFloor at the pinned commit, and s3.asm's Sonic_ShieldMoves; double_jump_flag goes 1 on the press, 2 when the shield's animation ends, and 0 only on landing

Sonic 3 alone has the same bclr. The elemental shields' moves do change his motion (shield-moves) but aren't in the lab.

Landing on flat ground keeps Sonic's horizontal speed as his ground speed, sets his Y speed to 0, and, if he was curled and spin_dash_flag is clear (not pinball mode), uncurls him; with normal gravity a ball from a standing jump or a roll moves 5 px up, one from a roll jump doesn't move. It clears the jump, roll-jump, and insta-shield flags; with the bubble shield used, it bounces him instead (shield-moves). s3k/landing

About: Sonic 3 & Knuckles Jump

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24139-L24142loc_11F9C: move.w #0,y_vel(a0) move.w x_vel(a0),ground_vel(a0) bsr.w Player_TouchFloor_Check_Spindashskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24365-L24368 — with the flag set it jumps past the uncurlPlayer_TouchFloor_Check_Spindash: tst.b spin_dash_flag(a0) bne.s loc_121D8 move.b #0,anim(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24375-L24409Player_TouchFloor: … move.b y_radius(a0),d0 move.b default_y_radius(a0),y_radius(a0) … btst #Status_Roll,status(a0) … bclr #Status_Roll,status(a0) … sub.b default_y_radius(a0),d0 … add.w d0,y_pos(a0) …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24415-L24426tst.b double_jump_flag(a0) … loc_1222A: move.b #0,double_jump_flag(a0)Checked by claude, 2026-10-26 — read SonicKnux_DoLevelCollision's floor branch and Player_TouchFloor at the pinned commit

The lab's stages are built of Angel Island Act 1's block 1, a full 16 × 16 px block solid from every side; Sonic 3 & Knuckles's level collision is 16 × 16 px blocks, and a sensor's search looks in its block and at most one more. s3k/collision-blocks

About: Sonic 3 & Knuckles Hitbox

Value
{
 "word": 61441,
 "index": 255
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19250-L19264sub_F264: … move.w (a1),d0 … andi.w #$3FF,d0 … btst d5,d4 bne.s loc_F282 loc_F274: add.w a3,d2 bsr.w sub_F30C … …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19301-L19325cmpi.b #$10,d0 beq.s loc_F2FE … move.w #$F,d1 sub.w d0,d1 … loc_F2FE: sub.w a3,d2 bsr.w sub_F30C … subi.w #$10,d1Checked by claude, 2026-10-26 — read FindFloor's sub_F264 at the pinned commit; read block 1's entries in Levels/AIZ/Collision/1.bin (primary and secondary index `$FF`) and height map `$FF` (16 in every column) in the disassembly's data

A chunk word's low 10 bits are the block and bits 12 to 15 its solidity for the two collision paths; $F001 is block 1 solid from every side on both. The lab's ROM check reads block 1's collision index in RAM at the start of each run.

On a flat floor, not standing on an object, after each ground move, Player_AnglePos reads two floor sensors, at his center's X ± his width radius and his center's Y + his height radius; the nearer floor counts, and from 1 to 14 px into it he moves up to its surface. s3k/floor-sensors

About: Sonic 3 & Knuckles Hitbox

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L18812-L18847move.w y_pos(a0),d2 move.w x_pos(a0),d3 … move.b y_radius(a0),d0 … add.w d0,d2 move.b x_radius(a0),d0 … add.w d0,d3 … bsr.w FindFloor … …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L18886-L18893Player_Angle: move.w d0,d3 move.b (Secondary_Angle).w,d2 cmp.w d0,d1 ble.s loc_ED5E move.b (Primary_Angle).w,d2 move.w d1,d3 move.w d0,d1Checked by claude, 2026-10-26 — read Player_AnglePos and Player_Angle at the pinned commit

Above the floor, walk-off decides between a snap down and a fall.

On flat ground, not on an object, when both floor sensors find the floor more than |X speed's high byte| + 4 px below, at most 14, Sonic leaves the ground with his speeds as they are, unless stick_to_convex is set; closer than that, he moves down to it. Sonic 2 has the same rule; Sonic 1 used a flat 14 px. s3k/walk-off

About: Sonic 3 & Knuckles Coyote time

Value
{
 "add": 4,
 "max": 14
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L18853-L18879loc_ED14: … move.b x_vel(a0),d0 … neg.b d0 … addq.b #4,d0 cmpi.b #$E,d0 … move.b #$E,d0 … cmp.b d0,d1 …s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L43135-L43143loc_1E31E: mvabs.b x_vel(a0),d0 addq.b #4,d0 cmpi.b #$E,d0 blo.s + move.b #$E,d0 + cmp.b d0,d1 bgt.s loc_1E33Cs1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm) · _incObj/Sonic AnglePos.asm#L100-L101 — Sonic 1's AnglePoscmpi.w #$E,d1 bgt.s .in_air ; branch if Sonic is > 14px above floorskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L18854tst.b stick_to_convex(a0)Checked by claude, 2026-10-26 — read Player_AnglePos at the pinned commit, Sonic 2's AnglePos, and Sonic 1's; `move.b x_vel(a0),d0` reads the speed's high byte, its whole pixels

stick_to_convex, which skips the test, is 0 in the lab.

Cited by: Sonic 3 & Knuckles

Outside Competition mode, on flat ground with a ground speed, Sonic's wall sensor sits 10 px ahead of where the frame's speeds would put his center and 8 px below it; in the air his side sensors sit 10 px to either side of his center at its height. s3k/wall-sensors

About: Sonic 3 & Knuckles Hitbox

Value: 8 px below his center, on flat ground

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19725-L19773move.l x_pos(a0),d3 move.l y_pos(a0),d2 move.w x_vel(a0),d1 … add.l d1,d3 move.w y_vel(a0),d1 … add.l d1,d2 … andi.b #$38,d1 … addq.w #8,d2skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20224-L20231CheckRightWallDist: move.w y_pos(a0),d2 move.w x_pos(a0),d3 tst.w (Competition_mode).w bne.s loc_FAA4 loc_FA88: addi.w #$A,d3skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20541-L20548CheckLeftWallDist: move.w y_pos(a0),d2 move.w x_pos(a0),d3 tst.w (Competition_mode).w bne.s loc_FDC8 loc_FDA8: subi.w #$A,d3Checked by claude, 2026-10-26 — read sub_F61C, CheckRightWallDist, and CheckLeftWallDist at the pinned commit

On flat ground, with a ground speed and bit 6 of object_control clear (no object carrying him), a wall at the sensor ahead cuts the frame's X speed by the sensor's depth in whole pixels, so the move stops him beside it, and sets the ground speed to 0. s3k/ground-wall

About: Sonic 3 & Knuckles Hitbox

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22747-L22809loc_11350: btst #6,object_control(a0) bne.w locret_113F4 … tst.w ground_vel(a0) … bsr.w sub_F61C … tst.w d1 bpl.s locret_113F4 asl.w #8,d1 … …Checked by claude, 2026-10-26 — read loc_11350 in Sonic_Move at the pinned commit; Sonic_RollSpeed branches to it too (L23066)

In the air SonicKnux_DoLevelCollision picks one of four checks by the direction of his speeds after gravity, from GetArcTan less $20: mostly down, mostly up, mostly left, or mostly right. The arctangent table puts the split where the smaller speed is 250/256 of the larger. s3k/air-quadrant

About: Sonic 3 & Knuckles Hitbox

Value: 250 /256, the ratio of the smaller speed to the larger at which the table reaches `$20`

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24083-L24093move.w x_vel(a0),d1 move.w y_vel(a0),d2 jsr (GetArcTan).l subi.b #$20,d0 andi.b #$C0,d0 cmpi.b #$40,d0 beq.w Player_HitLeftWall cmpi.b #$80,d0 beq.w Player_HitCeilingAndWalls cmpi.b #$C0,d0 beq.w loc_12102skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L3094-L3118cmp.w d3,d4 … move.b ArcTanTable(pc,d4.w),d0 … moveq #$40,d0 sub.b ArcTanTable(pc,d3.w),d0 ; arctan(y/x) = 90 - arctan(x/y)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L3132-L3133ArcTanTable: binclude "Levels/Misc/arctan.bin"Checked by claude, 2026-10-26 — read SonicKnux_DoLevelCollision and GetArcTan at the pinned commit; `od -An -tx1 -j 240 -N 17 Levels/Misc/arctan.bin` at the pin gives `$1F` for entries 240 to 249 and `$20` from entry 250 to 256

With both speeds 0, GetArcTan returns $40, the down check.

Moving mostly down or up, both side sensors push Sonic out of a wall and stop his X speed; moving mostly left or right, only that side's does, and it also sets his ground speed to his Y speed. Unlike Sonic 2, a push moving left or right doesn't end the checks: the ceiling and then the floor are still tested. s3k/air-wall

About: Sonic 3 & Knuckles Hitbox

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24094-L24105bsr.w CheckLeftWallDist tst.w d1 bpl.s loc_11F44 sub.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall loc_11F44: bsr.w CheckRightWallDist tst.w d1 bpl.s loc_11F56 add.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wallskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24203-L24212Player_HitLeftWall: bsr.w CheckLeftWallDist tst.w d1 bpl.s Player_HitCeiling ; branch if distance is positive (not inside wall) sub.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall move.w y_vel(a0),ground_vel(a0) Player_HitCeiling: bsr.w sub_11FEEskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24312-L24321loc_12102: bsr.w CheckRightWallDist tst.w d1 bpl.s loc_1211A add.w d1,x_pos(a0) move.w #0,x_vel(a0) move.w y_vel(a0),ground_vel(a0) loc_1211A: bsr.w sub_11FEEs2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38012-L38019Sonic_HitLeftWall: bsr.w CheckLeftWallDist tst.w d1 bpl.s Sonic_HitCeiling ; branch if distance is positive (not inside wall) sub.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall move.w y_vel(a0),inertia(a0) rtss2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38106-L38113Sonic_HitRightWall: bsr.w CheckRightWallDist tst.w d1 bpl.s Sonic_HitCeiling2 add.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall move.w y_vel(a0),inertia(a0) rtsskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21730-L21743 — Sonic 3 alone's Player_HitLeftWall, falling through to the ceiling checkbsr.w CheckLeftWallDist … move.w y_vel(a0),ground_vel(a0) Player_HitCeiling:Checked by claude, 2026-10-26 — read SonicKnux_DoLevelCollision, Player_HitLeftWall, and loc_12102 at the pinned commit, s3.asm's Player_HitLeftWall, and Sonic 2's Sonic_HitLeftWall and Sonic_HitRightWall

s3.asm's Player_HitLeftWall is the same, so Sonic 3 alone changed this already.

Sonic's head sensors are read in the air only while he moves mostly up, left, or right. Inside a ceiling he moves down by the depth; moving up under a flat ceiling his Y speed becomes 0, moving sideways only if he was rising, and the floor isn't tested that frame. Moving mostly left, a head 20 px or more inside a ceiling is instead pushed off a wall on his right, a check Sonic 2 lacks. s3k/air-ceiling

About: Sonic 3 & Knuckles Hitbox

Value
{
 "tall": 20
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24211-L24240Player_HitCeiling: bsr.w sub_11FEE … neg.w d1 cmpi.w #$14,d1 bhs.s loc_12054 … add.w d1,y_pos(a0) tst.w y_vel(a0) … move.w #0,y_vel(a0) ; stop Sonic in y since he hit a ceiling … …skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24283-L24297bsr.w sub_11FEE … sub.w d1,y_pos(a0) … andi.b #$40,d0 bne.s loc_120EA move.w #0,y_vel(a0) ; stop Sonic in y since he hit a ceilingskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24321-L24335bsr.w sub_11FEE … sub.w d1,y_pos(a0) tst.w y_vel(a0) … move.w #0,y_vel(a0) … rtss2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38022-L38029Sonic_HitCeiling: bsr.w Sonic_CheckCeiling … sub.w d1,y_pos(a0) … move.w #0,y_vel(a0) ; stop Sonic in y since he hit a ceilingChecked by claude, 2026-10-26 — read Player_HitCeiling, Player_HitCeilingAndWalls, and loc_12102 at the pinned commit and Sonic 2's Sonic_HitCeiling

A ceiling block whose angle is steep lands him on it instead (loc_120EA); the lab's full block has the flat angle.

Falling mostly down, Sonic lands when a floor sensor is inside the ground unless both are deeper than his Y speed's whole pixels plus 8, and moves up by the deeper one's depth; moving mostly left or right and not rising, any depth lands him; rising, he doesn't land, except in a wind tunnel. s3k/landing-depth

About: Sonic 3 & Knuckles Jump

Value: 8 px

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24108-L24126bsr.w sub_11FD6 … bpl.s locret_11FD4 move.b y_vel(a0),d2 addq.b #8,d2 neg.b d2 cmp.b d2,d1 bge.s loc_11F6E cmp.b d2,d0 blt.s locret_11FD4 … add.w d1,y_pos(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24243-L24261loc_12068: … tst.w y_vel(a0) bmi.s locret_1209C … bsr.w sub_11FD6 … bpl.s locret_1209C … add.w d1,y_pos(a0) … move.w #0,y_vel(a0) …Checked by claude, 2026-10-26 — read SonicKnux_DoLevelCollision and loc_12068 at the pinned commit; sub_11FD6 returns the nearer sensor's distance in d1 and the other's in d0

The test compares bytes.

Standing on flat ground, not on an object, not Super or Hyper, with no move_lock or infinite-inertia flag, with ground speed 0 after the left and right steps, and the floor under his center 12 px or more below his feet, Sonic turns to face right if last frame's right floor sensor met no block, or else left if the left one met none, and balances; otherwise Down crouches. Sonic 2 turned him only if the floor 6 px back the other way was also that far down. s3k/balance

About: Sonic 3 & Knuckles Hitbox

Value: 12 px

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22480-L22490bne.w loc_112EA ; if yes, branch tst.w ground_vel(a0) ; is Sonic moving? … btst #Status_OnObj,status(a0) beq.w Sonic_Balanceskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22566-L22576Sonic_Balance: move.w x_pos(a0),d3 bsr.w ChooseChkFloorEdge cmpi.w #$C,d1 blt.w loc_11276 tst.b (Super_Sonic_Knux_flag).w ; is Sonic Super/Hyper? bne.w loc_11250 ; if so, branch cmpi.b #3,next_tilt(a0) bne.s loc_111F6 btst #Status_Facing,status(a0) bne.s loc_111CEskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22587-L22591loc_111CE: … bclr #Status_Facing,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22602-L22618loc_111F6: cmpi.b #3,tilt(a0) bne.s loc_11276 btst #Status_Facing,status(a0) beq.s loc_11228 … loc_11228: bset #Status_Facing,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22035-L22036move.b (Primary_Angle).w,next_tilt(a0) move.b (Secondary_Angle).w,tilt(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36717-L36724+ move.b #AniIDSonAni_Balance3,anim(a0) ; set Sonic's animation to "Balance3" … subq.w #6,d3 jsr (ChkFloorEdge_Part2).l cmpi.w #$C,d1 blt.w Obj01_ResetScr … bclr #status.player.x_flip,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22467-L22470tst.b status_secondary(a0) ; is bit 7 set? (Infinite inertia) bmi.w loc_11332 ; if so, branch tst.w move_lock(a0) bne.w loc_112EAskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L20343-L20347 — Sonic 3 alone's Sonic_Balance turns him before its 6 px check tooloc_1228A: … bclr #Status_Facing,status(a0)Checked by claude, 2026-10-26 — read Sonic_Move's first lines and standstill branch and Sonic_Balance at the pinned commit (facing right on a right edge he keeps facing right; facing left, `bclr` turns him), s3.asm's Sonic_Balance, and Sonic 2's Sonic_Balance

Player_AnglePos writes 3 to both angle buffers and a sensor that meets a block overwrites its own; Sonic_Control copies them to next_tilt and tilt. The edge check here runs on the frame's start position.

Cited by: Sonic 3 & Knuckles

Standing or rolling on flat ground with normal gravity, a jump press goes through only when the head sensors find 6 or more clear pixel rows above them; refused, the rest of the ground frame runs. On slopes and walls, and with reverse gravity, the sensors used turn with the angle. s3k/jump-headroom

About: Sonic 3 & Knuckles Jump

Value: 6 px

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23329-L23341tst.b (Reverse_gravity_flag).w … bsr.w CalcRoomOverHead … cmpi.w #6,d1 ; does Sonic have enough room to jump? blt.w locret_118B2 ; if not, branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19855-L19862move.b d0,(Primary_Angle).w move.b d0,(Secondary_Angle).w … cmpi.b #$80,d0 beq.w Sonic_CheckCeilingChecked by claude, 2026-10-26 — read Sonic_Jump and CalcRoomOverHead at the pinned commit

CalcRoomOverHead writes $80 to both angle buffers, which the balance check reads the next frame.

On the ground, while Background_collision_flag is clear, nothing but a jump press looks above Sonic: walking or rolling under a block that overlaps him, he stays on the ground. s3k/ground-no-ceiling

About: Sonic 3 & Knuckles Hitbox

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22328-L22337Sonic_MdNormal: bsr.w SonicKnux_Spindash bsr.w Sonic_Jump bsr.w Player_SlopeResist bsr.w Sonic_Move bsr.w SonicKnux_Roll bsr.w Player_LevelBound jsr (MoveSprite_TestGravity2).l bsr.w Call_Player_AnglePos bsr.w Player_SlopeRepelskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22402-L22411Sonic_MdRoll: tst.b spin_dash_flag(a0) bne.s loc_10FEA bsr.w Sonic_Jump loc_10FEA: bsr.w Player_RollRepel bsr.w Sonic_RollSpeed bsr.w Player_LevelBound jsr (MoveSprite_TestGravity2).lChecked by claude, 2026-10-26 — read Sonic_MdNormal and Sonic_MdRoll and the routines they call at the pinned commit; only Sonic_Jump calls CalcRoomOverHead, and the wall checks after Player_SlopeRepel run only with Background_collision_flag set, which Angel Island Act 1 leaves clear in the lab

Sonic dies once his Y position is more than 224 px below the level's bottom boundary, unless the level has set Disable_death_plane; with reverse gravity it is the top boundary instead. In Angel Island Act 1, run in MAME, every one of 18 falls into a pit killed him on the first frame after his center passed the boundary plus 224 px; the other branches are read in the code only. s3k/bottom-boundary

About: Sonic 3 & Knuckles Fall damage

Value: 224 px

Verifiedskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23207-L23243Player_LevelBound: … move.w (Camera_min_X_pos).w,d0 addi.w #$10,d0 … move.w (Camera_max_X_pos).w,d0 addi.w #$128,d0 … Player_Boundary_CheckBottom: tst.b (Disable_death_plane).w bne.s locret_11720 … …Checked by claude, 2026-10-26 — read Player_LevelBound at the pinned commit (`cmp.w y_pos(a0),d0` then `blt.s Player_Boundary_Bottom`: a death once y_pos exceeds Camera_max_Y_pos plus 224). The probe runs Sonic & Knuckles + Sonic The Hedgehog 3 (USA) in MAME 0.289 on the stages of stage-rule, built in Angel Island Act 1 with the bottom boundary held at `$300`; on 2026-10-26 18 of its cases ended in a fall into a pit, and each death came on the first frame after his center passed row 992 (`$300` + 224), the row the probe computes from the boundary it reads in RAM and this claim's 224Probe: probes/lab/s3k-conformance.mjs

It runs in every mode before the move, so the death comes the frame after his center passes the line. The same routine stops him at the camera's left limit plus 16 px and its right limit plus 296.

A frame-by-frame model of Sonic_MdNormal, Sonic_MdRoll, Sonic_MdJump, and SonicKnux_Spindash on flat ground, with the insta-shield, matches Sonic 3 & Knuckles itself, run in MAME with Sonic alone on a floor built of Angel Island Act 1's blocks, on every frame of the movement lab's flat-ground presets, stress scripts, and spin-dash and roll scripts and of 100 random input scripts. s3k/movement-rule

About: Sonic 3 & Knuckles Running

Value
{
 "ground": {
  "accel": 12,
  "friction": 12,
  "decel": 128,
  "top": 1536,
  "flip": 128
 },
 "roll": {
  "start": 256,
  "stop": 128,
  "friction": 6,
  "decel": 32,
  "flip": 128,
  "cap": 4096
 },
 "air": {
  "accel": 24,
  "top": 1536,
  "dragShift": 5,
  "dragFrom": -1024
 },
 "jump": {
  "speed": -1664,
  "releaseCap": -1024,
  "gravity": 56,
  "rollShift": 5
 },
 "spindash": {
  "charge": 512,
  "max": 2048,
  "decayShift": 5
 }
}
Verifiedskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22328-L22337 — the standing mode and its orderSonic_MdNormal: bsr.w SonicKnux_Spindash bsr.w Sonic_Jump bsr.w Player_SlopeResist bsr.w Sonic_Move bsr.w SonicKnux_Roll bsr.w Player_LevelBound jsr (MoveSprite_TestGravity2).l bsr.w Call_Player_AnglePos bsr.w Player_SlopeRepelskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22385-L22451 — Sonic_MdAir, Sonic_MdRoll, Sonic_MdJumpskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22463-L22951 — Sonic_Move with friction, the speeds from the ground speed, the wall ahead, and sub_113F6 and sub_11482skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22959-L23196 — Sonic_RollSpeed and its left and right steps, Sonic_ChgJumpDir with the air dragskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23258-L23438 — SonicKnux_Roll, Sonic_Jump, Sonic_JumpHeight, the start of Sonic_ShieldMovesskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23679-L23822 — SonicKnux_Spindashskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24075-L24160 — SonicKnux_DoLevelCollision's down branchskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24375-L24426 — Player_TouchFloorskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L36108-L36110 — MoveSprite_TestGravity is MoveSprite with normal gravityMoveSprite_TestGravity: tst.b (Reverse_gravity_flag).w beq.s MoveSpriteskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L1324-L1328 — Poll_Controller, a press per buttonmove.b (a0),d1 ; Get press button data eor.b d0,d1 ; Toggle off buttons that are being held move.b d0,(a0)+ ; Put raw controller input (for held buttons) in F604/F606 and.b d0,d1 move.b d1,(a0)+ ; Put pressed controller input in F605/F607skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22006move.w (Ctrl_1).w,(Ctrl_1_logical).w ; copy new held buttons, to enable joypad controlChecked by claude, 2026-10-26 — read the four mode routines, the spin dash, and every subroutine they call for flat ground, and Poll_Controller, at the pinned commit. The probe runs Sonic & Knuckles + Sonic The Hedgehog 3 (USA) in MAME 0.289 through the movement lab's ROM check (probes/lab/conformance.mjs): Angel Island Act 1 after its intro, Sonic alone (the save select's no-save slot with Sonic picked, no Tails object), the level's objects cleared every frame, Sonic placed standing on a 4096 px floor of the act's block 1, input written into the joypad bytes each game frame, and the model run on the same input. On 2026-10-26 it compared 140 scripts (23 presets, 9 stress scripts, 8 of the entry's own with spin dashes, a slow crouch, an unroll, and an insta-shield after a roll jump, and 100 random ones of 300 frames), 33,965 frames, on X and Y in 16.16, X, Y, and ground speed, airborne, curled, and facing, and all matched, on the first run of the model written from the codeProbe: probes/lab/s3k-conformance.mjs

One frame, out of water, g the ground speed and vx, vy the X and Y speeds in 1/256 px/frame, positions 16.16. Down is +y. A, B, or C going down this frame is a press, even with another held. Standing: crouching (animation 8), a press starts the spin dash, and while it charges each frame takes 1/32 of the counter and a press adds $200 (to $800); letting go of Down releases it (curl, Y + 5, g from spindash, negated facing left). These frames, and the start, don't move him. Otherwise a press sets vy −= $680, curls him (Y + 5) unless he is rolling (then the roll-jump flag), and ends the frame. Then Left, then Right: Left with g ≤ 0 faces left and takes $C, a speed past −$600 kept; Left with g > 0 takes $80 (to −$80 if it crosses), skidding (facing right) if the result's high byte is ≥ 4. Right mirrors it, skidding if the result with its low byte cleared is ≤ −$400. With g 0 after them: balance or, with Down, crouch. With neither held, friction $C toward 0. vx = g; with Down and neither Left nor Right, |g| ≥ $100 curls him into a roll (Y + 5), slower crouches. Rolling: Left or Right brake by $20 against the motion (to ∓$80 if it crosses), friction 6, then under $80 he stands up (Y − 5) with g kept; vx is g clamped to ±$1000. Then X += vx and the floor sensors snap him, or he walks off. Air: a jump rising faster than $400 with no button held is cut to −$400; once no faster, the first press clears the roll-jump flag (the insta-shield). Unless roll-jumping, Left and Right add $18 and face that way, a speed past $600 kept. If −$400 ≤ vy < 0, vx −= vx >> 5. X += vx, Y += vy, vy += $38; then the level checks, and landing makes g = vx, vy = 0, and uncurls him (Y − 5 unless roll-jumping). The values: ground-speeds, ground-friction, skid-threshold, roll-start, unroll, roll-speeds, air-keep-speed, air-drag-same, jump-speed, release-cap, gravity, takeoff, spindash, spindash-controls. Slopes, water, objects, and the camera are outside the model.

Cited by: Sonic the Hedgehog

On stages built in Angel Island Act 1 from the act's full 16 × 16 block, the movement lab's Sonic 3 & Knuckles model matches the game itself, run in MAME, on every frame of 100 random stages with random input scripts, three in four with floating blocks, and of the lab's stage presets, until a fall into a pit kills him at the bottom boundary or he nears the end of the built floor. s3k/stage-rule

About: Sonic 3 & Knuckles Hitbox

Value
{
 "stages": 100,
 "frames": 300
}
Verifiedskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L18764-L18900 — Player_AnglePos, Player_Angleskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19223-L19340 — FindFloorFindFloor: lea (Find_Tile_FG).l,a5 tst.b (Background_collision_flag).w beq.s sub_F264skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19509-L19700 — FindWallskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L19715-L19900 — sub_F61C, CalcRoomOverHead, Sonic_CheckFloorskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20016-L20030 — ChkFloorEdge_Part2skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20224-L20300 — CheckRightWallDist, Sonic_CheckCeilingskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L20541-L20555 — CheckLeftWallDistskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22566-L22650 — Sonic_Balanceskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24075-L24360 — SonicKnux_DoLevelCollision's four directionsskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L3075-L3133 — GetArcTan and its tableChecked by claude, 2026-10-26 — read the routines above at the pinned commit. The probe runs Sonic & Knuckles + Sonic The Hedgehog 3 (USA) in MAME 0.289 through the movement lab's ROM check (probes/lab/conformance.mjs, s3k-stage.mjs): each stage built in Angel Island Act 1's foreground rows 6 and 7 (y 768 to 1023, every other row emptied) from the act's block 1, after checking in RAM that block 1's collision index is s3k/collision-blocks' on both paths, the level's objects cleared every frame, Sonic placed standing at the stage's start, input written into the joypad bytes each game frame, and the model run on the same stage and input. The random stages are sonic-movement.mjs's (randomStages, seed 7), the ones Sonic the Hedgehog's check runs. On 2026-10-26 it compared 115 cases, 100 random stages of 300 frames and 15 stage-preset panes, 28,505 frames, on X and Y in 16.16, X, Y, and ground speed, airborne, curled, and facing, and all matched. 18 ended when the bottom boundary killed him (bottom-boundary); 3 stopped where he came within 48 px of the built floor's ends, x 0 and 4096Probe: probes/lab/s3k-conformance.mjs

The stages are Sonic the Hedgehog's layouts (s1disasm/stage-rule), so the two games' runs meet the same walls, ledges, and ceilings, and the camera's limits the probe writes each frame (left 0, right $4000, bottom $300) keep the level's own from moving.

On flat ground, Sonic 3 & Knuckles changes when Sonic rolls and stands: Down curls him only from $100, not Sonic 2's $80, and, off objects, crouches him while he is still moving slower, where Sonic 2 crouched only from a standstill; a roll stands up under $80 with that speed kept, where Sonic 2's rolls on to 0 (both outside pinball mode). In the air he keeps a speed above the top while steering, where Sonic 2 pulled him down to it; a second press after a roll jump gives back steering, which Sonic 2's jump never did; a wall push moving sideways no longer ends the frame's checks; and a head 20 px into a ceiling moving left is pushed off a right wall instead, a check Sonic 2 lacks. Standing over a drop, not Super, he turns toward it at once, where Sonic 2 turned only if the floor 6 px the other way was also low. s3k/movement-differs-from-sonic-the-hedgehog-2

About: Sonic 3 & Knuckles Running

Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23271-L23275 — roll-startcmpi.w #$100,d0 ; is Sonic moving at $100 speed or faster? bhs.s Player_ChkRoll ; if so, branch btst #Status_OnObj,status(a0) bne.s locret_1177E move.b #8,anim(a0) ; enter ducking animations2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37345-L37347mvabs.w inertia(a0),d0 cmpi.w #$80,d0 ; is Sonic moving at $80 speed or faster? blo.s Obj01_NoRoll ; if not, branchs2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36788-L36791 — Sonic 2 crouches only from Sonic_Move's standstill branchSonic_Duck: btst #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed? beq.s Obj01_ResetScr ; if not, branch move.b #AniIDSonAni_Duck,anim(a0) ; use "ducking" animationskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23012-L23016 — unrollcmpi.w #$80,d0 bhs.s loc_115C6 tst.b spin_dash_flag(a0) bne.s loc_115B4 bclr #Status_Roll,status(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37097-L37102Sonic_CheckRollStop: tst.w inertia(a0) bne.s Obj01_Roll_ResetScr … bclr #status.player.rolling,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23139-L23142 — air-keep-speedadd.w d5,d0 ; remove this frame's acceleration change cmp.w d1,d0 ; compare speed with top speed ble.s loc_11682 ; if speed was already greater than the maximum, branch move.w d1,d0s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37214-L37219sub.w d5,d0 ; add acceleration to the left move.w d6,d1 neg.w d1 cmp.w d1,d0 ; compare new speed with top speed bgt.s + ; if new speed is less than the maximum, branch move.w d1,d0 ; limit speed in air going left, even if Sonic was already going faster (speed limit/cap)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L23438 — insta-shield-motionbclr #Status_RollJump,status(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L37461-L37479 — Sonic 2's routine for the rise touches no roll-jump flag; landing clears it (roll-jump-lock)Sonic_JumpHeight: tst.b jumping(a0) ; is Sonic jumping? … move.w d1,y_vel(a0) ; immediately reduce Sonic's upward speed to d1 + tst.b y_vel(a0) ; is Sonic exactly at the height of his jump? beq.s Sonic_CheckGoSuper ; if yes, test for turning into Super Sonic rtsskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24207-L24212 — air-wall, falling through to the ceiling checksub.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall move.w y_vel(a0),ground_vel(a0) Player_HitCeiling: bsr.w sub_11FEEs2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38016-L38019sub.w d1,x_pos(a0) move.w #0,x_vel(a0) ; stop Sonic since he hit a wall move.w y_vel(a0),inertia(a0) rtsskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L24215-L24217 — air-ceilingneg.w d1 cmpi.w #$14,d1 bhs.s loc_12054s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L38022-L38029 — Sonic 2's ceiling check after a left wall, with no depth testSonic_HitCeiling: bsr.w Sonic_CheckCeiling … sub.w d1,y_pos(a0) … move.w #0,y_vel(a0) ; stop Sonic in y since he hit a ceilingskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L22587-L22591 — balanceloc_111CE: … bclr #Status_Facing,status(a0)s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm) · s2.asm#L36717-L36724+ move.b #AniIDSonAni_Balance3,anim(a0) ; set Sonic's animation to "Balance3" … subq.w #6,d3 … cmpi.w #$C,d1 blt.w Obj01_ResetScr … bclr #status.player.x_flip,status(a0)skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21730-L21743 — Sonic 3 alone's air wall falls through to the same ceiling check, with the 20 px rulebsr.w CheckLeftWallDist … move.w y_vel(a0),ground_vel(a0) Player_HitCeiling: … cmpi.w #$14,d1skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L21115 — and its shield press clears the roll-jump flagbclr #Status_RollJump,status(a0)Checked by claude, 2026-10-26 — compared Sonic 3 & Knuckles's Sonic_MdNormal, Sonic_MdRoll, Sonic_MdJump, and the routines they call for flat ground with Sonic 2's at both pinned commits (s2disasm at main's pin); the claims named in each note quote both sides in full

Rules that stayed, each in a claim that quotes Sonic 2's lines beside these: ground-speeds, ground-friction, skid-threshold, roll-speeds, spindash-controls, collision-box, walk-off, and roll-jump-size. Off flat ground there is more: a standing player slides on slopes (slope-standing) and slips rather than falls off steep ones (slope-slip). Sonic 3 alone (s3.asm) already has the air-wall and ceiling change (air-wall, and the s3.asm lines here), the insta-shield's unlock (roll-jump-lock), the turn on a ledge (balance), and the air steering (air-keep-speed), but keeps Sonic 2's roll start at $80, its unroll at 0, and its standstill-only crouch (roll-start, unroll).

Cited by: Sonic the Hedgehog, Sonic the Hedgehog 2

Built at the pinned commit with its own build scripts, as they stand (FixBugs = 0, Sonic 3 Complete off), skdisasm reproduces the No-Intro Sonic & Knuckles + Sonic The Hedgehog 3 (USA) ROM byte for byte: buildSK.lua (sonic3k.asm) gives its first 2 MB, the code the locked-on game runs, and buildS3.lua (s3.asm) its last 2 MB. s3k/rom-matches-build

Value
{
 "sk": "88d6499d874dcb5721ff58d76fe1b9af811192e3",
 "s3": "75e9c4705259d84112b3e697a6c00a0813d47d71"
}
Codeskdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · sonic3k.asm#L38FixBugs = 0skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · s3.asm#L25FixBugs = 0skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · buildSK.lua#L28common.build_rom_and_handle_failure("sonic3k", "skbuilt", "-D Sonic3_Complete=0",skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm) · buildS3.lua#L10common.build_rom_and_handle_failure("s3", "s3built", "",Sonic & Knuckles + Sonic The Hedgehog 3 (USA) · 0x0-0x3FFFFF — the whole file; the probe compares each build with its halfChecked by claude, 2026-10-26 — ran buildSK.lua and buildS3.lua on a git archive of the pinned commit (lua 5.4) and compared each build with its half of the ROM with cmp; read the four lines quotedProbe: probes/lab/s3k-build.mjs

So every s3k claim's code is what the cartridge holds, not a revision near it (contrast Sonic 2, s2disasm/rom-matches-revision-2). The MD5s the repository's chkbitperfect.lua expects of the two builds are these halves' (sonic-3-and-knuckles-genesis-rom).