;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DKC Barrel (1.0)
; By Sonikku
; 
; The barrel object from Donkey Kong Country.
; When A or B is pressed, Mario launches in the direction that
; the sprite was facing. 
; 
; Have a BARREL of fun with this.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

	dcb "INIT"
	LDA #$01
	STA $157C,x
	STZ $C2,x
	RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main sprite JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	dcb "MAIN"
	PHB	 ; \
	PHK	 ;  | main sprite function, just calls local subroutine
	PLB	 ;  |
	JSR START_HB_CODE       ;  |
	PLB	 ;  |
	RTL	 ; /

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main sprite routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;*******The list of values below are indexed by the sprites current frame.******
MARIOSPDY	dcb $90,$D0,$90,$D0,$90,$D0,$90,$D0 ; Speed of Mario when shot vertically. 
MARIOSPDX	dcb $00,$40,$00,$D0,$00,$40,$00,$D0 ; Speed of Mario when shot horizontally. 
MARIODIR	dcb $00,$01,$00,$00,$00,$01,$00,$00 ; Direction of Mario when shot.
MARIOPOSE	dcb $0B,$0C,$0B,$0C,$0B,$0C,$0B,$0C ; Pose of Mario when shot.
;***************************************************************************************
CENTERSPD	dcb $B0,$50			; Speed at which Mario centers when touching the sprite. Changing these values not reccomended.
RETURN	RTS
START_HB_CODE	
	JSR SUB_GFX
	LDA $9D
	BNE RETURN
	JSR SUB_OFF_SCREEN_X0
	LDA $14C8,x
	CMP #$08
	BNE RETURN
	LDA $1540,x
	BNE FLYING
	JSL $01A7DC
	BCC RETURN
	LDA #$05
	STA $1497
	PHX
	LDX #$0C
LOOP	LDA $7FAB9E,x
	CMP $7FAB9E,x
	BNE DONE
	STZ $1540,x
	TXA
	BEQ DONE
	DEX
	BRA LOOP
DONE	PLX
	INC $1570,x
	LDA $1570,x
	LSR A
	LSR A
	LSR A
	AND #$07
	STA $C2,x
	LDA #$FF
	STA $78
	STZ $7D
	STZ $7B
	JSR SUB_HORZ_POS
	TYA
	LDA $7B
	CLC
	ADC CENTERSPD,y
	STA $7B
	LDA $D8,x
	SEC
	SBC #$16
	STA $96
	LDA $14D4,x
	SBC #$00
	STA $97
	LDA $16
	AND #$80
	BEQ RETURN
	STZ $140D
	LDA #$09
	STA $1DFC
	LDA #$30
	STA $1540,x
	RTS
FLYING	LDA $77
	BNE STOPFLY
	LDY $C2,x
	LDA MARIOSPDY,y
	STA $7D
	LDA MARIOSPDX,y
	STA $7B
	LDA MARIODIR,y
	STA $76
	LDA MARIOPOSE,y
	STA $72
	RTS
STOPFLY
	STZ $1540,x
	RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; graphics routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TILEMAP		dcb $80,$82,$A0,$A2
		dcb $84,$86,$A4,$A6
		dcb $80,$82,$A0,$A2
		dcb $CC,$CE,$EC,$EE
		dcb $80,$82,$A0,$A2
		dcb $84,$86,$A4,$A6
		dcb $80,$82,$A0,$A2
		dcb $CC,$CE,$EC,$EE
X_OFFSET            dcb $FF,$FF,$FF,$FF,$F8,$08,$F8,$08
Y_OFFSET            dcb $F9,$F9,$09,$09

SUB_GFX             JSR GET_DRAW_INFO       ; sets y = OAM offset
	LDA $157C,x             ; \ $02 = direction
	ASL A
	ASL A
	STA $02                 ; /     
	LDA $C2,x
	ASL A
	ASL A
	STA $03             
	
	PHX
	LDX #$03

LOOP_START          PHX
	TXA
	CLC
	ADC $02
	TAX
	LDA X_OFFSET,x
	CLC
	ADC $00                 ; \ tile x position = sprite y location ($01)
	STA $0300,y             ; /
	PLX

	LDA Y_OFFSET,x
	CLC
	ADC $01                 ; \ tile y position = sprite x location ($00)
	STA $0301,y             ; /
	
	PHX
	TXA
	CLC
	ADC $03
	TAX
	LDA TILEMAP,x
	STA $0302,y 
	PLX
	
	PHX
	LDX $15E9
	LDA $15F6,x             ; tile properties xyppccct, format
	LDX $02                 ; \ if direction == 0...
	BNE NO_FLIP             ;  |
	ORA #$40                ; /    ...flip tile
NO_FLIP             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 #$03                ;  | A = (number of tiles drawn - 1)
	JSL $01B7B3             ; / don't draw if offscreen
	RTS	 ; return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B760 - graphics routine helper - shared
; sets off screen flags and sets index to OAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	;org $03B75C

TABLE1              dcb $0C,$1C
TABLE2              dcb $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 TABLE1,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 TABLE2,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	 ; /

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; off screen processing code - shared
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	;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_X0   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_X3  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
	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 RETURN_2
ERASE_SPRITE        LDA $14C8,x             ; \ if sprite status < 8, permanently erase sprite
	CMP #$08                ; |
	BCC KILL_SPRITE         ; /
	LDY $161A,x
	CPY #$FF
	BEQ KILL_SPRITE
	LDA #$00
	STA $1938,y
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
	STA $01
	TAY
	LDA $1C
	CLC
	ADC TABLE3,y
	ROL $00
	CMP $D8,x
	PHP
	LDA.W $001D
	LSR $00
	ADC TABLE6,y
	PLP
	SBC $14D4,x
	STA $00
	LDY $01
	BEQ LABEL22
	EOR #$80
	STA $00
LABEL22             LDA $00
	BPL RETURN_2
	BMI ERASE_SPRITE

SUB_IS_OFF_SCREEN   LDA $15A0,x             ; \ if sprite is on screen, accumulator = 0 
	ORA $186C,x             ; |  
	RTS	 ; / return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
