Code
EXTRA_BITS = $7FAB10
NEW_SPRITE_NUM = $7FAB9E ;08 bytes custom sprite number
EXTRA_PROP_1 = $7FAB28
JUMP_TIMER = $163E
RAM_ThrowTimer = $1504
Hit_Counter = $1528 ; The hit counter for any sprite that takes lots of hits to kill
GetSpriteClippingA = $03B69F
CheckForContact = $03B72B
GetSpriteClippingB = $03B6E5
;CheckForContact = $03B72B
ShowSprContactGfx = $01AB72
HurtMario = $00F5B7
GivePoints = $02ACE5
GetRand = $01ACF9
SPRITE_STATE = $C2
Invuln_Timer = $1564 ; The RAM address for Larry's stun duration
Hits = $08 ; This is how many hits it takes to kill Larry (default == 3)
RAM_HitCount = $1534
SPRITE_TO_GEN dcb $5A,$5A,$5A ;magie,shells,magie ...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PROPERTIES dcb $40,$00 ;xyppccct format
BOOMERANG_TILE = $CA
TIME_TO_EXPLODE = $A0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dcb "INIT"
JSR SUB_GET_DIR
TYA
STA $157C,x
TXA
AND #$03
ASL A
ASL A
ASL A
ASL A
ASL A
STA JUMP_TIMER,x
CLC
ADC #$32
STA RAM_ThrowTimer,x
RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main sprite JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dcb "MAIN"
HAMMER_BRO_JSL PHB ; \
PHK ; | main sprite function, just calls local subroutine
PLB ; |
JSR DecrementTimers
JSR START_HB_CODE ; |
PLB ; |
RTL ; /
DecrementTimers:
LDA $14C8,x
CMP #$08
BNE DoneDec
LDA $9D
BNE DoneDec
LDA RAM_ThrowTimer,x
BEQ DoneDec
DEC RAM_ThrowTimer,x
DoneDec:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main sprite routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TIME_TO_SHOW = $10 ;time to display the boomerang before it is thrown
SPRITE_GRAVITY = $00
X_SPEED dcb $08,$F8,$08,$F8,$0C,$F4,$10,$F0,$14,$EC
KILLED_X_SPEED dcb $F0,$10
TIME_TILL_THROW dcb $68,$69
STAR INC RAM_ThrowTimer,x
RETURN RTS
START_HB_CODE JSR SUB_GFX ; graphics routine
LDA $14C8,x ; \
CMP #$02 ; } ... not (killed with spin jump [4] or star[2])
BEQ STAR
CMP #$08 ; | if status != 8, return
BNE RETURN ; /
LDA $9D ; \ if sprites locked, return
BNE RETURN ; /
LDA #SPRITE_GRAVITY
STA $AA,x ;Gravity update if zero.
BNE RETURN
JSR SUB_OFF_SCREEN_HB ; handle off screen situation
LDA Invuln_Timer,x ; \
BEQ No_Inv ; | Decrement Invuln timer if necessary
DEC Invuln_Timer,x ; /
No_Inv:
INC $1570,x ; increment number of frames hammer bro has been on screen
LDA $151C,x
AND #$01
BEQ LABEL3B
LDA $1570,x ; \ calculate which frame to show:
LSR A ; |
LSR A ; |
LSR A ; |
AND #$01 ; | update every 16 cycles if normal
BRA LABEL3
LABEL3B LDA $151C,x
BEQ LABEL3
LDA #$01
LABEL3 STA $1602,x ; / write frame to show
LDA RAM_ThrowTimer,x ; \ if time until spit >= $10
CMP #TIME_TO_SHOW ; | just go to normal walking code
BCS JUMP_BIRDO ; /
INC $1602,x
INC $1602,x
LDA Invuln_Timer,x
CMP #$00
BEQ Go_Throw
LDA TIME_TILL_THROW,y
STA RAM_ThrowTimer,x
Go_Throw:
LDA RAM_ThrowTimer,x ; \ throw hammer if it's time
BNE NO_RESET ; |
LDY $C2,x
LDA TIME_TILL_THROW,y
STA RAM_ThrowTimer,x
NO_RESET CMP #$01
BNE JUMP_BIRDO
LDA $C2,x
EOR #$01
STA $C2,x
JSR SUB_HAMMER_THROW ; /
JUMP_BIRDO
LDA $1588,x ; \ if sprite is in contact with an object...
AND #$03 ; |
BEQ NO_OBJ_CONTACT ; |
LDA $157C,x ; | flip the direction status
EOR #$01 ; |
STA $157C,x ; /
NO_OBJ_CONTACT LDA EXTRA_PROP_1,x ; don't stay on ledges if bit is set
AND #$02 ;
BEQ FALLING ;
LDA $1588,x ; run the subroutine if the sprite is in the air...
ORA $151C,x ; ...and not already turning
BNE ON_GROUND ;
JSR SUB_CHANGE_DIR ;
LDA #$01 ; set that we're already turning
STA $151C,x ;
ON_GROUND LDA $1588,x ; if on the ground, reset the turn counter
AND #$04
BEQ IN_AIR
STZ $151C,x
STZ $AA,x
BRA X_TIME
FALLING LDA $1588,x ; if on the ground, reset the turn counter
AND #$04
BEQ IN_AIR
LDA #$10 ; \ y speed = 10
STA $AA,x ; /
Walk_Normal:
LDA $151C,x ;
TAY ;
LDA $1540,x ;
BEQ X_TIME ;
LDA X_SPEED,y ; | set y speed
STA $B6,x ; /
BRA IN_AIR
X_TIME
LDA $1528,x ; \ set x speed based on total HP
ASL
CLC
ADC $157C,x ; and direction
TAY
;LDY $157C,x ; \ set x speed based on direction
LDA X_SPEED,y ; |
STA $B6,x ; /
IN_AIR JSL $01802A ; update position based on speed values
LDA Invuln_Timer,x ; \
CMP #$00 ; | Ignore if Larry is still immune to bombs
BEQ Jump_to_Weapon ; |
BRA No_Jump_to ; /
Jump_to_Weapon:
JSR HIT_ROUTINE
No_Jump_to:
LDA $1588,x ; \ if hammer bro is touching the side of an object...
AND #$03 ; |
BEQ DONE_WITH_SPEED ; |
LDA $151C,x
INC A
AND #$03
STA $151C,x
DONE_WITH_SPEED JSL $018032 ; interact with sprites
JSL $01A7DC ; check for mario/sprite contact (carry set = contact)
LDA $1490 ; \ if mario star timer > 0, goto HAS_STAR
BNE HAS_STAR ; / NOTE: branch to RETURN_24 to disable star killing
NO_CONTACT JSR KILL_BOOMERANGS
RTS ; return
KILL_BOOMERANGS
RTS
RETURN_24 RTS ; final return
HAS_STAR LDA #$02 ; \ status = 2 (being killed by star)
STA $14C8,x ; /
LDA #$D0 ; \ set y speed
STA $AA,x ; /
JSR SUB_HORZ_POS ; get new direction
LDA KILLED_X_SPEED,y ; \ set x speed based on direction
STA $B6,x ; /
INC $18D2 ; increment number consecutive enemies killed
LDA $18D2 ; \
CMP #$08 ; | if consecutive enemies stomped >= 8, reset to 8
BCC NO_RESET2 ; |
LDA #$08 ; |
STA $18D2 ; /
NO_RESET2 JSL $02ACE5 ; give mario points
LDY $18D2 ; \
CPY #$08 ; | if consecutive enemies stomped < 8 ...
BCS NO_SOUND2 ; |
LDA STAR_SOUNDS,y ; | ... play sound effect
STA $1DF9 ; /
NO_SOUND2 RTS ; final return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; hammer routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X_OFFSET dcb $06,$FA
X_OFFSET2 dcb $00,$FF
SUB_HAMMER_THROW
JSL $02A9DE ; \ get an index to an unused sprite slot, return if all slots full
BMI RETURN67 ; / after: Y has index of sprite being generated
PHX
TYX
LDA #$10 ; \ sound effect (can also be $20)
STA $1DF9
LDA #$08
STA $14C8,x
PHX
LDA #$02
JSL RANDOM
TAX
LDA SPRITE_TO_GEN,x ; \ set sprite number for new sprite
PLX
;LDA #$3A
STA $7FAB9E,x
JSL $07F7D2
JSL $0187A7
LDA #$08
STA $7FAB10,x
PLX
PHY
LDA $157C,x
TAY
LDA $E4,x ; \ set xlo position for new sprite
CLC
ADC X_OFFSET,y
PLY
STA $00E4,y
PHY
LDA $157C,x
TAY
LDA $14E0,x ; | set xhi position for new sprite
ADC X_OFFSET2,y
PLY
STA $14E0,y ; /
LDA $D8,x ; \ set y position for new sprite
SEC ; | (y position of generator - 1)
SBC #$0E ; |
STA $00D8,y ; |
LDA $14D4,x ; |
SBC #$00 ; |
STA $14D4,y ; /
PHX ; \ before: X must have index of sprite being generated
TYX ; | routine clears *all* old sprite values...
JSL $07F7D2 ; | ...and loads in new values for the 6 main sprite tables
JSL $0187A7 ; get table values for custom sprite
LDA #$88
STA EXTRA_BITS,x
PLX ; /
LDA #$50
JSR CODE_01BF6A
LDX $15E9
LDA $00
STA $00AA,y
LDA $01
STA $00B6,y
;RETURN1 RTS
; LDA $157C,x
; STA $157C,y
RETURN67 RTS ; return
RANDOM PHX
PHP
SEP #$30
PHA
JSL $01ACF9 ; Random number generation routine
PLX
CPX #$FF ;\ Handle glitch if max is FF
BNE NORMALRT ;|
LDA $148B ;|
BRA ENDRANDOM ;/
NORMALRT INX ; Amount in plus 1
LDA $148B ;\
STA $4202 ;| Multiply with hardware regsisters
STX $4203 ;|
NOP ;|
NOP ;|
NOP ;|
NOP ;/
LDA $4217
ENDRANDOM PLP
PLX
RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; aiming routine
; input: accumulator should be set to total speed (x+y)
; output: $00 = y speed, $01 = x speed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CODE_01BF6A: STA $01
PHX ;\ preserve sprite indexes of Magikoopa and magic
PHY ;/
JSR SUB_VERT_POS ; $0E = vertical distance to Mario
STY $02 ; $02 = vertical direction to Mario
LDA $0E ;\ $0C = vertical distance to Mario, positive
BPL CODE_01BF7C ; |
EOR #$FF ; |
CLC ; |
ADC #$01 ; |
CODE_01BF7C: STA $0C ;/
JSR SUB_HORZ_POS ; $0F = horizontal distance to Mario
STY $03 ; $03 = horizontal direction to Mario
LDA $0F ;\ $0D = horizontal distance to Mario, positive
BPL CODE_01BF8C ; |
EOR #$FF ; |
CLC ; |
ADC #$01 ; |
CODE_01BF8C: STA $0D ;/
LDY #$00
LDA $0D ;\ if vertical distance less than horizontal distance,
CMP $0C ; |
BCS CODE_01BF9F ;/ branch
INY ; set y register
PHA ;\ switch $0C and $0D
LDA $0C ; |
STA $0D ; |
PLA ; |
STA $0C ;/
CODE_01BF9F: LDA #$00 ;\ zero out $00 and $0B
STA $0B ; | ...what's wrong with STZ?
STA $00 ;/
LDX $01 ;\ divide $0C by $0D?
CODE_01BFA7: LDA $0B ; |\ if $0C + loop counter is less than $0D,
CLC ; | |
ADC $0C ; | |
CMP $0D ; | |
BCC CODE_01BFB4 ; |/ branch
SBC $0D ; | else, subtract $0D
INC $00 ; | and increase $00
CODE_01BFB4: STA $0B ; |
DEX ; |\ if still cycles left to run,
BNE CODE_01BFA7 ;/ / go to start of loop
TYA ;\ if $0C and $0D was not switched,
BEQ CODE_01BFC6 ;/ branch
LDA $00 ;\ else, switch $00 and $01
PHA ; |
LDA $01 ; |
STA $00 ; |
PLA ; |
STA $01 ;/
CODE_01BFC6: LDA $00 ;\ if horizontal distance was inverted,
LDY $02 ; | invert $00
BEQ CODE_01BFD3 ; |
EOR #$FF ; |
CLC ; |
ADC #$01 ; |
STA $00 ;/
CODE_01BFD3: LDA $01 ;\ if vertical distance was inverted,
LDY $03 ; | invert $01
BEQ CODE_01BFE0 ; |
EOR #$FF ; |
CLC ; |
ADC #$01 ; |
STA $01 ;/
CODE_01BFE0: PLY ;\ retrieve Magikoopa and magic sprite indexes
PLX ;/
RTS ; return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Be killed by shells
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HIT_ROUTINE:
HITPOINTS ;TXA ; \ Process every 4 frames
;EOR $13 ; |
;AND #$03 ; |
;BNE RETURN_BOB ; /
LDY #$09 ; \ Loop over sprites:
KILLED_X_SPEED:
dcb $FF,$00
STUNNED_X_SPEED:
dcb $20,$DF
SpriteInteract:
ldy #$0b
InteractLoop:
lda $14c8,y
cmp #$09
bcs ProcessSprite
NextSprite:
dey
bpl InteractLoop
rts
ProcessSprite:
PHX
TYX
JSL GetSpriteClippingB
PLX
JSL GetSpriteClippingA
JSL CheckForContact
bcc NextSprite
PHX
TYX
JSL ShowSprContactGfx
lda $14C8,x
CMP #$0A
BEQ NoKill
LDA #$02 ; Kill thrown sprite
STA $14C8,x
LDA #$D0 ; Set killed Y speed
STA $AA,x
LDY #$00 ; Set killed X speed
LDA $B6,x
BPL SetSpeed
INY
SetSpeed:
LDA KILLED_X_SPEED,y
STA $B6,x
NoKill:
PLX
HandleBirdoHit:
LDA #$28 ; Play sound effect
STA $1DFC
LDA #$F0 ; Set stunned timer
STA $1564,x
INC $1528,x
LDA $1528,x
cmp #Hits
bcc Return3
LDA #$02 ; Kill Larry
STA $14C8,x
STZ $B6,x ; Set X speed
LDA #$F0 ; Set Y speed
STA $AA,x
GOAL DEC $13C6 ; prevent Mario from walking at the level end
LDA #$FF ; \ set goal
STA $1493 ; /
LDA #$0B ; \ set ending music
STA $1DFB ; /
RTS ; return
LDA #$03
STA $1602,x ; / write frame to show
Return3:
rts
ProcessCachedHit:
LDA $1528,x
BPL Return3
AND #$7F
STA $1528,x
BRA HandleBirdoHit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; graphics routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TILEMAP: db $84,$82,$80 ; facing right
db $A4,$A2,$A0
db $C4,$C2,$C0
db $80,$82,$84 ; facing left
db $A0,$A2,$A4
db $C0,$C2,$C4
db $8A,$88,$86 ; facing right
db $AA,$A8,$A6
db $CA,$C8,$C6
db $86,$88,$8A ; facing left
db $A6,$A8,$AA
db $C6,$C8,$CA
X_OFFSET: db $00,$10,$20
db $00,$10,$20
db $00,$10,$20
Y_OFFSET: db $E0,$E0,$E0
db $F0,$F0,$F0
db $00,$00,$00
PROPERTIES: db $40,$40,$40
db $40,$40,$40
db $40,$40,$40
db $00,$00,$00
db $00,$00,$00
db $00,$00,$00
SUB_GFX: JSR GET_DRAW_INFO ; sets y = OAM offset
LDA $157C,x
STA $04
ASL A
ASL A
ASL A
CLC
ADC $04
STA $02
PHX
LDX #$08
LOOP_START: PHX
LDA X_OFFSET,x
CLC
ADC $00 ; \ tile x position = sprite y location ($01)
STA $0300,y ; /
LDA Y_OFFSET,x
CLC
ADC $01 ; \ tile y position = sprite x location ($00)
STA $0301,y ; /
TXA
CLC
ADC $02
TAX
PHX
LDA $14
LSR A
LSR A
LSR A
AND #$01
BNE SKIP
TXA
CLC
ADC #$12
TAX
SKIP: LDA TILEMAP,x
STA $0302,y
PLX
PHX
LDX $15E9
LDA $15F6,x ; tile properties xyppccct, format
PLX
ORA PROPERTIES,x
ORA $64 ; add in tile priority of level
STA $0303,y ; store tile properties
PLX
INY ; \ increase index to sprite tile map ($300)...
INY ; | ...we wrote 1 16x16 tile...
INY ; | ...sprite OAM is 8x8...
INY ; / ...so increment 4 times
DEX
BPL LOOP_START
PLX
LDY #$02 ; \ 460 = 2 (all 16x16 tiles)
LDA #$08 ; | A = (number of tiles drawn - 1)
JSL $01B7B3 ; / don't draw if offscreen
RTS ; return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_CHANGE_DIR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;org $019098
SUB_CHANGE_DIR ;LDA $15AC,x
;BNE LABEL41
;LDA #$08
;STA $15AC,x
LDA $B6,x
EOR #$FF
INC A
STA $B6,x
LDA $157C,x
EOR #$01
STA $157C,x
LABEL41 RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; routines below can be shared by all sprites. they are ripped from original
; SMW and poorly documented
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STAR_SOUNDS dcb $00,$13,$14,$15,$16,$17,$18,$19
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B760 - graphics routine helper - shared
; sets off screen flags and sets index to OAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GET_DRAW_INFO
; This is a helper for the graphics routine. It sets off screen flags, and sets up
; variables. It will return with the following:
;
; Y = index to sprite OAM ($300)
; $00 = sprite x position relative to screen boarder
; $01 = sprite y position relative to screen boarder
;
; It is adapted from the subroutine at $03B760
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SPR_T1: db $0C,$1C
SPR_T2: db $01,$02
GET_DRAW_INFO: STZ $186C,x ; reset sprite offscreen flag, vertical
STZ $15A0,x ; reset sprite offscreen flag, horizontal
LDA $E4,x ; \
CMP $1A ; | set horizontal offscreen if necessary
LDA $14E0,x ; |
SBC $1B ; |
BEQ ON_SCREEN_X ; |
INC $15A0,x ; /
ON_SCREEN_X: LDA $14E0,x ; \
XBA ; |
LDA $E4,x ; |
REP #$20 ; |
SEC ; |
SBC $1A ; | mark sprite invalid if far enough off screen
CLC ; |
ADC.w #$0040 ; |
CMP.w #$0180 ; |
SEP #$20 ; |
ROL A ; |
AND #$01 ; |
STA $15C4,x ; /
BNE INVALID ;
LDY #$00 ; \ set up loop:
LDA $1662,x ; |
AND #$20 ; | if not smushed (1662 & 0x20), go through loop twice
BEQ ON_SCREEN_LOOP ; | else, go through loop once
INY ; /
ON_SCREEN_LOOP: LDA $D8,x ; \
CLC ; | set vertical offscreen if necessary
ADC SPR_T1,y ; |
PHP ; |
CMP $1C ; | (vert screen boundry)
ROL $00 ; |
PLP ; |
LDA $14D4,x ; |
ADC #$00 ; |
LSR $00 ; |
SBC $1D ; |
BEQ ON_SCREEN_Y ; |
LDA $186C,x ; | (vert offscreen)
ORA SPR_T2,y ; |
STA $186C,x ; |
ON_SCREEN_Y: DEY ; |
BPL ON_SCREEN_LOOP ; /
LDY $15EA,x ; get offset to sprite OAM
LDA $E4,x ; \
SEC ; |
SBC $1A ; | $00 = sprite x position relative to screen boarder
STA $00 ; /
LDA $D8,x ; \
SEC ; |
SBC $1C ; | $01 = sprite y position relative to screen boarder
STA $01 ; /
RTS ; return
INVALID: PLA ; \ return from *main gfx routine* subroutine...
PLA ; | ...(not just this subroutine)
RTS ; /
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B817 - horizontal mario/sprite check - shared
; Y = 1 if mario left of sprite??
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;org $03B817
SUB_HORZ_POS LDY #$00 ;A:25D0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1020 VC:097 00 FL:31642
LDA $94 ;A:25D0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZCHC:1036 VC:097 00 FL:31642
SEC ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1060 VC:097 00 FL:31642
SBC $E4,x ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1074 VC:097 00 FL:31642
STA $0F ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1104 VC:097 00 FL:31642
LDA $95 ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1128 VC:097 00 FL:31642
SBC $14E0,x ;A:2500 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZcHC:1152 VC:097 00 FL:31642
BPL LABEL16 ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1184 VC:097 00 FL:31642
INY ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1200 VC:097 00 FL:31642
LABEL16 RTS ;A:25FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:1214 VC:097 00 FL:31642
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_VERT_POS
; This routine determines if Mario is above or below the sprite. It sets the Y register
; to the direction such that the sprite would face Mario
; It is ripped from $03B829
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SUB_VERT_POS LDY #$00 ;A:25A1 X:0007 Y:0001 D:0000 DB:03 S:01EA P:envMXdizCHC:0130 VC:085 00 FL:924
LDA $96 ;A:25A1 X:0007 Y:0000 D:0000 DB:03 S:01EA P:envMXdiZCHC:0146 VC:085 00 FL:924
CLC
ADC #$18
SEC ;A:2546 X:0007 Y:0000 D:0000 DB:03 S:01EA P:envMXdizCHC:0170 VC:085 00 FL:924
SBC $D8,x ;A:2546 X:0007 Y:0000 D:0000 DB:03 S:01EA P:envMXdizCHC:0184 VC:085 00 FL:924
STA $0E ;A:25D6 X:0007 Y:0000 D:0000 DB:03 S:01EA P:eNvMXdizcHC:0214 VC:085 00 FL:924
LDA $97 ;A:25D6 X:0007 Y:0000 D:0000 DB:03 S:01EA P:eNvMXdizcHC:0238 VC:085 00 FL:924
SBC $14D4,x ;A:2501 X:0007 Y:0000 D:0000 DB:03 S:01EA P:envMXdizcHC:0262 VC:085 00 FL:924
BPL SPR_L11 ;A:25FF X:0007 Y:0000 D:0000 DB:03 S:01EA P:eNvMXdizcHC:0294 VC:085 00 FL:924
INY ;A:25FF X:0007 Y:0000 D:0000 DB:03 S:01EA P:eNvMXdizcHC:0310 VC:085 00 FL:924
SPR_L11 RTS ;A:25FF X:0007 Y:0001 D:0000 DB:03 S:01EA P:envMXdizcHC:0324 VC:085 00 FL:924
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B817 - horizontal mario/sprite check - shared
; Y = 1 if mario left of sprite??
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;org $03B817 ; Y = 1 if contact
SUB_GET_DIR LDY #$00 ;A:25D0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1020 VC:097 00 FL:31642
LDA $94 ;A:25D0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZCHC:1036 VC:097 00 FL:31642
SEC ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1060 VC:097 00 FL:31642
SBC $E4,x ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1074 VC:097 00 FL:31642
STA $0F ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1104 VC:097 00 FL:31642
LDA $95 ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1128 VC:097 00 FL:31642
SBC $14E0,x ;A:2500 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZcHC:1152 VC:097 00 FL:31642
BPL LABEL16 ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1184 VC:097 00 FL:31642
INY ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1200 VC:097 00 FL:31642
LABEL16 RTS ;A:25FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:1214 VC:097 00 FL:31642
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B85D - off screen processing code - shared
; sprites enter at different points
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;org $03B83B
TABLE3 dcb $40,$B0
TABLE6 dcb $01,$FF
TABLE4 dcb $30,$C0,$A0,$80,$A0,$40,$60,$B0
TABLE5 dcb $01,$FF,$01,$FF,$01,$00,$01,$FF
SUB_OFF_SCREEN_MOLE LDA #$06 ; \ entry point of routine determines value of $03
BRA STORE_03 ; |
SUB_OFF_SCREEN_X1 LDA #$04 ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X2 LDA #$02 ; |
STORE_03 STA $03 ; |
BRA START_SUB ; |
SUB_OFF_SCREEN_HB STZ $03 ; /
START_SUB JSR SUB_IS_OFF_SCREEN ; \ if sprite is not off screen, return
BEQ RETURN_2 ; /
LDA $5B ; \ goto VERTICAL_LEVEL if vertical level
AND #$01 ; |
BNE VERTICAL_LEVEL ; /
LDA $D8,x ; \
CLC ; |
ADC #$50 ; | if the sprite has gone off the bottom of the level...
LDA $14D4,x ; | (if adding 0x50 to the sprite y position would make the high byte >= 2)
ADC #$00 ; |
CMP #$02 ; |
BPL ERASE_SPRITE ; / ...erase the sprite
LDA $167A,x ; \ if "process offscreen" flag is set, return
AND #$04 ; |
BNE RETURN_2 ; /
LDA $13 ; \
AND #$01 ; |
ORA $03 ; |
STA $01 ; |
TAY ; /
LDA $1A ;x boundry ;A:0101 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0256 VC:090 00 FL:16953
CLC ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0280 VC:090 00 FL:16953
ADC TABLE4,y ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0294 VC:090 00 FL:16953
ROL $00 ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0326 VC:090 00 FL:16953
CMP $E4,x ;x pos ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0364 VC:090 00 FL:16953
PHP ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0394 VC:090 00 FL:16953
LDA $1B ;x boundry hi ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNvMXdizCHC:0416 VC:090 00 FL:16953
LSR $00 ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdiZCHC:0440 VC:090 00 FL:16953
ADC TABLE5,y ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdizcHC:0478 VC:090 00 FL:16953
PLP ;A:01FF X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNvMXdizcHC:0510 VC:090 00 FL:16953
SBC $14E0,x ;x pos high ;A:01FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0538 VC:090 00 FL:16953
STA $00 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0570 VC:090 00 FL:16953
LSR $01 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0594 VC:090 00 FL:16953
BCC LABEL20 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0632 VC:090 00 FL:16953
EOR #$80 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0648 VC:090 00 FL:16953
STA $00 ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0664 VC:090 00 FL:16953
LABEL20 LDA $00 ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0688 VC:090 00 FL:16953
BPL RETURN_2 ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0712 VC:090 00 FL:16953
ERASE_SPRITE LDA $14C8,x ; \ if sprite status < 8, permanently erase sprite
CMP #$08 ; |
BCC KILL_SPRITE ; /
LDY $161A,x ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0140 VC:071 00 FL:21152
CPY #$FF ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0172 VC:071 00 FL:21152
BEQ KILL_SPRITE ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0188 VC:071 00 FL:21152
LDA #$00 ; \ mark sprite to come back A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0204 VC:071 00 FL:21152
STA $1938,y ; / A:FF00 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0220 VC:071 00 FL:21152
KILL_SPRITE STZ $14C8,x ; erase sprite
RETURN_2 RTS ; return
VERTICAL_LEVEL LDA $167A,x ; \ if "process offscreen" flag is set, return
AND #$04 ; |
BNE RETURN_2 ; /
LDA $13 ; \ only handle every other frame??
LSR A ; |
BCS RETURN_2 ; /
AND #$01 ;A:0227 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0228 VC:112 00 FL:1142
STA $01 ;A:0201 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0244 VC:112 00 FL:1142
TAY ;A:0201 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0268 VC:112 00 FL:1142
LDA $1C ;A:0201 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0282 VC:112 00 FL:1142
CLC ;A:02BD X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0306 VC:112 00 FL:1142
ADC TABLE3,y ;A:02BD X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0320 VC:112 00 FL:1142
ROL $00 ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:enVMXdizCHC:0352 VC:112 00 FL:1142
CMP $D8,x ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:enVMXdizCHC:0390 VC:112 00 FL:1142
PHP ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNVMXdizcHC:0420 VC:112 00 FL:1142
LDA.W $001D ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNVMXdizcHC:0442 VC:112 00 FL:1142
LSR $00 ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:enVMXdiZcHC:0474 VC:112 00 FL:1142
ADC TABLE6,y ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:enVMXdizCHC:0512 VC:112 00 FL:1142
PLP ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdiZCHC:0544 VC:112 00 FL:1142
SBC $14D4,x ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNVMXdizcHC:0572 VC:112 00 FL:1142
STA $00 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0604 VC:112 00 FL:1142
LDY $01 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0628 VC:112 00 FL:1142
BEQ LABEL22 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0652 VC:112 00 FL:1142
EOR #$80 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0668 VC:112 00 FL:1142
STA $00 ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0684 VC:112 00 FL:1142
LABEL22 LDA $00 ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0708 VC:112 00 FL:1142
BPL RETURN_2 ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0732 VC:112 00 FL:1142
BMI ERASE_SPRITE ;A:0280 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0170 VC:064 00 FL:1195
SUB_IS_OFF_SCREEN LDA $15A0,x ; \ if sprite is on screen, accumulator = 0
ORA $186C,x ; |
RTS ; / return
#