;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Boss Bass
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; symbolic names for RAM addresses
RAM_SpriteDir = $157C
RAM_NoJumpTimer = $1504
RAM_StateTimer = $1540
RAM_SpriteState = $C2
ExecutePtr = $0086DF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; INIT and MAIN routines
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DCB "INIT"
LDA $D8,x
ORA #$08
STA $D8,x
STZ RAM_SpriteState,x
JSR SubHorzPos
TYA
STA RAM_SpriteDir,x
LDA TimeInState
STA RAM_StateTimer,x
RTL
DCB "MAIN"
PHB
PHK
PLB
JSR DecrementTimers
JSR BossBassMain
PLB
RTL
DecrementTimers:
LDA $14C8,x
CMP #$08
BNE DoneDec
LDA $9D
BNE DoneDec
LDA RAM_NoJumpTimer,x
BEQ DoneDec
DEC RAM_NoJumpTimer,x
DoneDec:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sprite Main
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BossBassMain:
JSR SubGfx ; Draw sprite
LDA $1528,x ; If the eaten flag is set:
BEQ NotEaten
LDA #$03 ; Make Mario invisible
STA $78
NotEaten:
LDA $14C8,X ; \ Return if status != Normal
CMP #$08 ; |
BNE Return ; /
LDA $9D ; \ Return if sprites are locked
BNE Return ; /
;; JSR SubOffScreen ; Only process while on screen
JSR SetUpMovement
JSL $018022 ; Update x position, no gravity
JSL $01801A ; Update y position, no gravity
JSL $01A7DC ; Handle Mario/sprite contact
BCC Return ; Return if no contact
JSR HandleContact
Return:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Handle movement
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TimeInState:
dcb $11,$28
SwimSpeedX:
DCB $31,$CF
JumpProximity:
DCB $25,$DC
SetUpMovement:
LDA RAM_SpriteState,x
BNE Jumping
Swimming:
LDA RAM_SpriteDir,x
LDY RAM_StateTimer,x
BNE SkipFlipDireciton
EOR #$01
STA RAM_SpriteDir,x
LDA #$04
STA RAM_NoJumpTimer,x
LDA #$1C
STA RAM_StateTimer,x
SkipFlipDireciton:
LDY RAM_SpriteDir,x
LDA SwimSpeedX,y
STA $B6,x
JSR SubHorzPos ;0 if traveling towards mario
TYA
EOR RAM_SpriteDir,x
BNE SkipSetTimerMax
LDA RAM_NoJumpTimer,x ; Don't jump if timer is set
BNE NoIncState
JSR SubVertPos
CPY #$01 ; Doesn't jump if above Mario
BNE NoIncState
LDA $0F
CMP #$B0
BCC NoIncState
JSR SubHorzPos
CPY #$00
BEQ Less20
GreatE0:
LDA $0F
CMP #$F0
BCS NoIncState
CMP #$D0
BCC NoIncState
BRA IncState
Less20:
LDA $0F
CMP #$10
BCC NoIncState
CMP #$30
BCS NoIncState
IncState:
INC RAM_SpriteState,x
JSR SetStateTimer
LDA #$D9
STA $AA,x
RTS
NoIncState:
LDA #$20
STA RAM_StateTimer,x
SkipSetTimerMax:
STZ $AA,x
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
JumpAccelX:
dcb $01,$FF
Jumping:
LDA RAM_StateTimer,x ; Go back to swimming state if time
BEQ GotoSwim
LDA $AA,x ; Adjust Y speed
CLC
ADC #$02
STA $AA,x
LDA RAM_SpriteDir,x ; Get index for X acceleration
LDY $00AA,x
BPL NoAdjustIndex
EOR #$01
NoAdjustIndex:
TAY
LDA $B6,x ; Adjust X speed
CLC
ADC JumpAccelX,Y
STA $B6,x
Return2:
RTS
GotoSwim:
STZ RAM_SpriteState,x
JSR SetStateTimer
STZ $AA,x
LDA #$10
STA RAM_NoJumpTimer,x
RTS
HandleContact:
LDA RAM_SpriteState,x ; Only hurt Mario when jumping
BEQ Return2
LDA.B #$09 ; Set death animation
STA $71
STA $1DFB ; Set death music
LDA.B #$30 ; Set time until we return to the OW
STA $1496
STA $1528,x ; Set eaten flag
Return2:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetStateTimer:
LDY RAM_SpriteState,x
LDA TimeInState,Y
STA RAM_StateTimer,x
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Graphics Routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpriteTiles: dcb $46,$47,$2B,$49,$59,$FF,$FF,$FF
dcb $46,$47,$2B,$4A,$5A,$FF,$FF,$FF
dcb $46,$47,$2B,$4D,$7F,$FF,$FF,$FF
dcb $46,$47,$04,$4D,$7F
SpriteTileSize: dcb $02,$02,$02,$00,$00
;; SpriteTileDispY: dcb $E8,$E8,$F8,$F8,$00
SpriteTileDispY: dcb $F0,$F0,$00,$00,$08
SpriteTileDispX: dcb $00,$08,$00,$10,$10
dcb $00,$F8,$00,$F8,$F8
SpriteGfxFlip: dcb $00,$40
SubGfx:
JSR GetDrawInfo
PHY
LDA $15F6,X ; $02 = Palette info
LDY RAM_SpriteDir,X
BNE NoFlip
ORA #$40
NoFlip:
STA $02
LDA #$03 ; $03 = Tilemap offset
LDY $C2,x
BNE StoreFrame
LDA $14
LSR
AND #$02
StoreFrame:
ASL
ASL
ASL
STA $03
PLY
PHX ; Push sprite index
LDX #$04 ; Draw 5 tiles
GfxLoopStart:
PHX ; Push tile number
PHX ; Push tile number
LDA $02
AND #$40
BEQ NoAdjust
TXA
CLC
ADC #$05
TAX
NoAdjust:
LDA $00
CLC
ADC SpriteTileDispX,X
STA $0300,Y
PLX ; Pull tile number
LDA $01
CLC
ADC SpriteTileDispY,X
STA $0301,Y
PHX ; Push tile number
TXA
CLC
ADC $03
TAX
LDA SpriteTiles,X
STA $0302,Y
PLX ; Pull tile number
LDA $02
ORA $64
STA $0303,Y
LDA SpriteTileSize,X
PHA
TYA
LSR
LSR
TAX
PLA
STA $0460,X
PLX ; Pull tile number
INY ; Adjust index into the OAM
INY
INY
INY
DEX
BPL GfxLoopStart
PLX ; Pull sprite index
LDY #$FF ; We already wrote to $0460,Y
LDA #$04 ; We wrote 5 tiles
JSL $01B7B3
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DATA_03B75C: dcb $0C,$1C
DATA_03B75E: dcb $01,$02
GetDrawInfo: 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 ADDR_03B774 ; |
INC $15A0,X ; /
ADDR_03B774: LDA $14E0,X ; \
XBA ; | Mark sprite invalid if far enough off screen
LDA $E4,X ; |
REP #$20 ; Accum (16 bit)
SEC ; |
SBC $1A ; |
CLC ; |
ADC.W #$0040 ; |
CMP.W #$0180 ; |
SEP #$20 ; Accum (8 bit)
ROL ; |
AND.B #$01 ; |
STA $15C4,X ; |
BNE ADDR_03B7CF ; /
LDY.B #$00 ; \ set up loop:
LDA $1662,X ; |
AND.B #$20 ; | if not smushed (1662 & 0x20), go through loop twice
BEQ ADDR_03B79A ; | else, go through loop once
INY ; /
ADDR_03B79A: LDA $D8,X ; \
CLC ; | set vertical offscree
ADC DATA_03B75C,Y ; |
PHP ; |
CMP $1C ; | (vert screen boundry)
ROL $00 ; |
PLP ; |
LDA $14D4,X ; |
ADC.B #$00 ; |
LSR $00 ; |
SBC $1D ; |
BEQ ADDR_03B7BA ; |
LDA $186C,X ; | (vert offscreen)
ORA DATA_03B75E,Y ; |
STA $186C,X ; |
ADDR_03B7BA: DEY ; |
BPL ADDR_03B79A ; /
LDY $15EA,X ; get offset to sprite OAM
LDA $E4,X ; \
SEC ; |
SBC $1A ; |
STA $00 ; / $00 = sprite x position relative to screen boarder
LDA $D8,X ; \
SEC ; |
SBC $1C ; |
STA $01 ; / $01 = sprite y position relative to screen boarder
RTS ; Return
ADDR_03B7CF: PLA ; \ Return from *main gfx routine* subroutine...
PLA ; | ...(not just this subroutine)
RTS ; /
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SubHorzPos:
LDY #$00
LDA $94
SEC
SBC $E4,x
STA $0F
LDA $95
SBC $14E0,x
BPL HorzIncY
INY
HorzIncY:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SubVertPos:
LDY #$00
LDA $96
SEC
SBC $D8,x
STA $0F
LDA $97
SBC $14D4,x
BPL VertIncY
INY
VertIncY:
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_OFF_SCREEN
; This subroutine deals with sprites that have moved off screen
; It is adapted from the subroutine at $01AC0D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DATA_01AC0D: dcb $40,$B0
DATA_01AC0F: dcb $01,$FF
DATA_01AC11: dcb $30,$C0
DATA_01AC19: dcb $01,$FF
SubOffScreen: STZ $03
JSR IsSprOnScreen ; \ if sprite is not off screen, return
BEQ Return01ACA4 ; /
LDA $5B ; \ vertical level
AND #$01 ; |
BNE VerticalLevel ; /
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 OffScrEraseSprite ; / ...erase the sprite
LDA $167A,X ; \ if "process offscreen" flag is set, return
AND #$04 ; |
BNE Return01ACA4 ; /
LDA $13
AND #$01
STA $01
TAY
LDA $1A
CLC
ADC DATA_01AC11,Y
ROL $00
CMP $E4,X
PHP
LDA $1B
LSR $00
ADC DATA_01AC19,Y
PLP
SBC $14E0,X
STA $00
LSR $01
BCC ADDR_01AC7C
EOR #$80
STA $00
ADDR_01AC7C: LDA $00
BPL Return01ACA4
OffScrEraseSprite: LDA $14C8,X ; \ If sprite status < 8, permanently erase sprite
CMP #$08 ; |
BCC OffScrKillSprite ; /
LDY $161A,X
CPY #$FF
BEQ OffScrKillSprite
LDA #$00
STA $1938,Y
OffScrKillSprite: STZ $14C8,X ; Erase sprite
Return01ACA4: RTS
VerticalLevel: LDA $167A,X ; \ If "process offscreen" flag is set, return
AND #$04 ; |
BNE Return01ACA4 ; /
LDA $13 ; \
LSR ; |
BCS Return01ACA4 ; /
LDA $E4,X ; \
CMP #$00 ; | If the sprite has gone off the side of the level...
LDA $14E0,X ; |
SBC #$00 ; |
CMP #$02 ; |
BCS OffScrEraseSprite ; / ...erase the sprite
LDA $13
LSR
AND #$01
STA $01
TAY
LDA $1C
CLC
ADC DATA_01AC0D,Y
ROL $00
CMP $D8,X
PHP
LDA $001D
LSR $00
ADC DATA_01AC0F,Y
PLP
SBC $14D4,X
STA $00
LDY $01
BEQ ADDR_01ACF3
EOR #$80
STA $00
ADDR_01ACF3: LDA $00
BPL Return01ACA4
BMI OffScrEraseSprite
IsSprOnScreen: LDA $15A0,X ; \ A = Current sprite is offscreen
ORA $186C,X ; /
RTS ; Return
Ich wollt es so machen das er nach ein Paar Sekunden wieder erscheint wenn man ihn getötet hat egal wo man in dem Level ist. So wie in smb3.
Weil momentan macht er zwar alles was er soll, aber wenn man ihn am Anfang mit einer Feuerblume oder einem Panzer killt ist das restliche Level ganz schön einfach.