...Davor war ich mir sicher das man keins bekommt...egal ^^ Trotzdem interessant ^^
...Davor war ich mir sicher das man keins bekommt...egal ^^ Trotzdem interessant ^^
JMP Mario
JMP Mario
JMP Mario
JMP Return
JMP Return
JMP Return
JMP Return
RISE_SPEED dcb $F0,$E0,$D0
TIME_ON_GROUND dcb $30,$20,$10
X_SPEED_LEFT dcb $10,$20,$30
X_SPEED_RIGHT dcb $EF,$DF,$CF
RISE_SPEED dcb $F0,$E0,$D0,$D0
TIME_ON_GROUND dcb $30,$20,$10,$10
X_SPEED_LEFT dcb $10,$20,$30,$30
X_SPEED_RIGHT dcb $EF,$DF,$CF,$CF
TILE_MAP dcb $0E,$0E,$2E,$2E,$48
TILE_MAP dcb $8E,$8E,$AE,$AE,$C8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Homing Thwomp, by yoshicookiezeus and edited by dahnamics
;;
;; Description: A thwomp that follows Mario horizontally when on the ceiling, and spawns
;; Spinies, Green Koopas and Hopping Flames randomly when it hits the ground.
;; It has three hit points, and shell like items hurt it. It gets faster with
;; each hit and explodes like a Bob-Omb when killed. It also ends the level.
;;
;; NOTE: ONLY use this sprite in one-screen areas with "No vertical or horizontal scroll"
;; enabled!
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Homing Thwomp, by yoshicookiezeus
;;
;; Description: A thwomp that follows Mario horizontally when on the ceiling, and spawns
;; Bob-Ombs when it hits the ground. It has three hit points, and only gets
;; hurt by Bob-Omb explosions. It gets faster with each hit.
::
;; NOTE: ONLY use this sprite in one-screen areas with "No vertical or horizontal scroll"
;; enabled!
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; symbolic names for RAM addresses (don't change these)
GetSpriteClippingA = $03B69F
GetSpriteClippingB = $03B6E5
CheckForContact = $03B72B
ShowSprContactGfx = $01AB72
SPRITE_Y_SPEED = $AA
SPRITE_X_SPEED = $B6
SPRITE_STATE = $C2
SPRITE_X_POS = $E4
SPRITE_Y_POS = $D8
ORIG_Y_POS = $151C
EXPRESSION = $1594
FREEZE_TIMER = $1540
SPR_OBJ_STATUS = $1588
H_OFFSCREEN = $15A0
V_OFFSCREEN = $186C
; definitions of bits (don't change these)
IS_ON_GROUND = $04
; sprite data
SPRITE_GRAVITY = $04
MAX_Y_SPEED = $3E
RISE_SPEED dcb $F0,$E0,$D0,$D0
TIME_TO_SHAKE = $18
SOUND_EFFECT = $09
TIME_ON_GROUND dcb $30,$20,$10,$10
ANGRY_TILE = $4A
X_SPEED_LEFT dcb $10,$20,$30,$30
X_SPEED_RIGHT dcb $EF,$DF,$CF,$CF
X_OFFSET dcb $FC,$04,$FC,$04,$00
Y_OFFSET dcb $00,$00,$10,$10,$08
TILE_MAP dcb $8E,$8E,$AE,$AE,$C8
PROPERTIES dcb $03,$43,$03,$43,$03
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite init JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dcb "INIT"
LDA SPRITE_Y_POS,x
STA ORIG_Y_POS,x
LDA $E4,x
CLC
ADC #$08
STA $E4,x
RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite code JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dcb "MAIN"
PHB
PHK
PLB
JSR SPRITE_CODE_START
PLB
RTL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite main code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RETURN RTS
SPRITE_CODE_START JSR SUB_GFX
LDA $14C8,x ; return if sprite status != 8
ALIVE CMP #$08 ; \ if status != 8, return
BNE RETURN ; /
LDA $9D ; return if sprites locked
BNE RETURN
LDA $1564,x ; if invincibility timer isn't active,
BEQ JUMP ; go to hitpoints routine
DEC $1564,x ; else, decrease invincibility timer
BRA NO_JUMP
JUMP JSR HITPOINTS
NO_JUMP JSR SUB_OFF_SCREEN_X0 ; only process sprite while on screen
JSL $01A7DC ; interact with mario
LDA SPRITE_STATE,x
CMP #$01
BEQ FALLING
CMP #$02
BEQ RISING0
;-----------------------------------------------------------------------------------------
; state 0
;-----------------------------------------------------------------------------------------
HOVERING LDA V_OFFSCREEN,x ;fall if offscreen vertically
BNE SET_FALLING
LDA H_OFFSCREEN,x ;return if offscreen horizontally
BNE RETURN0
STZ SPRITE_Y_SPEED,x
JSR SUB_HORZ_POS ;determine if mario is close and act accordingly
TYA
STA $157C,x
LDY $1528,x ;check what side of sprite Mario is on
LDA $157C,x ;and set x speed accordingly
BEQ LEFT
LDA X_SPEED_RIGHT,y
STA SPRITE_X_SPEED,x
BRA CONTINUE
LEFT LDA X_SPEED_LEFT,y
STA SPRITE_X_SPEED,x
CONTINUE LDA SPRITE_X_POS,x
CLC
ADC #$08
SEC
SBC $94
CMP #$10
BCS RETURN0
SET_FALLING STZ SPRITE_X_SPEED,x
LDA #$02 ;set expression
STA EXPRESSION,x
INC SPRITE_STATE,x ;chage state to falling
LDA #$00
STA SPRITE_Y_SPEED,x ;set initial speed
RETURN0 JSL $01802A ;apply speed
RTS
RISING0 BRA RISING1
;-----------------------------------------------------------------------------------------
; state 1
;-----------------------------------------------------------------------------------------
SPRITE_TO_GEN dcb $30,$06,$B6,$B4,$1C,$10,$1F
FALLING JSL $01801A ;apply speed
LDA SPRITE_Y_SPEED,x ;increase speed if below the max
CMP #MAX_Y_SPEED
BCS DONT_INC_SPEED
ADC #SPRITE_GRAVITY
STA SPRITE_Y_SPEED,x
DONT_INC_SPEED
JSL $019138 ;interact with objects
LDA SPR_OBJ_STATUS,x ;return if not on the ground
AND #IS_ON_GROUND
BEQ RETURN68
JSR SUB_9A04 ; ?? speed related
LDA #TIME_TO_SHAKE ;shake ground
STA $1887
LDA #SOUND_EFFECT ;play sound effect
STA $1DFC
LDY $1528,x
LDA TIME_ON_GROUND,y ;set time to stay on ground
STA FREEZE_TIMER,x
INC SPRITE_STATE,x ;go to rising state
LDA $1528,x
CMP #$02
BNE SUB_BOMB_THROW
LDA $77
AND #$04
BEQ SUB_BOMB_THROW
LDA #TIME_TO_SHAKE
STA $18BD
BRA SUB_BOMB_THROW
RISING1 BRA RISING
RETURN68 RTS
SUB_BOMB_THROW LDA $15A0,x ; \ no bomb if off screen
ORA $186C,x ; |
ORA $15D0,x
BNE RETURN68
JSL $02A9DE ; \ get an index to an unused sprite slot, return if all slots full
BMI RETURN68 ; / after: Y has index of sprite being generated
LDA #$01 ; \ set sprite status for new sprite
STA $14C8,y ; /
PHX
LDA #$02
JSL RANDOM
TAX
LDA SPRITE_TO_GEN,x ; \ set sprite number for new sprite
PLX
STA $9E,y
LDA $E4,x ; \ set position of spawned sprite
STA $E4,y ; |
LDA $D8,x ; |
CLC ; |
ADC #$10 ; |
STA $D8,y ; |
LDA $14D4,x ; |
STA $14D4,y ; |
LDA $14E0,X ; |
STA $14E0,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
PLX ; /
PHY
LDA $157C,x
TAY
LDA #$00
PLY
STA $B6,y
LDA #$00
STA $AA,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
;-----------------------------------------------------------------------------------------
; state 2
;-----------------------------------------------------------------------------------------
RISING LDA FREEZE_TIMER,x ;if we're still waiting on the ground, return
BNE RETURN2
STZ EXPRESSION,x ;reset expression
JSL $019138 ;interact with objects
LDA SPR_OBJ_STATUS,x ;check if the sprite is in original position
AND #$08
BEQ RISE
STZ SPRITE_STATE,x ;reset state to hovering
RTS
RISE LDY $1528,x
LDA RISE_SPEED,y ;set rising speed and apply it
STA SPRITE_Y_SPEED,x
JSL $01801A
RETURN2 RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; graphics routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SUB_GFX JSR GET_DRAW_INFO
LDA EXPRESSION,x
STA $02
PHX
LDX #$03
CMP #$00
BEQ LOOP_START
INX
LOOP_START LDA $00
CLC
ADC X_OFFSET,x
STA $0300,y
LDA $01
CLC
ADC Y_OFFSET,x
STA $0301,y
LDA PROPERTIES,x
ORA $64
STA $0303,y
LDA TILE_MAP,x
CPX #$04
BNE NORMAL_TILE
PHX
LDX $02
CPX #$02
BNE NOT_ANGRY
LDA #ANGRY_TILE
NOT_ANGRY PLX
NORMAL_TILE STA $0302,y
INY
INY
INY
INY
DEX
BPL LOOP_START
PLX
LDY #$02 ; \ 460 = 2 (all 16x16 tiles)
LDA #$04 ; | A = (number of tiles drawn - 1)
JSL $01B7B3 ; / don't draw if offscreen
RTS ; return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; speed related
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SUB_9A04 LDA SPR_OBJ_STATUS,x
BMI THWOMP_1
LDA #$00
LDY $15B8,x
BEQ THWOMP_2
THWOMP_1 LDA #$18
THWOMP_2 STA SPRITE_Y_SPEED,x
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Be killed by shells
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HITPOINTS ;TXA ; \ Process every 4 frames
;EOR $13 ; |
;AND #$03 ; |
;BNE RETURN_BOB ; /
LDY #$09 ; \ Loop over sprites:
KILLED_X_SPEED:
dcb $FF,$00
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 #$20 ; Set stunned timer
STA $1564,x
;JSL $019138 ;interact with objects
INC $1528,x
LDA $1528,x
cmp #$04
bcc Return3
LDA #$0D ; \ turn sprite
STA $9E,x ; / into bob-omb
JSL $07F7D2 ; reset sprite tables
LDA #$08 ; \ sprite status:
STA $14C8,x ; / normal
LDA #$01 ; \ make it
STA $1534,x ; / explode
LDA #$30 ; \ set time for
STA $1540,x ; / explosion
LDA #$09 ; \ play sound
STA $1DFC ; / effect
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
;###############################################################################################
;###############################################################################################
;###############################################################################################
; ROUTINES FROM THE LIBRARY ARE PASTED BELOW
; You should never have to modify this code
;###############################################################################################
;###############################################################################################
;###############################################################################################
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_HORZ_POS
; This routine determines which side of the sprite Mario is on. It sets the Y register
; to the direction such that the sprite would face Mario
; It is ripped from $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 SPR_L16 ;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
SPR_L16 RTS ;A:25FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:1214 VC:097 00 FL:31642
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_OFF_SCREEN
; This subroutine deals with sprites that have moved off screen
; It is adapted from the subroutine at $01AC0D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SPR_T12 dcb $40,$B0
SPR_T13 dcb $01,$FF
SPR_T14 dcb $30,$C0,$A0,$C0,$A0,$F0,$60,$90 ;bank 1 sizes
dcb $30,$C0,$A0,$80,$A0,$40,$60,$B0 ;bank 3 sizes
SPR_T15 dcb $01,$FF,$01,$FF,$01,$FF,$01,$FF ;bank 1 sizes
dcb $01,$FF,$01,$FF,$01,$00,$01,$FF ;bank 3 sizes
SUB_OFF_SCREEN_X1 LDA #$02 ; \ entry point of routine determines value of $03
BRA STORE_03 ; | (table entry to use on horizontal levels)
SUB_OFF_SCREEN_X2 LDA #$04 ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X3 LDA #$06 ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X4 LDA #$08 ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X5 LDA #$0A ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X6 LDA #$0C ; |
BRA STORE_03 ; |
SUB_OFF_SCREEN_X7 LDA #$0E ; |
STORE_03 STA $03 ; |
BRA START_SUB ; |
SUB_OFF_SCREEN_X0 STZ $03 ; /
START_SUB JSR SUB_IS_OFF_SCREEN ; \ if sprite is not off screen, return
BEQ RETURN_35 ; /
LDA $5B ; \ goto VERTICAL_LEVEL if vertical level
AND #$01 ; |
BNE VERTICAL_LEVEL ; /
LDA SPRITE_Y_POS,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_35 ; /
LDA $13 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0756 VC:176 00 FL:205
AND #$01 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0780 VC:176 00 FL:205
ORA $03 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0796 VC:176 00 FL:205
STA $01 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0820 VC:176 00 FL:205
TAY ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0844 VC:176 00 FL:205
LDA $1A ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0858 VC:176 00 FL:205
CLC ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0882 VC:176 00 FL:205
ADC SPR_T14,y ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0896 VC:176 00 FL:205
ROL $00 ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizcHC:0928 VC:176 00 FL:205
CMP $E4,x ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:0966 VC:176 00 FL:205
PHP ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:0996 VC:176 00 FL:205
LDA $1B ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizCHC:1018 VC:176 00 FL:205
LSR $00 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdiZCHC:1042 VC:176 00 FL:205
ADC SPR_T15,y ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizcHC:1080 VC:176 00 FL:205
PLP ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F0 P:eNvMXdizcHC:1112 VC:176 00 FL:205
SBC $14E0,x ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1140 VC:176 00 FL:205
STA $00 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1172 VC:176 00 FL:205
LSR $01 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1196 VC:176 00 FL:205
BCC SPR_L31 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1234 VC:176 00 FL:205
EOR #$80 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1250 VC:176 00 FL:205
STA $00 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1266 VC:176 00 FL:205
SPR_L31 LDA $00 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1290 VC:176 00 FL:205
BPL RETURN_35 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1314 VC:176 00 FL:205
ERASE_SPRITE LDA $14C8,x ; \ if sprite status < 8, permanently erase sprite
CMP #$08 ; |
BCC KILL_SPRITE ; /
LDY $161A,x ;A:FF08 X:0007 Y:0001 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1108 VC:059 00 FL:2878
CPY #$FF ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1140 VC:059 00 FL:2878
BEQ KILL_SPRITE ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1156 VC:059 00 FL:2878
LDA #$00 ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1172 VC:059 00 FL:2878
STA $1938,y ;A:FF00 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZcHC:1188 VC:059 00 FL:2878
KILL_SPRITE STZ $14C8,x ; erase sprite
RETURN_35 RTS ; return
VERTICAL_LEVEL LDA $167A,x ; \ if "process offscreen" flag is set, return
AND #$04 ; |
BNE RETURN_35 ; /
LDA $13 ; \
LSR A ; |
BCS RETURN_35 ; /
LDA $E4,x ; \
CMP #$00 ; | if the sprite has gone off the side of the level...
LDA $14E0,x ; |
SBC #$00 ; |
CMP #$02 ; |
BCS ERASE_SPRITE ; / ...erase the sprite
LDA $13 ;A:0000 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:1218 VC:250 00 FL:5379
LSR A ;A:0016 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1242 VC:250 00 FL:5379
AND #$01 ;A:000B X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1256 VC:250 00 FL:5379
STA $01 ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1272 VC:250 00 FL:5379
TAY ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1296 VC:250 00 FL:5379
LDA $1C ;A:001A X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0052 VC:251 00 FL:5379
CLC ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0076 VC:251 00 FL:5379
ADC SPR_T12,y ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0090 VC:251 00 FL:5379
ROL $00 ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:enVMXdizCHC:0122 VC:251 00 FL:5379
CMP SPRITE_Y_POS,x ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0160 VC:251 00 FL:5379
PHP ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0190 VC:251 00 FL:5379
LDA.W $001D ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F2 P:eNVMXdizcHC:0212 VC:251 00 FL:5379
LSR $00 ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdiZcHC:0244 VC:251 00 FL:5379
ADC SPR_T13,y ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdizCHC:0282 VC:251 00 FL:5379
PLP ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:envMXdiZCHC:0314 VC:251 00 FL:5379
SBC $14D4,x ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0342 VC:251 00 FL:5379
STA $00 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0374 VC:251 00 FL:5379
LDY $01 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0398 VC:251 00 FL:5379
BEQ SPR_L38 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0422 VC:251 00 FL:5379
EOR #$80 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0438 VC:251 00 FL:5379
STA $00 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0454 VC:251 00 FL:5379
SPR_L38 LDA $00 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0478 VC:251 00 FL:5379
BPL RETURN_35 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0502 VC:251 00 FL:5379
BMI ERASE_SPRITE ;A:8AFF X:0002 Y:0000 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0704 VC:184 00 FL:5490
SUB_IS_OFF_SCREEN LDA H_OFFSCREEN,x ; \ if sprite is on screen, accumulator = 0
ORA V_OFFSCREEN,x ; |
RTS ; / return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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 dcb $0C,$1C
SPR_T2 dcb $01,$02
GET_DRAW_INFO STZ V_OFFSCREEN,x ; reset sprite offscreen flag, vertical
STZ H_OFFSCREEN,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 H_OFFSCREEN,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 SPRITE_Y_POS,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 V_OFFSCREEN,x ; | (vert offscreen)
ORA SPR_T2,y ; |
STA V_OFFSCREEN,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 SPRITE_Y_POS,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 ; /
EXTRA_BITS = $7FAB10
NEW_SPRITE_NUM = $7FAB9E ;08 bytes custom sprite number
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 Lemmy's stun duration
Lemmy_Hits = $05 ; This is how many hits it takes to kill Lemmy (default == 3)
RAM_HitCount = $1534
SPRITE_TO_GEN dcb $4C,$4C,$4C
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
X_SPEED dcb $F8,$F8,$08,$08 ;rest at bottom, forward speed, rest at top, backwards speed
TIME_IN_POS dcb $37,$18,$37,$18 ;moving forward, rest, moving backwards, rest ($48,$10,$48,$10)
TIME_TILL_THROW dcb $68,$69
STAR INC RAM_ThrowTimer,x
RETURN RTS
START_HB_CODE JSR SUB_GFX ; draw hammer bro gfx
LDA $14C8,x ; \ if hammer bro status != 8...
CMP #$02 ; } ... not (killed with spin jump [4] or star[2])
BEQ STAR
CMP #$08
BNE RETURN ; / ... return
LDA $9D ; \ if sprites locked...
BNE RETURN ; / ... return
;JSR SUB_GET_DIR ; \ always face mario
;TYA ; |
;STA $157C,x ; /
JSR SUB_OFF_SCREEN_HB ; only process hammer bro while on screen
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 JUMP_TIMER,x
CMP #$28 ; | just go to normal walking code
BCS WALK_BIRDO ; /
LDA Invuln_Timer,x
CMP #$00
BNE WALK_BIRDO
LDA JUMP_TIMER,x
CMP #$21
BNE NO_JUMP2
LDA $1570,x
LSR A
AND #01
BEQ NO_JUMP2
;STZ $B6,x ; x speed = 0
LDA #$D0 ; \ y speed
STA $AA,x ; /
BRA APPLY_SPEED
NO_JUMP2 CMP #$00
BNE WALK_BIRDO
LDA #$7F
STA JUMP_TIMER,x
WALK_BIRDO LDA Invuln_Timer,x ; \ If in stunned state...
CMP #$00 ; |
BEQ Walk_Normal ; |
STZ $B6,x ; | ...halt motion...
INC $1540,x ; | ...and freeze movement timer by incrementing it.
BRA APPLY_SPEED ; /
Walk_Normal:
LDA $151C,x ;
TAY ;
LDA $1540,x ;
BEQ CHANGE_SPEED ;
LDA X_SPEED,y ; | set y speed
STA $B6,x ; /
BRA APPLY_SPEED
CHANGE_SPEED LDA TIME_IN_POS,y ;A:0001 X:0007 Y:0000 D:0000 DB:01 S:01F5 P:envMXdiZCHC:0654 VC:057 00 FL:24235
STA $1540,x ;A:0020 X:0007 Y:0000 D:0000 DB:01 S:01F5 P:envMXdizCHC:0686 VC:057 00 FL:24235
LDA $151C,x
INC A
AND #$03
STA $151C,x
APPLY_SPEED JSL $01802A ; update position based on speed values
LDA Invuln_Timer,x ; \
CMP #$00 ; | Ignore if Lemmy 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 DONT_CHANGE_DIR ; |
LDA $151C,x
INC A
AND #$03
STA $151C,x
DONT_CHANGE_DIR JSL $018032 ; interact with other sprites
JSL $01A7DC ; check for mario/hammer bro contact
BCC NO_CONTACT ; No Contact
LDA $1490 ; \ if mario star timer > 0 ...
BNE HAS_STAR ; / ... goto HAS_STAR
NO_CONTACT JSR KILL_BOOMERANGS
RTS ; return
KILL_BOOMERANGS
RTS
HAS_STAR LDA #$02 ; \ sprite status = 2 (being killed by star)
STA $14C8,x ; /
STZ $B6 ; Freeze X speed
LDA #$D0 ; \ set y speed
STA $AA,x ; /
;JSR SUB_HORZ_POS ; get new sprite direction
;LDA KILLED_X_SPEED,y ; \ set x speed based on sprite 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 #$20 ; \ sound effect
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 $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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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 $10,$EF
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 #$30 ; Set stunned timer
STA $1564,x
INC $1528,x
LDA $1528,x
cmp #Lemmy_Hits
bcc Return3
LDA #$02 ; Kill Lemmy
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