;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boomerang Brother, by mikeyk
;;
;; Description: Similar to his role in SMB3, this guy throws boomerangs at Mario. 
;;
;; BIG FAT NOTE: This sprite depends on the boomerang sprite.  Make sure you insert the
;; boomerang as the very next sprite.  (ex. If this is sprite 1B, make the boomerang 1C)
;;
;; Uses first extra bit: NO
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

incsrc subroutinedefs_trasm.asm

                    EXTRA_BITS = $7FAB10
                    NEW_SPRITE_NUM = $7FAB9E    ;08 bytes   custom sprite number

                    JUMP_TIMER = $163E
	RAM_ThrowTimer = $1504

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


TILEMAP		    dcb $6B,$44,$44,$00
		    dcb $6B,$42,$42,$00
        	    dcb $6D,$46,$46,$00
		    dcb $6D,$48,$48,$00

HORZ_DISP           dcb $00,$00,$00
                    dcb $00,$00,$00
VERT_DISP           dcb $F0,$00,$00
TILE_SIZE           dcb $02,$02,$02

PROPERTIES          dcb $40,$00             ;xyppccct format

                    BOOMERANG_TILE = $4E
		    BombTile = $29
BombBroPalette = $0D

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                    dcb "INIT"
                    JSL SubHorizPos
                    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                 

LDA $7FAB10,x
AND #$04
BEQ EndInit
LDA #BombBroPalette
STA $15F6,x
EndInit:

                    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 = $22      ;time to display the boomerang before it is thrown

X_SPEED             dcb $00,$F8,$00,$08     ;rest at bottom, moving up, rest at top, moving down
TIME_IN_POS         dcb $48,$10,$48,$10     ;moving up, rest at top, moving down, rest at bottom
TIME_TILL_THROW     dcb $F7,$62

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

                    JSL SubHorizPos         ; \ always face mario
                    TYA                     ;  | 
                    STA $157C,x             ; /
                    

                    JSL SubOffscreenX3   ; only process hammer bro while on screen
                    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 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 JUMP_TIMER,x
                    CMP #$21
                    BNE NO_JUMP2
                    LDA $1570,x
                    LSR A
                    AND #01
                    BEQ NO_JUMP2
                    LDA #$D0                ; \  y speed
                    STA $AA,x               ; /
                    BRA APPLY_SPEED
NO_JUMP2            CMP #$00
                    BNE WALK_BIRDO
                    LDA #$FE
                    STA JUMP_TIMER,x

WALK_BIRDO          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 $81802A             ; update position based on speed values

                    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 $818032             ; interact with other sprites               
                    JSL $81A7DC             ; check for mario/hammer bro contact

NO_CONTACT          JSR KILL_BOOMERANGS
                    RTS                     ; return



KILL_BOOMERANGS     




                    RTS


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; hammer routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

X_OFFSET            dcb $F9,$07
X_OFFSET2           dcb $FF,$00

RETURN68            RTS     
SUB_HAMMER_THROW    LDA $15A0,x             ; \ no egg if off screen
                    ORA $186C,x             ;  |
                    ORA $15D0,x
                    BNE RETURN68
                    
                    JSL $82A9DE             ; \ 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             ; /

LDA $7FAB10,x
AND #$04
BNE ThrowBomb

                    PHX
                    LDA NEW_SPRITE_NUM,x
                    INC A
                    TYX
                    STA NEW_SPRITE_NUM,x
                    PLX

                    PHY
                    LDA $157C,x
                    TAY
                    LDA $E4,x               ; \ set x position for new sprite
                    CLC
                    ADC X_OFFSET,y
                    PLY
                    STA $00E4,y

                    PHY
                    LDA $157C,x
                    TAY
                    LDA $14E0,x             ;  |
                    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 $87F7D2             ;  | ...and loads in new values for the 6 main sprite tables
                    JSL $8187A7             ;  get table values for custom sprite
                    LDA #$08
                    STA EXTRA_BITS,x
                    PLX                     ; / 

                    LDA $157C,x
                    STA $157C,y
                    
                    LDA #$4E                    ; \ set timer until change direction
                    STA $1540,y                 ; /     
                    
RETURN67            RTS                     ; return

ThrowBomb:

PHY
LDY $157C,x
LDA $E4,x
CLC
ADC X_OFFSET,y
PLY
STA $00E4,y

PHY
LDY $157C,x
LDA $14E0,x
ADC X_OFFSET2,y
PLY
STA $14E0,y

LDA $D8,x
SEC
SBC #$0E
STA $00D8,y
LDA $14D4,x
SBC #$00
STA $14D4,y

PHX
TYX
LDA #$45
STA $7FAB9E,x
JSL $87F7D2
JSL $8187A7
LDA #$08
STA $7FAB10,x
PLX

LDA #$B8
STA $00AA,y
LDA $157C,x
LSR
LDA #$1C
BCC StoreXSpeed
EOR #$FF
INC
StoreXSpeed:
STA $00B6,y

LDA #$02
STA $1510,y
LDA #$FF
STA $187B,y
RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; graphics routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SUB_GFX             JSL GetDrawInfo       ; after: Y = index to sprite tile map ($300)
                                            ;      $00 = sprite x position relative to screen boarder 
                                            ;      $01 = sprite y position relative to screen boarder  
                    LDA $1602,x             ; \
                    ASL A                   ;  | $03 = index to frame start (frame to show * 2 tile per frame)
                    ASL A
                    STA $03                 ; /
                    LDA $157C,x             ; \ $02 = sprite direction
                    STA $02                 ; /
                    PHX                     ; push sprite index

                    LDX #$02                ; loop counter = (number of tiles per frame) - 1
LOOP_START          PHX                     ; push current tile number
                   
                    PHX
                    TXA
                    LDX $02
                    BNE NO_ADJ
                    CLC
                    ADC #$03
NO_ADJ              TAX                    
                    LDA $00                 ; \ tile x position = sprite x location ($00)
                    CLC
                    ADC HORZ_DISP,x
                    STA $0300,y             ; /                    
                    PLX
                                        
                    LDA $01                 ; \ tile y position = sprite y location ($01) + tile displacement
                    CLC                     ;  |
                    ADC VERT_DISP,x         ;  |
                    STA $0301,y             ; /
                    
                    LDA TILE_SIZE,x
                    PHX
                    PHA
                    TYA                     ; \ get index to sprite property map ($460)...
                    LSR A                   ; |    ...we use the sprite OAM index...
                    LSR A                   ; |    ...and divide by 4 because a 16x16 tile is 4 8x8 tiles
                    TAX                     ; | 
                    PLA
                    STA $0460,x             ; /  
                    PLX                  

                    TXA                     ; \ X = index to horizontal displacement
                    ORA $03                 ; / get index of tile (index to first tile of frame + current tile number)
                    TAX                     ; \ 
                    
                    LDA TILEMAP,x           ; \ store tile
                    STA $0302,y             ; / 
        
                    LDX $02                 ; \
                    LDA PROPERTIES,x        ;  | get tile properties using sprite direction
                    LDX $15E9               ;  |
                    ORA $15F6,x             ;  | get palette info
                    ORA $64                 ;  | put in level properties
                    STA $0303,y             ; / store tile properties
                    
                    PLX                     ; \ pull, X = current tile of the frame we're drawing
                    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                     ;  | go to next tile of frame and loop
                    BPL LOOP_START          ; / 

                    PLX                     ; pull, X = sprite index
                    
                    LDA RAM_ThrowTimer,x
                    CMP #$02
                    BCC NO_SHOW_HAMMER
                    CMP #30
                    BCS NO_SHOW_HAMMER
                    LDA $1602,x
                    CMP #$02
                    BCS SHOW_HAMMER_TOO
                    
NO_SHOW_HAMMER      LDY #$FF                ; \ 02, because we didn't write to 460 yet
                    LDA #$02                ;  | A = number of tiles drawn - 1
                    JSL $81B7B3             ; / don't draw if offscreen
                    RTS                     ; return

HAMMER_OFFSET       dcb $F6,$0A

SHOW_HAMMER_TOO     PHX
                    
                    LDA $00
                    LDX $02
                    CLC
                    ADC HAMMER_OFFSET,x
                    STA $0300,y
                    
                    LDA $01                 ; \ tile y position = sprite y location ($01) + tile displacement
                    CLC                     ;  |
                    ADC #$F2
                    STA $0301,y             ; /
                    
                    LDA #BOOMERANG_TILE     ; \ store tile
                    STA $0302,y             ; / 

                    PHX
                    TYA                     ; \ get index to sprite property map ($460)...
                    LSR A                   ; |    ...we use the sprite OAM index...
                    LSR A                   ; |    ...and divide by 4 because a 16x16 tile is 4 8x8 tiles
                    TAX                     ; | 
                    LDA #$02
                    STA $0460,x             ; /  
                    PLX     

                    LDA #$89 
                    CPX #$00
                    BEQ NO_FLIP_HAMMER     
                    ORA #$40
NO_FLIP_HAMMER      ORA $64                 ;  | put in level properties
                    STA $0303,y             ; / store tile properties

                    PLX
LDA $7FAB10,x
AND #$04
BEQ NoBombTile
LDA #BombTile
STA $0302,y
LDA #$07
ORA $64
STA $0303,y
NoBombTile:
                    INY                     ;  | increase index to sprite tile map ($300)...
                    INY                     ;  |    ...we wrote 1 16x16 tile...
                    INY                     ;  |    ...sprite OAM is 8x8...
                    INY                     ;  |    ...so increment 4 times

                    LDY #$FF                ; \ 02, because we didn't write to 460 yet
                    LDA #$03                ;  | A = number of tiles drawn - 1
                    JSL $81B7B3             ; / don't draw if offscreen
                    RTS                     ; return

