Claim set · data/claims/mega-man-4.yaml

Mega Man 4 (plasticsmoke ca65 disassembly, and the Rev 1 ROM's bytes)

Game: Mega Man 4.

Mega Man 4 takes off at exactly 5 px/frame ($05.$00), up from Mega Man 3's $04.$E5, and a release cuts any rise to a speed of 0 where Mega Man 3 sets 0.25 px/frame downward. Both cut on every rising frame without A. mega-man-4/jump-line

About: Mega Man 4 Variable jump height

Value
{
 "takeoff": 1280,
 "afterRelease": 0
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L179-L190L_813E: LDA ent_angle ; player $04B0 flag BNE L_8149 ; nonzero: normal jump LDA joy1_held ; held buttons AND #$04 ; Down held? BNE L_8156 ; Down+A = slide L_8149: LDA #$00 ; zero sub-velocity STA ent_yvel_sub ; Y velocity sub = 0 LDA #$05 ; jump speed 5 px/frame STA ent_yvel ; Y velocity = +5 (up) JMP L_82C8 ; enter airborne physicsMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L420-L431L_8306: LDA ent_yvel ; player Y velocity BMI L_8338 ; moving down: keep falling LDA ent_var6 ; knockback/no-jump-cut flag BNE L_833D ; set: no jump cut LDA joy1_held ; held buttons AND #$80 ; A still held? BNE L_8338 ; held: full jump LDA #$00 ; zero STA ent_yvel_sub ; cut jump: Y vel sub = 0 STA ent_yvel ; cut jump: Y vel = 0 BEQ L_8338 ; (always taken)Mega Man 4 (USA) (Rev 1) · 0x78159-0x78165 — bank $3C $8149, the take-off in the Rev 1 ROMMega Man 4 (USA) (Rev 1) · 0x78322-0x7832E — bank $3C $8312, the cut in the Rev 1 ROMMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_ground.asm#L74-L77lda #$E5 ; normal jump: Y vel = $04.E5 sta ent_yvel_sub,x ; store Y velocity sub-pixel lda #$04 ; Y velocity whole = $04 sta ent_yvel,x ; store Y velocity wholeMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/movement.asm#L424-L427reset_gravity_player: lda #$C0 ; player rest vel sub = $C0 sta ent_yvel_sub,x ; store Y sub velocity lda #$FF ; player rest vel = $FF ($FFC0 = -0.25) sta ent_yvel,x ; store Y velocity whole byteChecked by claude, 2026-10-21 — read the ground state's A handler and the shared air physics in Mega Man 4, and Mega Man 3's jump start and reset_gravity (mega-man-3/release-cut), at their pinned commits; the Rev 1 bytes at the two offsets are the same instructions (A9 00 8D D8 03 A9 05 8D F0 03 4C …)

The check runs after the frame's move and gravity (JSR L_92C5 at L410), as in Mega Man 2. The ent_var6 flag skips the cut, as Mega Man 3's force_full_jump does.

Cited by: Jump, Mega Man 4, Variable jump height

Mega Man 4's slide keeps Mega Man 3's 2.5 px/frame but moves on 26 frames (a timer of $1A, counted after each move from the set-up frame on) where Mega Man 3's moves on 21 (a timer of 20). Its A test runs on every slide frame, the set-up's included: a fresh A press without Down jumps out whenever he has headroom, where Mega Man 3 waits for its 9th frame, and A with Down held keeps sliding. The set-up's own press comes with Down, and A held from it into the second frame is no fresh press, so the earliest jump out comes on the slide's 3rd frame. mega-man-4/slide-line

About: Mega Man 4 Ground slide

Value
{
 "speed": 640,
 "frames": 26,
 "jumpFromFrame": 3
}
VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L254 — the set-up runs the slide state's A test and move on the same frame, so the test runs from the slide's 1st frameJMP L_8368 ; post-slide-start processingMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L510-L516LDY #$04 ; speed selector 4 = slide JSR entity_horiz_dispatch ; move player horizontally BCS L_83C3 ; hit wall: try to stand LDA $34 ; slide timer BEQ L_83C3 ; expired: try to stand DEC $34 ; count down slide BNE L_83EF ; still sliding: doneMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L217-L226LDA #$1A ; slide duration 26 frames STA $34 ; set slide timer LDA #$02 ; state $02 = slide STA player_state ; enter slide state LDA #$80 ; slide speed 2.5 px/frame STA ent_xvel_sub ; X velocity sub = $80 STA $37 ; mirror in $37 LDA #$02 ; 2 px STA ent_xvel ; X velocity = 2 STA $38 ; mirror in $38Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L473-L496L_8368: LDA joy1_press ; newly pressed AND #$80 ; A button? BEQ L_839D ; no jump: steering LDA joy1_held ; held buttons AND #$04 ; Down held? BNE L_839D ; Down+A: stay sliding LDY #$03 ; probe 3 = standing headroom JSR tile_collision_detect ; check tile above head LDA $10 ; collision result BNE L_839D ; blocked: no jump JSR L_83F2 ; platform overhead check …Mega Man 4 (USA) (Rev 1) · 0x78194-0x781A7 — bank $3C $8184, the slide's set-up in the Rev 1 ROMMega Man 4 (USA) (Rev 1) · 0x78378-0x783AC — bank $3C $8368, the jump out of the slide in the Rev 1 ROMMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L288-L289lda #$14 ; slide timer = 20 frames sta $33 ; store slide timerMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L344-L348 — Mega Man 3 tests for 0 before decrementing, so its last move comes on the frame the timer is already 0 (mega-man-3/slide)slide_collision_wall_solid: lda $10 ; hit a wall? and #$10 ; bit 4 = solid wall bne slide_end_ground_check ; yes → end slide lda $33 ; timer expired? beq slide_end_ground_check ; yes → end slideMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L349-L355dec $33 ; decrement timer lda $33 ; check slide timer phase cmp #$0C ; >= $0C? (uncancellable phase) bcs slide_continue_moving ; yes → uncancellable, keep sliding lda joy1_press ; A button pressed? (cancellable phase) and #BTN_A ; check A button bne slide_end_ground_check ; yes → cancel into slide jumpChecked by claude, 2026-10-26 — read Mega Man 4's slide set-up and the slide state (state $02) from its A test through the timer and the standing test (L497-L524), and Mega Man 3's slide (mega-man-3/slide), at their pinned commits. Mega Man 4 decrements and ends on reaching 0 in the same frame (26 → 0 over 26 moves); Mega Man 3 moves once more on the frame it finds 0. Measured in Mesen (MesenCE 2.2.1) from power-on, at the start of Skull Man's stage on flat floor: a slide moved 2.5 px on each of 26 frames and stood him up on the 26th; A held from the set-up into the 2nd frame didn't jump, a press on the 3rd frame did, and Down with A held for 60 frames never jumpedProbe: probes/jump-physics/movement.mjs

As in Mega Man 3, a turn ends the slide (L504-L508) and a ceiling over his head keeps it going past the timer (L518-L524). This claim's value used to say the jump out comes "from frame 2", the first frame after the set-up; mega-man-5/slide-kept's "frame 1" counts the set-up frame, where the test first runs. Both describe the same code, and neither frame can carry a fresh press without Down, so the earliest jump out in either count is the 3rd frame.

Cited by: Ground slide, Mega Man 4

A B press fires a normal shot and sets the charge counter to 1; each frame B stays held in a state below 4 the counter rises by 1, looping from 100 back to 92. On release, a counter under 32 ($20) fires nothing more, 32 or more fires a half-charged shot, and 92 ($5C) or more a full one. mega-man-4/charge-shot

About: Mega Man 4 Charge shot

Value
{
 "half": 32,
 "full": 92
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L73-L95L_8073: LDA $35 ; charge counter BEQ L_80CF ; not charging: done LDA player_state ; player state CMP #$04 ; states >= 4 (Rush riding etc.) BCS L_80CF ; cannot charge: done LDA joy1_held ; held buttons AND #$40 ; B button still held? BEQ L_80CF ; released: fire handled at L_8CCC INC $35 ; advance charge … LDA $35 ; reload charge …Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L1694-L1722LDA $35 ; charge counter BEQ L_8D2F ; no charge: check B press LDA current_weapon ; current weapon BNE L_8D2F ; not buster: check B press LDA joy1_held ; held buttons AND #$40 ; B still held? BNE L_8D59 ; still charging: no fire LDA #$21 ; charged spawn offset $21 STA $11 ; set spawn-offset index … CMP #$20 ; level 1 threshold ($20) BCC L_8D59 ; tap shot: normal spawn …Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L1743-L1751L_8D2F: LDA joy1_press ; newly pressed AND #$40 ; B button? BEQ L_8D5B ; no fire: done L_8D35: LDY #$00 ; slot 0 marker STY temp_00 ; clear chosen-slot temp INY ; Y = 1 STY $35 ; minimum charge (tap)Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L1769-L1772L_8D59: LDA #$00 ; A = 0 (no shot fired) L_8D5B: RTS ; doneMega Man 4 (USA) (Rev 1) · 0x78083-0x780AE — bank $3C $8073, the counter in the Rev 1 ROMMega Man 4 (USA) (Rev 1) · 0x78D02-0x78D0F — bank $3C $8CF2, the thresholds in the Rev 1 ROMChecked by claude, 2026-10-21 — read the charge counter in the per-frame update and the Mega Buster's handler (L_8CCC) from the release test to the shot at the pinned commit. Both charged paths reach L_8D35 and fire with spawn offset `$21`, or `$20` for the full charge; under `$20` the release branches to L_8D59, which returns without a shot. The `$40` test only picks the flash colors

Charging runs only with the Mega Buster selected (L49-L51). The counter starts at 1, so the half charge comes 31 held frames after the press and the full one 91, if every frame counts; not yet measured.

Cited by: Charge shot, Mega Man 2, Mega Man 4

Mega Man 4 keeps Mega Man 3's knockback, 0.5 px/frame ($00.$80) against his facing under gravity until the hurt animation reaches 9, with no push when the hit lands during a slide. mega-man-4/knockback

About: Mega Man 4 Knockback

Value
{
 "back": 128
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L801-L811LDY ent_var5 ; knockback probe selector JSR entity_player_collide ; ride/collide with platforms LDA #$80 ; knockback speed 0.5 px/frame STA ent_xvel_sub ; X velocity sub LDA #$00 ; zero STA ent_xvel ; X velocity px LDA ent_flags ; player flags PHA ; save (facing) LDA ent_hp ; hurt sub-state CMP #$02 ; $02 = was sliding BEQ L_8616 ; sliding: skip pushbackMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L830-L832LDA ent_anim_phase ; player anim counter CMP #$09 ; knockback anim done (frame 9)? BNE L_865B ; not yet: keep flying backMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L776-L786player_knockback_physics: lda $3E ; check saved OAM for special cases: cmp #$10 ; $10 = sliding (no knockback physics) beq player_knockback_landing ; sliding → skip knockback … lda #$80 ; knockback speed = $00.80 (half pixel/frame) sta ent_xvel_sub ; set knockback X speed sub lda #$00 ; knockback X speed whole = 0 sta ent_xvel ; x_speed whole = 0Checked by claude, 2026-10-21 — read the hurt state ($06) in Mega Man 4 and player_damage in Mega Man 3 (mega-man-3/knockback) at their pinned commits

Both set a 60 ($3C) countdown when the hurt state ends (Mega Man 4 L833-L835); the atlas has checked in Mega Man 3 only that it gates damage.

Cited by: Knockback, Mega Man 4

One routine, entity_player_collide, moves Mega Man vertically in every state: by the sign of his speed's whole byte it moves him down or up by the speed (8.8 fixed point, positive up), takes gravity off the speed, and only then tests the floor points under a fall or the ceiling points over a rise. The ground, air, and slide states all run it before their horizontal move, so a frame's floor and ceiling tests use the X the frame started with and its wall test the new Y. mega-man-4/motion-order

About: Mega Man 4 Jump physics

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L321-L331L_F174: LDA ent_yvel,X ; load vert velocity pixel BMI L_F17C ; negative -> moving down (falling) JMP L_F1FD ; positive/zero -> moving up (rising) ; --------------------------------------------------------------------------- ; player falling (vert velocity negative = downward in screen coords) ; --------------------------------------------------------------------------- L_F17C: JSR L_F2B8 ; apply downward vert velocityMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L365-L367L_F1B0: JSR L_F2F6 ; apply gravity (accelerate downward) JSR tile_collision_detect ; check tile collisionMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L410-L412L_F1FD: INY ; increment screen offset JSR L_F2D8 ; apply upward vert velocityMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L429-L431L_F219: JSR L_F2F6 ; apply gravity (accelerate downward) JSR tile_collision_detect ; check tile collisionMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L171-L172 — the ground state runs the air routine (L_82C8) before its own A test and walkJSR L_82C8 ; shared physics; carry = grounded BCC L_80F9 ; airborne: done for this frameMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L387-L390L_82C8: LDY #$00 ; probe selector 0 STY $A4 ; clear wind-tile flag JSR entity_player_collide ; ride/collide with platformsMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L447-L453 — the air routine's horizontal move comes after entity_player_collideL_833D: LDA joy1_held ; held buttons AND #$03 ; L/R bits STA ent_dir ; air control: face held dir STA $31 ; store direction LDY #$00 ; speed selector 0 = walk JSR entity_horiz_dispatch ; move horizontally in airMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L464-L467LDY #$04 ; probe selector 4 (slide height) JSR entity_player_collide ; ride/collide with platforms JSR L_92C5 ; environment + ground check BCS L_8368 ; still grounded: continue slideChecked by claude, 2026-10-26 — read entity_player_collide's dispatch, both branches, and the movers L_F2B8 and L_F2D8 at the pinned commit, and the three player states that call it (ground $8130, air $82C8, slide $8353)

Mega Man 2 runs the horizontal move first in each state (mega-man-2/collision-order). A speed of exactly 0 counts as rising, so the frame after a release cut (jump-line) moves 0 and tests the ceiling.

Gravity takes $40/256 = 0.25 px/frame from Mega Man's upward speed every frame; the stage start writes $40 to gravity ($99). mega-man-4/gravity

About: Mega Man 4 Jump physics

Value: 64 1/256 px/frame²

VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_game_loop.asm#L76-L77LDA #$40 ; normal gravity ($15 underwater) STA gravity ; set gravity accelerationMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L622-L629L_F302: LDA ent_yvel_sub,X ; load vert velocity sub-pixel SEC ; prepare subtraction SBC gravity ; subtract gravity acceleration STA ent_yvel_sub,X ; store updated sub-pixel LDA ent_yvel,X ; load vert velocity pixel SBC #$00 ; subtract borrow STA ent_yvel,X ; store updated pixelChecked by claude, 2026-10-26 — read the stage init (L_C541) and the gravity routine L_F2F6 at the pinned commit. Measured in Mesen (MesenCE 2.2.1) from power-on, standing where Mega Man lands at the start of Skull Man's stage, a held jump's speed fell by `$40` every frame from `$04`.`$C0` to the landingProbe: probes/jump-physics/movement.mjs

Water doesn't change the value for the player: a water timer ($43, set to 3 on entering water) skips gravity for its first frames (L616-L621). The $15 in the stage start's comment is written only by a water enemy's own routine (bank3B L_A870), which puts $40 back after its move.

When gravity takes Mega Man's speed below -7 px/frame (its whole byte under $F9), the gravity routine sets it to exactly $F9.$00, so he falls at most 7 px a frame. mega-man-4/fall-cap

About: Mega Man 4 Jump physics

Value: -1792 1/256 px/frame

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L630-L636BPL L_F323 ; positive (rising) -> done CMP #$F9 ; below terminal velocity ($F9)? BCS L_F323 ; no -> done (already capped) LDA #$F9 ; terminal velocity pixel STA ent_yvel,X ; clamp to $F9 LDA #$00 ; zero sub-pixel STA ent_yvel_sub,X ; clear sub-pixel velocityMega Man 4 (USA) (Rev 1) · 0x7F323-0x7F332 — fixed bank $F313, the clamp in the Rev 1 ROMChecked by claude, 2026-10-26 — read L_F2F6 at the pinned commit: after the subtraction a negative whole byte below `$F9` is replaced by `$F9` and the fraction zeroed; the Rev 1 bytes at the offset are the same instructions

Mega Man 3 also caps at $F9 (mega-man-3/jump-line), and Mega Man 2 at 12 px/frame (mega-man-2/max-fall). Mega Man 6 stops only the whole byte, so its fall creeps past 7 (mega-man-6/fall-limits). Mega Man 4's fall reaches the cap 24 frames after a fall from rest begins at −1 px/frame (computed).

On the ground Mega Man's vertical speed rests at -1 px/frame ($FF.$00), which every landing and every floor contact sets through entity_stop_y. So each grounded frame moves him 1 px down, takes gravity, and tests his floor points one row lower; ground there puts him back on it at the same speed, and none leaves him in the air, falling at 1.25 px/frame from the next frame. mega-man-4/ground-check

About: Mega Man 4 Jump physics

Value: -256 1/256 px/frame

VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L648-L652L_F324: LDA #$00 ; zero STA ent_yvel_sub,X ; clear vert velocity sub-pixel LDA #$FF ; $FF = stopped / minimal STA ent_yvel,X ; set vert velocity pixelMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L399-L404L_F1F5: JSR L_D9E7 ; push entity Y up onto floor tile JSR entity_stop_y ; stop vertical velocity L_F1FB: SEC ; set carry = collision RTS ; returnMega Man 4 (USA) (Rev 1) · 0x7F334-0x7F33D — fixed bank $F324, entity_stop_y in the Rev 1 ROMChecked by claude, 2026-10-26 — read entity_stop_y and the falling branch of entity_player_collide at the pinned commit. Measured in Mesen (MesenCE 2.2.1) from power-on, standing and walking where Mega Man lands at the start of Skull Man's stage, the speed read `$FF`.`$00` on every grounded frame and his Y didn't changeProbe: probes/jump-physics/movement.mjs

Mega Man 3 rests at $FF.$C0 (-0.25 px/frame, mega-man-3/release-cut) and Mega Man 2 at -0.25 too (mega-man-2/ground-check). In Mega Man 4 the same $FF00 rests every entity (mega-man-code-lineage/mm3-mm4-plain-movers).

When a falling Mega Man's floor points find a solid tile, align_down subtracts the tested row's depth into its 16 px tile from his Y pixel, which puts the points on the tile's top row and his feet on its top, and keeps the Y fraction; the speed goes back to -1 px/frame. A fall of up to 7 px a frame always ends on the top of the tile it reaches. mega-man-4/floor-snap

About: Mega Man 4 Jump physics

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_tile_collision.asm#L1973-L1981L_D9E7: LDA $11 ; load collision Y pixel position PHA ; save original for restoration AND #$0F ; mask to within-tile offset STA $11 ; store offset temporarily LDA ent_y_px,X ; load entity Y pixel position SEC ; prepare subtraction SBC $11 ; subtract within-tile offset STA ent_y_px,X ; store adjusted positionMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L399-L401L_F1F5: JSR L_D9E7 ; push entity Y up onto floor tile JSR entity_stop_y ; stop vertical velocityChecked by claude, 2026-10-26 — read align_down ($D9E7) and its caller in entity_player_collide's falling branch at the pinned commit

Mega Man 2 zeroes the Y fraction on landing (mega-man-2/floor-snap); Mega Man 4 keeps it, so a jump's fraction carries into the next one. From flat ground every jump lands with fraction 0, since 5 px/frame and 0.25 px/frame² leave a whole number at each landing (computed).

Mega Man's position is his center. Standing, walking, and in the air his floor points are 12 px below it at x-7, x, and x+7; his ceiling points 9 px above it at x-7 and x+7; and his wall points 8 px to the side he moves toward, at 8 px above, level with, and 11 px below his center. mega-man-4/terrain-box

About: Mega Man 4 Jump physics

Value
{
 "floor": {
  "dy": 12,
  "dx": [
   -7,
   0,
   7
  ]
 },
 "ceiling": {
  "dy": -9,
  "dx": [
   -7,
   7
  ]
 },
 "wall": {
  "dx": 8,
  "dy": [
   -8,
   0,
   11
  ]
 }
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_tile_collision.asm#L625-L631 — tile_collision_detect picks shape Y from the tables at $D69E and $D6DE; the floor test passes Y = 0, the ceiling test 1 (entity_player_collide's INY)L_D2FC: JSR L_D53A ; save bank state, load stage bank JSR L_D552 ; apply scroll offset to entity position LDA $D69E,Y ; get collision shape pointer low byte STA $5A ; store shape pointer low LDA $D6DE,Y ; get collision shape pointer high byte STA $5B ; store shape pointer highMega Man 4 (USA) (Rev 1) · 0x7D6AE-0x7D6B3 — $D69E-$D6A3, the low bytes of shapes 0-5: $1E $23 $27 $2A $2F $34Mega Man 4 (USA) (Rev 1) · 0x7D6EE-0x7D6F3 — $D6DE-$D6E3, their high bytes, all $D7Mega Man 4 (USA) (Rev 1) · 0x7D72E-0x7D748 — $D71E-$D738, shapes 0-5, each a point count less 1, the Y offset, the first X offset, and the X steps: shape 0 is 02 0C F9 07 07 (three points 12 px down, from x-7 in steps of 7), shape 1 is 01 F7 F9 0E (two points 9 px up, x-7 and x+7)Mega Man 4 (USA) (Rev 1) · 0x7D818-0x7D81F — $D808-$D80F, the low bytes of the wall shapes 0-7 ($D848-$D84F holds their high bytes, all $D8)Mega Man 4 (USA) (Rev 1) · 0x7D898-0x7D8B4 — $D888-$D8A4, wall shapes 0-7, each a point count less 1, the X offset, the first Y offset, and the Y steps: shape 0 (right) is 02 08 F8 08 0B, three points 8 px right at 8 up, level, and 11 down; shape 1 (left) is 02 F8 F8 08 0BChecked by claude, 2026-10-26 — read tile_collision_detect and scroll_collision_check at the pinned commit for the shape format, and the pointer tables and shapes as bytes in the Rev 1 ROM; the ground and air states pass Y = 0 (L_82C8, L388), entity_horiz_dispatch adds 1 for a move left

With the floor points on the row under his feet, the wall points cover the 20 rows from his feet up and the ceiling points sit on the 21st; Mega Man 2 tests 24 rows (mega-man-2/terrain-box). Each test ORs the types of its points, and bit 4 of a type is solid.

When the horizontal move puts a wall point in a solid tile, the move routine pushes Mega Man back by the point's depth into that 16 px tile, so x+8 ends on the wall's first column moving right and x-8 on the first column past it moving left; the X fraction, his speed, and his pose stay, so he walks in place against it. mega-man-4/wall-stop

About: Mega Man 4 Jump physics

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_tile_collision.asm#L1905-L1916L_D99E: .byte $05,$A5 ; shape data / overlap byte .byte $12 ; (entry at $D99F is: LDA $12) AND #$0F ; mask to within-tile offset STA $12 ; store within-tile offset LDA ent_x_px,X ; load entity X pixel SEC ; prepare subtraction SBC $12 ; subtract within-tile offset STA ent_x_px,X ; store adjusted X pixel LDA ent_x_screen,X ; load entity screen index SBC #$00 ; subtract borrow from sub-pixel STA ent_x_screen,X ; store adjusted screenMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_tile_collision.asm#L1928-L1937L_D9B7: LDA $12 ; load collision X pixel position AND #$0F ; mask to within-tile offset EOR #$0F ; complement (distance to boundary) SEC ; set carry for +1 in ADC ADC ent_x_px,X ; add to entity X pixel STA ent_x_px,X ; store adjusted X pixel LDA ent_x_screen,X ; load entity screen index ADC #$00 ; add carry (screen overflow) STA ent_x_screen,X ; store adjusted screenMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L125-L131L_F079: JSR scroll_collision_check ; check collision with scroll bounds CLC ; default: no collision LDA $10 ; load collision result AND #$10 ; test solid-tile bit BEQ L_F087 ; not solid -> return JSR L_D9B7 ; push entity X right out of wallChecked by claude, 2026-10-26 — read entity_move_right and entity_move_left with their wall tests (L_F032, L_F079) and align_right/align_left at the pinned commit

Mega Man 2 also zeroes the X fraction at a wall (mega-man-2/wall-stop). A slide tests its own wall points (slide-box).

Because the ground state tests the floor before it moves him, Mega Man walks one frame past the edge before he falls: the frame whose move takes all three floor points off a ledge still counts as grounded, and on the next the floor test finds nothing after a 1 px drop, so he leaves the ground falling 1.25 px/frame and that frame moves him by the air's rules. His feet are then 1, 2, 3, 5, 7, and 9 px below the ledge on that frame and the five after (computed). mega-man-4/walk-off

About: Mega Man 4 Coyote time

Value
{
 "heights": [
  1,
  2,
  3,
  5,
  7,
  9
 ],
 "v": -320
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L171-L172JSR L_82C8 ; shared physics; carry = grounded BCC L_80F9 ; airborne: done for this frameMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L410-L419JSR L_92C5 ; environment + ground check BCS L_8320 ; on ground: landing handling LDA #$07 ; sub-type $07 = falling CMP ent_sub_type ; already falling sprite? BEQ L_8306 ; yes: skip set CLC ; prepare add ADC $33 ; + shoot-pose offset JSR entity_set_subtype ; set falling sprite LDA #$01 ; state $01 = airborne STA player_state ; now airborneMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L365-L367L_F1B0: JSR L_F2F6 ; apply gravity (accelerate downward) JSR tile_collision_detect ; check tile collisionChecked by claude, 2026-10-26 — read the ground state's entry and the air routine L_82C8 to L_8352 at the pinned commit; the heights come from the rest speed, gravity, and the move-then-gravity order (ground-check, gravity, motion-order), with the start's Y fraction of 0

The heights are the model's (src/widgets/platformer/mega-man-4.model.ts); the atlas hasn't measured a walk-off in the cartridge.

Mega Man 4 gives no grace jump off a ledge. The ground state reads A only after the air routine reports him standing, and the air state never reads it, so a press on the frame the floor test first fails, or on any later frame of the fall, doesn't jump. mega-man-4/no-coyote-time

About: Mega Man 4 Coyote time

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L171-L175JSR L_82C8 ; shared physics; carry = grounded BCC L_80F9 ; airborne: done for this frame LDA joy1_press ; newly pressed buttons AND #$80 ; A button (jump)? BNE L_813E ; pressed: jump/slide startMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L447-L458L_833D: LDA joy1_held ; held buttons AND #$03 ; L/R bits STA ent_dir ; air control: face held dir STA $31 ; store direction LDY #$00 ; speed selector 0 = walk JSR entity_horiz_dispatch ; move horizontally in air JSR L_8CBD ; per-weapon handler dispatch JSR L_922B ; Up held: grab ladder CLC ; carry clear = airborne L_8352: RTS ; doneChecked by claude, 2026-10-26 — read the ground state's entry and the air state ($82C8) through its return at the pinned commit; neither path of the air state tests joy1_press

A press on the frame whose move carries him off the edge still jumps, because that frame's floor test ran before the move (walk-off).

When a rising Mega Man's move puts a ceiling point, x-7 or x+7 at 9 px above his center, in a solid tile, entity_align_to_tile adds 16 minus the point's depth into the tile to his Y pixel, which puts the point on the row under the tile, and entity_stop_y sets his speed to -1 px/frame; he stays in the air and falls from the next frame. mega-man-4/ceiling-hit

About: Mega Man 4 Jump physics

Value: -256 1/256 px/frame

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L429-L437L_F219: JSR L_F2F6 ; apply gravity (accelerate downward) JSR tile_collision_detect ; check tile collision LDA $10 ; load collision result AND #$10 ; test solid-tile bit BEQ L_F22B ; not solid -> return no collision JSR entity_align_to_tile ; push entity Y down out of ceiling L_F228: JSR entity_stop_y ; stop vertical velocityMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_tile_collision.asm#L1949-L1955L_D9CD: LDA $11 ; load collision Y pixel position AND #$0F ; mask to within-tile offset EOR #$0F ; complement (distance to boundary) SEC ; set carry for +1 in ADC ADC ent_y_px,X ; add to entity Y pixel position STA ent_y_px,X ; store adjusted positionChecked by claude, 2026-10-26 — read the rising branch of entity_player_collide (L_F1FD to L_F22B) and entity_align_to_tile ($D9CD) at the pinned commit

The rising branch returns carry clear even after a hit, so the air routine runs on: the release test sees a falling speed and skips the cut, and the frame's horizontal move follows. Mega Man 2 instead leaves the speed at -0.25 after a hit (mega-man-2/ceiling-hit).

Nothing tests the ceiling before a jump starts: a fresh A press on the ground sets the jump speed and runs the air routine, whose rise is the first test. On tile floor the lowest ceiling he can walk under is 32 px up, 11 px over his ceiling points, so a jump there rises 5 px and then 4.75 px on its first two frames and meets the block on the 3rd, which turns it into a fall. mega-man-4/jump-under-ceiling

About: Mega Man 4 Jump physics

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L179-L190L_813E: LDA ent_angle ; player $04B0 flag BNE L_8149 ; nonzero: normal jump LDA joy1_held ; held buttons AND #$04 ; Down held? BNE L_8156 ; Down+A = slide L_8149: LDA #$00 ; zero sub-velocity STA ent_yvel_sub ; Y velocity sub = 0 LDA #$05 ; jump speed 5 px/frame STA ent_yvel ; Y velocity = +5 (up) JMP L_82C8 ; enter airborne physicsChecked by claude, 2026-10-26 — read the ground state's A handler at the pinned commit, and stepped the lab model under a ceiling 32 px up (src/widgets/platformer/mega-man-4.ceiling.test.ts)

A block whose bottom is 16 px over the floor stops him with its wall points (terrain-box), so a ceiling 32 px up is the lowest he walks under; there the press frame lifts his ceiling points to 26 px and the second to 30.75, and the third frame's rise meets it. Only off the tile grid, on a platform entity, could the press frame itself meet a ceiling.

A jump moves Mega Man on its press frame. The ground state has already run the air routine and found the floor; the A press sets 5 px/frame and runs the air routine again, which lifts him 5 px and moves him by the air's rules, so the ground's own walk doesn't run that frame. Measured in Mesen from power-on, standing where he lands at the start of Skull Man's stage, a jump's first frame raised his Y by exactly 5 px. mega-man-4/takeoff

About: Mega Man 4 Variable jump height

Value
{
 "rise": 5,
 "peak": 52.5,
 "peakFrame": 20,
 "airFrames": 40
}
VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L179-L190L_813E: LDA ent_angle ; player $04B0 flag BNE L_8149 ; nonzero: normal jump LDA joy1_held ; held buttons AND #$04 ; Down held? BNE L_8156 ; Down+A = slide L_8149: LDA #$00 ; zero sub-velocity STA ent_yvel_sub ; Y velocity sub = 0 LDA #$05 ; jump speed 5 px/frame STA ent_yvel ; Y velocity = +5 (up) JMP L_82C8 ; enter airborne physicsMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L171-L176JSR L_82C8 ; shared physics; carry = grounded BCC L_80F9 ; airborne: done for this frame LDA joy1_press ; newly pressed buttons AND #$80 ; A button (jump)? BNE L_813E ; pressed: jump/slide start JMP L_81D6 ; no jump: ground movementChecked by claude, 2026-10-26 — read the ground state's entry and A handler at the pinned commit. Measured in Mesen (MesenCE 2.2.1) from power-on at the start of Skull Man's stage, a jump with A held rose 5 px on its first frame, 52.5 px by frame 20, and landed on frame 41 after 40 frames in the airProbe: probes/jump-physics/movement.mjs

Mega Man 2 sets its speed on the press frame but moves him from the next (mega-man-2/jump-start). The held jump's height is 21 × 5 − 0.25 × 210 = 52.5 px (computed from jump-line and gravity).

Mega Man walks and moves through the air at the speed held in his X speed (ent_xvel), 1.30 px/frame ($01.$4C) on ordinary floor; no walking or air code sets it. The slide writes 2.5 px/frame there, and its end and the jump out of it write $01.$4C back. Measured in Mesen from power-on, at the start of Skull Man's stage, the X speed read $01.$4C and each walking frame moved him 332/256 px. mega-man-4/walk-speed

About: Mega Man 4 Running

Value: 332 1/256 px/frame

VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L325-L331L_825D: LDA $31 ; walk direction STA ent_dir ; face walk direction JSR L_93DB ; wind vs walk adjust (stage $08) BCC L_826C ; wind overrides: skip move LDY #$00 ; speed selector 0 = walk JSR entity_horiz_dispatch ; move player horizontallyMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L793-L800L_F3ED: CLC ; clear carry (default: no collision) LDA ent_dir,X ; load direction byte AND #$03 ; mask horiz direction bits (0-1) BEQ L_F445 ; no direction -> return AND #$01 ; test bit 0 (right?) BEQ L_F3FC ; no -> move left JMP entity_move_right ; move entity rightMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L525-L533L_83D3: LDA #$00 ; state $00 = ground STA player_state ; stand up LDA #$4C ; walk speed 1.30 px/frame STA ent_xvel_sub ; X velocity sub STA $37 ; mirror in $37 LDA #$01 ; 1 px STA ent_xvel ; X velocity STA $38 ; mirror in $38Checked by claude, 2026-10-26 — read the walk (L_825D), the air move (L_833D), entity_horiz_dispatch, and every write to ent_xvel in bank $3C at the pinned commit; outside the slide, the hurt state, and the wind and quicksand code of stages $01, $03, and $08, only `$01`.`$4C` is written. Measured in Mesen (MesenCE 2.2.1) from power-on at the start of Skull Man's stageProbe: probes/jump-physics/movement.mjs

332/256 = 1.296875 px/frame, Mega Man 3's walking speed too (mega-man-3/walk-speed).

On the ground Mega Man's sprite sub-type decides whether he moves. Standing ($01), a held direction sets the pause pose ($0D) and moves him one frame; in the pause pose he doesn't move until its animation advances, and then walks ($04) toward a held direction, or stands with none. Walking, the same direction keeps him moving; letting go puts him in the pause pose without a move, and the other direction does too, with one frame's move the new way. mega-man-4/ground-states

About: Mega Man 4 Running

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L286-L324L_8214: LDA ent_sub_type ; player sub-type … L_822B: LDA ent_anim_phase ; player anim counter BEQ L_82A6 ; anim step done: idle … L_8243: LDA joy1_held ; held buttons AND #$03 ; L/R held? BEQ L_8292 ; none: stop walking AND $31 ; same as current direction? …Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L880-L884L_F446: STA ent_sub_type,X ; set entity sub-type LDA #$00 ; zero STA ent_anim_phase,X ; clear animation counter STA ent_var3,X ; clear variable 3Checked by claude, 2026-10-26 — read the ground state's walk (L_820C to L_82A6) and entity_set_subtype at the pinned commit; $31 holds the walk direction, and setting a sub-type zeroes its animation phase

Sub-types $05, $0E, and $0F are the same poses with the shot's offset added ($33), and the code treats them alike. A press of A or Down+A on the ground is handled before any of this, in any pose.

The pause pose lasts 6 frames: its animation (sub-type $0D in bank $0D) holds its first frame for 6 animation ticks, one a frame. So from standing, or on a turn, a held direction moves Mega Man on the first frame, holds him still on the next 5, and walks from the 7th; letting go of a walk holds him for 6 frames, whatever the d-pad does, before he stands or walks on. Measured in Mesen from power-on, at the start of Skull Man's stage, Right moved him on frame 1, not on frames 2 to 6, and on every frame from 7 to 40; letting go on frame 41 kept him still in the pause pose on frames 41 to 46, and he stood from frame 47. mega-man-4/ground-measured

About: Mega Man 4 Running

Value
{
 "pauseFrames": 6
}
VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_core.asm#L295-L306LDA ent_var3,X ; load animation sub-frame counter AND #$7F ; mask off bit 7 for counter value INC ent_var3,X ; increment raw sub-frame counter INY ; Y = 1 (index to frame duration in AI data) CMP (temp_00),Y ; compare sub-frame to duration threshold BNE L_DCE2 ; if not equal, sub-frame not done yet LDA ent_var3,X ; reload sub-frame counter AND #$80 ; preserve only bit 7 (phase flag) STA ent_var3,X ; reset counter, keep phase flag LDA ent_anim_phase,X ; load animation phase counter AND #$7F ; mask off bit 7 for phase index INC ent_anim_phase,X ; increment raw animation phase counterMega Man 4 (USA) (Rev 1) · 0x1A717-0x1A718 — bank $0D $A707-$A708, the start of sub-type $0D's animation: 1 frame (the loop count), and 5, the counter value that advances itChecked by claude, 2026-10-26 — read the animation tick in the fixed bank (the sub-frame counter ent_var3 advances the phase when it reaches the descriptor's second byte, so after 6 ticks) and the descriptor sub-type `$0D` reads through `$BE0D`/`$BF0D` in bank `$0D`, which `$DFFA` maps for the player. Measured in Mesen (MesenCE 2.2.1) from power-on at the start of Skull Man's stage, with the animation phase read each frameProbe: probes/jump-physics/movement.mjs

Mega Man 6 holds a 5-frame halt after the first step too (mega-man-6/walk-start), from a counter, not an animation.

Every frame in the air the d-pad alone sets where Mega Man moves: the air routine copies the held Left or Right into his direction and moves him by his X speed that way, 1.30 px/frame, and with neither held he doesn't move. He turns at once, and nothing carries over from the ground. mega-man-4/air-speed

About: Mega Man 4 Air control

CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L447-L453L_833D: LDA joy1_held ; held buttons AND #$03 ; L/R bits STA ent_dir ; air control: face held dir STA $31 ; store direction LDY #$00 ; speed selector 0 = walk JSR entity_horiz_dispatch ; move horizontally in airMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L793-L800L_F3ED: CLC ; clear carry (default: no collision) LDA ent_dir,X ; load direction byte AND #$03 ; mask horiz direction bits (0-1) BEQ L_F445 ; no direction -> return AND #$01 ; test bit 0 (right?) BEQ L_F3FC ; no -> move left JMP entity_move_right ; move entity rightChecked by claude, 2026-10-26 — read L_833D and entity_horiz_dispatch at the pinned commit

Mega Man 2 sets a separate air speed, 1.3125 px/frame (mega-man-2/air-speed).

The frame a falling Mega Man's floor test finds ground puts him in the ground state with the walking pose ($04), and still moves him by the air's rules. On the next frame he walks on at once if he holds the direction he held on landing; none starts the pause pose, and the other direction starts it with one move that way, as a turn does. The air state reads no A press, so a press on the landing frame is lost, and the next frame's press jumps. mega-man-4/landing

About: Mega Man 4 Jump physics

VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L432-L453L_8320: LDA player_state ; player state BEQ L_8352 ; already grounded state: done LDA #$23 ; sound $23 = landing thud JSR queue_sound ; play it LDA #$00 ; state $00 = ground STA player_state ; land: back to ground state LDA #$04 ; sub-type $04 = step CLC ; prepare add ADC $33 ; + shoot-pose offset JSR entity_set_subtype ; set landing sprite JSR L_946E ; capture walk vel for wind sys …Checked by claude, 2026-10-26 — read L_8320 through L_833D at the pinned commit. Measured in Mesen (MesenCE 2.2.1) from power-on at the start of Skull Man's stage: a jump with Right held walked on from the landing without a pause; a standing jump landed into the pause pose; Left on the frame after a Right-held landing moved him 1.30 px back into the pause pose; an A press on the landing frame didn't jump, and a press on the next frame didProbe: probes/jump-physics/movement.mjs

Mega Man 2 instead lands running or into a landing stop (mega-man-2/landing).

Down and a fresh A press start a slide only if the slide's start point, 15 px ahead of his center and 4 px below it, isn't in a wall; with a wall there the press does nothing, neither slide nor jump. The slide moves his Y pixel 2 px down and tests a lower, wider box: floor points 10 px below the new center at x-14, x, and x+14, and wall points 15 px ahead, level with it and 9 px below. With no floor under those points, ground 16 px below the center keeps the slide going, and none stands him up. mega-man-4/slide-box

About: Mega Man 4 Ground slide

Value
{
 "lower": 2,
 "floor": {
  "dy": 10,
  "dx": [
   -14,
   0,
   14
  ]
 },
 "ceiling": {
  "dy": 0,
  "dx": [
   -14,
   0,
   14
  ]
 },
 "wall": {
  "dx": 15,
  "dy": [
   0,
   9
  ]
 },
 "start": {
  "dx": 15,
  "dy": 4
 },
 "headroom": {
  "dy": -14,
  "dx": [
   -14,
   0,
   14
  ]
 },
 "below": {
  "dy": 16,
  "dx": [
   -14,
   0,
   14
  ]
 }
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L204-L213L_816D: LDA temp_08 ; slide direction LSR A ; /2 (1->0 right, 2->1 left) CLC ; prepare add ADC #$06 ; probe index 6/7 (slide height) TAY ; Y = collision probe selector JSR scroll_collision_check ; check wall at slide height LDA $10 ; collision result AND #$10 ; bit 4 = solid BNE L_81D6 ; wall in the way: no slideMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L229-L232LDA ent_y_px ; player Y pixel CLC ; prepare add ADC #$02 ; lower hitbox by 2 px STA ent_y_px ; store YMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L464-L472LDY #$04 ; probe selector 4 (slide height) JSR entity_player_collide ; ride/collide with platforms JSR L_92C5 ; environment + ground check BCS L_8368 ; still grounded: continue slide LDY #$39 ; probe $39 = above (slide box) JSR tile_collision_detect ; check tile above LDA $10 ; collision result AND #$10 ; bit 4 = solid overhead BEQ L_83D3 ; no ceiling: stand upMega Man 4 (USA) (Rev 1) · 0x7D72E-0x7D748 — $D71E-$D738: shape 3 (standing headroom) 02 F2 F2 0E 0E, 14 px up from x-14 in steps of 14; shape 4 (slide floor) 02 0A F2 0E 0E; shape 5 (slide ceiling) 02 00 F2 0E 0EMega Man 4 (USA) (Rev 1) · 0x7D6E7-0x7D6E7 — $D6D7, shape $39's low byte, $00 ($D717 holds $D8)Mega Man 4 (USA) (Rev 1) · 0x7D810-0x7D814 — $D800-$D804, shape $39: 02 10 F2 0E 0E, 16 px down from x-14 in steps of 14Mega Man 4 (USA) (Rev 1) · 0x7D898-0x7D8B4 — $D888-$D8A4: wall shapes 4 and 5 (slide) 01 0F 00 09 and 01 F1 00 09, two points 15 px ahead, level and 9 px down; shapes 6 and 7 (slide start) 00 0F 04 and 00 F1 04Checked by claude, 2026-10-26 — read the slide set-up (L_8156 to L_81D3) and the slide state's floor test at the pinned commit, and the shapes it names (vertical 3, 4, 5, $39; horizontal 4 to 7) as bytes in the Rev 1 ROM

The floor points stay on the same row, so on flat ground his feet don't move, and the slide box's wall points cover the 10 rows over his feet. Mega Man 3 lowers him 2 px too (mega-man-3/slide). His Y pixel stays 2 px low on the frame he stands up, until the next frame's floor test puts him back.

A slide ends in two ways. When the slide box finds no floor and no ground 16 px below his center either (slide-box), he stands up at once, with no headroom test, before that frame's A test and move. Otherwise it ends at the standing test, which a wall, the timer's end, or a turn sends it to. A turn (a held direction against the slide's) zeroes the timer and still moves him 2.5 px the new way on that frame. The test checks his standing headroom, three points 14 px above the slide's center (12 px above his standing one) at x-14, x, and x+14: a solid tile there keeps him sliding at 2.5 px/frame, testing again each frame, and otherwise he stands up in the walking pose, at walking speed, after that frame's move. A fresh A press without Down jumps out of it instead, at 5 px/frame and walking speed, if the same headroom is clear, from the 2 px lower slide center; the earliest such press comes on the slide's 3rd frame (slide-line). mega-man-4/slide-exit

About: Mega Man 4 Ground slide

VerifiedMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L464-L472 — the slide state's entry; probe $39 is the ground 16 px below his center (slide-box)LDY #$04 ; probe selector 4 (slide height) JSR entity_player_collide ; ride/collide with platforms JSR L_92C5 ; environment + ground check BCS L_8368 ; still grounded: continue slide LDY #$39 ; probe $39 = above (slide box) JSR tile_collision_detect ; check tile above LDA $10 ; collision result AND #$10 ; bit 4 = solid overhead BEQ L_83D3 ; no ceiling: stand upMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L497-L524L_839D: LDA joy1_held ; held buttons AND #$03 ; L/R bits BEQ L_83B4 ; none: keep sliding STA temp_00 ; save held direction AND $31 ; same as slide direction? BNE L_83B4 ; yes: keep sliding LDA temp_00 ; held direction STA $31 ; turn: new slide direction STA ent_dir ; face new direction LDA #$00 ; zero STA $34 ; end slide timer (turn ends it) …Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L525-L537L_83D3: LDA #$00 ; state $00 = ground STA player_state ; stand up LDA #$4C ; walk speed 1.30 px/frame STA ent_xvel_sub ; X velocity sub STA $37 ; mirror in $37 LDA #$01 ; 1 px STA ent_xvel ; X velocity STA $38 ; mirror in $38 LDX #$00 ; X = player slot LDA #$04 ; sub-type $04 = step JSR entity_set_subtype ; set standing sprite …Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L473-L496L_8368: LDA joy1_press ; newly pressed AND #$80 ; A button? BEQ L_839D ; no jump: steering LDA joy1_held ; held buttons AND #$04 ; Down held? BNE L_839D ; Down+A: stay sliding LDY #$03 ; probe 3 = standing headroom JSR tile_collision_detect ; check tile above head LDA $10 ; collision result BNE L_839D ; blocked: no jump JSR L_83F2 ; platform overhead check …Checked by claude, 2026-10-26 — read the slide state ($8353) through L_83EF at the pinned commit. Measured in Mesen (MesenCE 2.2.1) from power-on at the start of Skull Man's stage on flat floor: a turn on a slide's 6th frame moved him 2.5 px back and stood him up, and a slide's end stood him up in the walking pose at 1.30 px/frame; an A press without Down on frame 3 jumped out at 5 px/frame and 1.30 px/frame, and A held from the set-up into frame 2 didn't. The lab's conformance check (probes/lab/conformance.mjs) matched the model frame for frame on these and on presses on frame 9, turns, and Down with A heldProbe: probes/jump-physics/movement.mjs

The stand-up leaves his walk direction ($31) as the slide's, so a direction held the same way walks on the next frame without the pause. A platform entity overhead blocks the jump and the stand-up too (L_83F2), which the lab doesn't model.

Mega Man 4's movement on ordinary floor differs from Mega Man 3's in five numbers. The first is the jump's take-off speed: 5 px/frame ($05.$00) against Mega Man 3's 4.89 ($04.$E5). The second is the speed on the ground and after a landing: -1 px/frame ($FF.$00) against -0.25 ($FF.$C0). Third, a release cuts a rise to 0, where Mega Man 3 sets the same -0.25. Fourth, the slide timer starts at 26 ($1A) against 20 ($14), so the slide moves on 26 frames against 21 (slide-line, mega-man-3/slide). Fifth, Mega Man 4 tests for the jump out of a slide on every slide frame, where Mega Man 3 skips the test while the timer is 12 ($0C) or more, so the earliest jump out comes on the 3rd frame against the 9th. mega-man-4/movement-differs-from-mega-man-3

About: Mega Man 4 Jump physics

Value
{
 "takeoff": 1280,
 "other": 1253
}
CodeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L186-L189LDA #$00 ; zero sub-velocity STA ent_yvel_sub ; Y velocity sub = 0 LDA #$05 ; jump speed 5 px/frame STA ent_yvel ; Y velocity = +5 (up)Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_ground.asm#L74-L77lda #$E5 ; normal jump: Y vel = $04.E5 sta ent_yvel_sub,x ; store Y velocity sub-pixel lda #$04 ; Y velocity whole = $04 sta ent_yvel,x ; store Y velocity wholeMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/fixed_entity_physics.asm#L648-L652 — entity_stop_y, which a landing and every grounded frame's floor contact callL_F324: LDA #$00 ; zero STA ent_yvel_sub,X ; clear vert velocity sub-pixel LDA #$FF ; $FF = stopped / minimal STA ent_yvel,X ; set vert velocity pixelMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/movement.asm#L203-L204gravity_snap_floor: jsr snap_y_to_floor ; snap to tile boundary (down) gravity_reset_vel: jsr reset_gravity ; reset velocity to rest valueMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/movement.asm#L424-L428reset_gravity_player: lda #$C0 ; player rest vel sub = $C0 sta ent_yvel_sub,x ; store Y sub velocity lda #$FF ; player rest vel = $FF ($FFC0 = -0.25) sta ent_yvel,x ; store Y velocity whole byte rts ; player rest vel = $FFC0Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L425-L430LDA joy1_held ; held buttons AND #$80 ; A still held? BNE L_8338 ; held: full jump LDA #$00 ; zero STA ent_yvel_sub ; cut jump: Y vel sub = 0 STA ent_yvel ; cut jump: Y vel = 0Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_ground.asm#L264-L267 — reset_gravity sets the player's rest speed, `$FF`.`$C0` (movement.asm L424-L428), whatever this line's comment sayslda joy1_held ; check if A button held and #BTN_A ; A button mask bne player_airborne_variable_jump ; held → keep rising (variable jump) jsr reset_gravity ; A released → clamp Y speed to 0 (variable jump)Mega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L217-L218LDA #$1A ; slide duration 26 frames STA $34 ; set slide timerMega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L288-L289lda #$14 ; slide timer = 20 frames sta $33 ; store slide timerMega Man 4 (U), annotated ca65 disassembly (plasticsmoke) · src/bank3C.asm#L473-L478L_8368: LDA joy1_press ; newly pressed AND #$80 ; A button? BEQ L_839D ; no jump: steering LDA joy1_held ; held buttons AND #$04 ; Down held?Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke) · src/fixed/player_states.asm#L349-L355dec $33 ; decrement timer lda $33 ; check slide timer phase cmp #$0C ; >= $0C? (uncancellable phase) bcs slide_continue_moving ; yes → uncancellable, keep sliding lda joy1_press ; A button pressed? (cancellable phase) and #BTN_A ; check A button bne slide_end_ground_check ; yes → cancel into slide jumpChecked by claude, 2026-10-26 — read both games' jump press, floor contact and rest speed, release cut, slide timer, and slide A test at their pinned commits; the frame counts follow from mega-man-4/slide-line and mega-man-3/slide. Compared in code, not in the lab: Mega Man 3's model was being written at the same time

The two games share the walk and air speed (1.30 px/frame), the slide's 2.5 px/frame, gravity of 0.25 px/frame², and the 7 px/frame fall cap; each set's own claims quote them (mega-man-4/walk-speed, slide-line, gravity, fall-cap; mega-man-3/walk-speed, slide, jump-line). The walk's pause and the box were not compared here.

Cited by: Mega Man (classic series)