;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; SMW Mega Mole (sprite BF), by imamelia ;; ;; This is a disassembly of sprite BF in SMW, the Mega Mole. This one is not ;; dynamic and is less messy than the one that comes with Sprite Tool. ;; ;; Uses first extra bit: YES ;; ;; If the extra bit is set, this will be a "friendly" Mega Mole; i.e., it will not hurt ;; the player. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; defines and tables ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Speed: db $10,$F0 XDisp: db $00,$10,$00,$10,$10,$00,$10,$00 YDisp: db $F0,$F0,$00,$00 Tilemap: db $C6,$C8,$E6,$E8,$CA,$CC,$EA,$EC !Palette = $01 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; init routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print "INIT ",pc JSR SubHorzPos TYA STA $157C,x LDA $7FAB10,x AND #$04 STA $1510,x RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; main routine wrapper ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print "MAIN ",pc PHB PHK PLB JSR MegaMoleMain PLB RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; main routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Return00: ; RTS ; MegaMoleMain: JSR MegaMoleGFX ; draw the sprite LDA $14C8,x ; CMP #$08 ; if the sprite is not in normal status... BNE Return00 ; return JSR SubOffscreenX3 ; LDY $157C,x ; index the speed table by the direction LDA Speed,y ; STA $B6,x ; set the sprite X speed LDA $9D ; if sprites are locked... BNE Return00 ; return LDA $1588,x ; AND #$04 ; push the sprite object status with respect to the ground PHA ; so we can check it later LDA $14 AND #$1F BNE .DontJump LDA #$B0 STA $AA,x .DontJump JSL $01802A ; update sprite position based on speed values JSL $018032 ; interact with other sprites LDA $1588,x ; AND #$04 ; branch if the sprite is not touching ground BEQ InAir ; STZ $AA,x ; set the sprite Y speed to 0 if the sprite is on the ground PLA ; BRA OnGround ; InAir: ; PLA ; pull the previous blocked value BEQ WasInAir ; if the sprite was on the ground before but is now in the air... LDA #$0A ; STA $1540,x ; set this timer WasInAir: ; LDA $1540,x ; if the timer is set... BEQ OnGround ; (time to walk off a ledge before falling?) STZ $AA,x ; zero the sprite Y speed OnGround: ; LDY $15AC,x ; LDA $1588,x ; AND #$03 ; if the sprite is touching a wall... BEQ NoFlipDir ; CPY #$00 ; and the turn timer hasn't already been set... BNE FlipDirection ; LDA #$10 ; STA $15AC,x ; set the turn timer FlipDirection: ; LDA $157C,x ; EOR #$01 ; and flip the sprite direction STA $157C,x ; NoFlipDir: ; CPY #$00 ; if the turn timer is at zero... BNE NoUpdateDirStat ; LDA $157C,x ; then update the direction status used by the GFX routine STA $151C,x ; NoUpdateDirStat: ; JSL $01A7DC ; check contact with the player BCC Return01 ; if there is none, end here JSR SubVertPos ; check the vertical distance between the player and the sprite LDA $0E ; player Y position minus sprite Y position CMP #$D8 ; if this value is greater than D8... BPL MoleWins ; then the player is touching the Mega Mole from the side or bottom RideMole: ; LDA $7D ; if the player is moving upward... BMI Return01 ; return LDA #$01 ; STA $1471 ; set the "on a sprite" flag LDA #$06 ; STA $154C,x ; disable interaction for a few frames STZ $7D ; and set the player Y speed to 0 LDA #$D6 ; LDY $187A ; if the player is on Yoshi... BEQ NotOnYoshi ; LDA #$C6 ; offset = C6 NotOnYoshi: ; if not, offset = D6 CLC ; ADC $D8,x ; set the Y offset for the player STA $96 ; to determine where to place him/her in relation to the sprite LDA $14D4,x ; ADC #$FF ; handle the position high byte to prevent overflow STA $97 ; LDY #$00 ; LDA $1491 ; $1491 = amount to move the player along the X axis (set in the position-updating routine) BPL RightXOffset ; if this value is positive, then the high byte of the X offset is 00 DEY ; if this value is negative, then the high byte of the X offset is FF RightXOffset: ; CLC ; ADC $94 ; add the X offset to the player X position STA $94 ; TYA ; high byte from Y to A ADC $95 ; set the high byte of the offset STA $95 ; Return01: ; RTS ; MoleWins: ; LDA $154C,x ; if the interaction-disable timer is set... ORA $15D0,x ; or the mole is being eaten... ORA $1510,x ; or the extra bit is set... BNE Return01 ; return JSL $00F5B7 ; if none of the above are true, hurt the player RTS ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; graphics routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MegaMoleGFX: JSR GetDrawInfo ; LDA $151C,x ; direction status STA $02 ; into scratch RAM LDA $14 ; sprite frame counter LSR ; LSR ; over 4 ;NOP ; in most sprites, there would be three LSRs here; they decided to animate this one twice as fast CLC ; ADC $15E9 ; add in the sprite index AND #$01 ; 2 possible frames ASL ; ASL ; x4, because there are 4 tiles per frame STA $03 ; $03 = starting tilemap index (00 for the first frame, 04 for the second) PHX ; save the sprite index LDX #$03 ; 4 tiles to draw, so load 03 GFXLoop: ; PHX ; push the current tile number (00-03) LDA $02 ; if the mole is facing right... BNE FacingLeft ; INX #4 ; increment the index to the X displacement table by 4 FacingLeft: ; LDA $00 ; $00 = base X position CLC ; ADC XDisp,x ; set the tile X displacement STA $0300,y ; OAM address #1 PLX ; LDA $01 ; $01 = base Y position CLC ; ADC YDisp,x ; set the tile Y displacement STA $0301,y ; OAM address #2 PHX ; TXA ; CLC ; ADC $03 ; add the frame value to X TAX ; to get the tilemap index LDA Tilemap,x ; set the tile number STA $0302,y ; OAM address #3 LDA #!Palette ; sprite palette and GFX page LDX $02 ; if the sprite is facing right... BNE NoFlipTile ; ORA #$40 ; X-flip the tile NoFlipTile: ; ORA $64 ; add in the sprite priority and set the tile properties STA $0303,y ; OAM address #4 PLX ; current tile INY #4 ; add 4 to the OAM index DEX ; and decrement the tile count BPL GFXLoop ; if positive, there are more tiles to draw PLX ; pull back the sprite index LDY #$02 ; the tiles are all 16x16, so Y = 02 LDA #$03 ; 4 tiles were drawn, so A = 03 JSL $01B7B3 ; finish the write to OAM RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; subroutines ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Table1: db $0C,$1C Table2: db $01,$02 Table3: db $40,$B0 Table6: db $01,$FF Table4: db $30,$C0,$A0,$C0,$A0,$F0,$60,$90,$30,$C0,$A0,$80,$A0,$40,$60,$B0 Table5: db $01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$00,$01,$FF ;SubOffscreenX0: ;LDA #$00 ;BRA SubOffscreenMain ;SubOffscreenX1: ;LDA #$02 ;BRA SubOffscreenMain ;SubOffscreenX2: ;LDA #$04 ;BRA SubOffscreenMain SubOffscreenX3: LDA #$06 ;BRA SubOffscreenMain ;SubOffscreenX4: ;LDA #$08 ;BRA SubOffscreenMain ;SubOffscreenX5: ;LDA #$0A ;BRA SubOffscreenMain ;SubOffscreenX6: ;LDA #$0C ;BRA SubOffscreenMain ;SubOffscreenX7: ;LDA #$0E SubOffscreenMain: STA $03 JSR SubIsOffscreen BEQ Return2 LDA $5B LSR BCS VerticalLevel LDA $D8,x CLC ADC #$50 LDA $14D4,x ADC #$00 CMP #$02 BPL EraseSprite LDA $167A,x AND #$04 BNE Return2 LDA $13 AND #$01 ORA $03 STA $01 TAY LDA $1A CLC ADC Table4,y ROL $00 CMP $E4,x PHP LDA $1B LSR $00 ADC Table5,y PLP SBC $14E0,x STA $00 LSR $01 BCC Label20 EOR #$80 STA $00 Label20: LDA $00 BPL Return2 EraseSprite: LDA $14C8,x CMP #$08 BCC KillSprite LDY $161A,x CPY #$FF BEQ KillSprite LDA #$00 STA $1938,y KillSprite: STZ $14C8,x Return2: RTS VerticalLevel: LDA $167A,x AND #$04 BNE Return2 LDA $13 LSR BCS Return2 AND #$01 STA $01 TAY LDA $1C CLC ADC Table3,y ROL $00 CMP $D8,x PHP LDA $1D LSR $00 ADC Table6,y PLP SBC $14D4,x STA $00 LDY $02 BEQ Label22 EOR #$80 STA $00 Label22: LDA $00 BPL Return2 BMI EraseSprite SubIsOffscreen: LDA $15A0,x ORA $186C,x RTS GetDrawInfo: STZ $186C,x STZ $15A0,x LDA $E4,x CMP $1A LDA $14E0,x SBC $1B BEQ OnscreenX INC $15A0,x OnscreenX: LDA $14E0,x XBA LDA $E4,x REP #$20 SEC SBC $1A CLC ADC.w #$0040 CMP #$0180 SEP #$20 ROL A AND #$01 STA $15C4,x BNE Invalid LDY #$00 LDA $1662,x AND #$20 BEQ OnscreenLoop INY OnscreenLoop: LDA $D8,x CLC ADC Table1,y PHP CMP $1C ROL $00 PLP LDA $14D4,x ADC #$00 LSR $00 SBC $1D BEQ OnscreenY LDA $186C,x ORA Table2,y STA $186C,x OnscreenY: DEY BPL OnscreenLoop LDY $15EA,x LDA $E4,x SEC SBC $1A STA $00 LDA $D8,x SEC SBC $1C STA $01 RTS Invalid: PLA PLA RTS SubHorzPos: LDY #$00 LDA $94 SEC SBC $E4,x STA $0F LDA $95 SBC $14E0,x BPL $01 INY RTS SubVertPos: LDY #$00 LDA $96 SEC SBC $D8,x STA $0F LDA $97 SBC $14D4,x BPL $01 INY RTS