Super Mario Bros. 3:Notes
From Data Crystal
Back to Super Mario Bros. 3 page.
Disassembly/reverse engineering notes
- NN: all values are hexadecimal and at least two digits (e.g. 0F, not F) unless noted otherwise.
- $NN or $NNNN: a memory address.
- Countdown timer: a byte in memory set to some value, decremented every frame and when it reaches 0 something is usually set up to happen. Many timers are cyclic, meaning that they are being re-set and reused immediately after reaching 0.
- If the player holds L/R the horizontal velocity $BD will start to increase (to-do: what's the exact increment?) at around 1 per frame. The same acceleration is always used when walking/running/dashing.
- abs($BD) can at most reach a limit that varies depending on things below.
- If walking, the limit is 18.
- If player holds B,
- The limit is raised to 28 and $BD is allowed to increase again.
- As long as abs($BD) stays >= 28, the P-timer $515 cycles from 7, and every time it elapses an arrow is added to the P-meter.
- When the P starts blinking, the player is in "flight mode":
- 1) The limit is raised to 38 and $BD is allowed to increase again.
- 2) The P-timer is LOCKED to the value 0F (don't know if the exact value has significance).
- 3) Pressing A at this point launches the player into flight/super-jump, indicated by $57B being set to 1.
- 4) The flight duration timer $56E is set to XX (to-do: look up the value).
- Player exits "flight-mode" ($57B = 0) when one of the following happens: (to-do: incomplete)
- 1) Player touches ground.
- 2) Flight-limit timer $56E elapses.
- 3) Player lets go of the A button.
- Once no longer in "flight-mode", the P-timer $515 cycles from 23. Every time it elapses an arrow is removed from the P-meter.
- You can only refill the P-meter again by accelerating to abs($BD) >= 28 as above. (If $515 hasn't had time to elapse, i.e. the P-meter hasn't decreased, you can stay "eligible" for $57B flight-mode by doing short hops of flight and staying at >= 28.)
$AC5A Jump power
$AC5A:A5 BD LDA $00BD ; Load player horz velocity $AC5C:10 03 BPL $AC61 ; If negative, $AC5E:20 0F DD JSR $DD0F ; take absolute value $AC61:4A LSR ; Divide by 16 $AC62:4A LSR $AC63:4A LSR $AC64:4A LSR $AC65:AA TAX ; X = A, going to use it as an index $AC66:AD 47 A6 LDA $A647 ; Load default jump velocity $AC69:38 SEC $AC6A:FD 48 A6 SBC $A648,X ; Subtract from the jump velocity (remember lower means more power) using the table 00,02,04,08. ; Thus a higher horizontal speed means a more powerful jump. $AC6D:85 CF STA $00CF ; Store as new vertical velocity.
$ACA1 Application of gravity
$ACA1:A0 05 LDY #$05 ; Y = default falling gravity $ACA3:A5 CF LDA $00CF ; Load current vertical velocity $ACA5:C9 E0 CMP #$E0 ; $ACA7:10 0D BPL $ACB6 ; If currently rising and v vel is still faster than E0, $ACA9:AD 79 05 LDA $0579 ; Don't know what 0579 is... unused? Debugger never sees a nonzero value. $ACAC:D0 0D BNE $ACBB $ACAE:A5 17 LDA $0017 ; Read gamepad. 80 is jump key, so value will appear negative! $ACB0:10 04 BPL $ACB6 ; If jump pressed, $ACB2:A0 01 LDY #$01 ; Y = jump gravity (lower than normal) $ACB4:D0 05 BNE $ACBB ; $ACB6:A9 00 LDA #$00 ; This is run if jump key is NOT pressed $ACB8:8D 79 05 STA $0579 ; So what does it do? $ACBB:98 TYA ; A=Y $ACBC:18 CLC ; $ACBD:65 CF ADC $00CF ; Add gravity to current vertical velocity $ACBF:85 CF STA $00CF ; And store back
So, jumps are aborted either by the user releasing the button (bit 7 in 0017 is zero) or the 00CF is more positive than E0. Since SOME gravity is always applied, this ensures jumps are aborted.
$BFCC (Subroutine) Clamp Y velocity to the maximum
$BFCC:A5 CF LDA $00CF ; Load current vertical velocity $BFCE:30 08 BMI $BFD8 ; Negative? Then skip clamping. $BFD0:C9 40 CMP #$40 ; #$40 is the maximum fall vel (note: gravity is added afterwards so the effective value is 45) $BFD2:30 04 BMI $BFD8 ; Less than this? Then skip clamping. $BFD4:A9 40 LDA #$40 ; Replace $00CF with the maximum fall vel. $BFD6:85 CF STA $00CF $BFD8:A2 12 LDX #$12 ; UNKNOWN $BFDA:20 93 BF JSR $BF93 ; UNKNOWN $BFDD:60 RTS