;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Spike, by mikeyk
;;
;; Uses first extra bit: YES
;; If the fitrt extra bit is set, the sprite generated is controlled by BallSpriteNum
;; below.  This is so different color spikes can share the same ball sprite.
;; If the bit is not set, the ball must be the next sprite in the sprite list.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	UpdateSpritePos = $01802A  
	SprSprInteract = $018032   
	MarioSprInteract = $01A7DC 
	FinishOAMWrite = $01B7B3
	FindFreeSlotLowPri = $02A9DE
	InitSpriteTables = $07F7D2
	InitCustomSprTables = $0187A7
	GetSpriteClippingA = $03B69F
	CheckForContact = $03B72B	
	GetRand  = $01ACF9
	
	ExtraProperty1 = $7FAB28
        NewSpriteNum = $7FAB9E
        ExtraBits = $7FAB10	
	
	BallDisplacement = $0E
	BallTile = $A4
	Timing1 = $10	    	   ; Paused after throwing    ;10
	Timing2 = Timing1+$0C      ; Holding ball above head	;0c
	Timing3 = Timing2+$0A 	   ; Retrieving ball frame 2	;0a
	Timing4 = Timing3+$08  	   ; Retrieving ball frame 1	;08
	TimeToPause = Timing4+$0c  ; Paused before throwing	;0c
	MinTimeToWalk = $A0
	BallSpriteNum = $41 	   ; Sprite number of Spike's Ball (Only used if first extra bit is set)

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

        dcb "INIT"
	LDA #$01
	STA $151C,x
        JSR SubHorzPos
        TYA
        STA $157C,x
	JSR SetWalkTime
        RTL     

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

        dcb "MAIN"
	PHB        
        PHK        
        PLB
	CMP #$02
	BEQ Killed
	CMP #$08
	BNE SkipMain
        JSR MainSub
        PLB        
        RTL        

Killed:	
	LDY $15EA,x
	LDA #$A0
	STA $0302,y
SkipMain:		
	PLB        
        RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main sprite routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Return:
	RTS
MainSub:
	LDA $1656,x		; Can be stomped on
	ORA #$10
	STA $1656,x
	LDA $1662,x		; 1 tile high
	AND #$C0		
	STA $1662,x
	
	JSR SubGfx
	LDA $9D
	BNE Return
	JSR SubOffScreen

	INC $1570,x
	
	LDA $C2,x
	BEQ WalkingState
	
ThrowingState:
	LDA $1540,x
	CMP #Timing1
	BNE NoThrow
	JSR GenerateSprite
	;; 	LDA #$F0
	;; 	STA $AA,x
	;; 	LDY $157C,x
	;; 	LDA RecoilSpeedX,y
	;; 	STA $B6,x
NoThrow:
	JSR MaybeFaceMario
	
	JSL $01802A             ; update position based on speed values
        JSL $018032             ; interact with other sprites
	LDA $1656,x
	PHA
	AND #$EF
	STA $1656,x
	JSL $01A7DC             ; Interact with Mario
	PLA
	STA $1656,x
	
	LDA $1540,x
	BNE Return2
	STA $C2,x
	JSR SetWalkTime
Return2:	
	RTS                     ; Return
	
RecoilSpeedX:
	dcb $FB,$05
SpeedX:
	dcb $08,$F8,$0C,$F4
	
WalkingState:	
	LDA $1588,x             ; If sprite is in contact with a wall,
        AND #$03                
        BEQ NoWallContact	;   change direction
        JSR ChangeDirection
NoWallContact:

	JSR MaybeStayOnLedges

	LDA $1588,x             ; if on the ground, reset the turn counter
        AND #$04
        BEQ NotOnGround
	STZ $AA,x
	STZ $151C,x		; Reset turning flag (used if sprite stays on ledges)
	JSR MaybeFaceMario
	JSR MaybeJumpShells
NotOnGround:	

	LDY $157C,x             ; Set x speed based on direction
	LDA ExtraProperty1,x
	AND #$01
	BEQ NoFastSpeed		; Increase speed if bit is set
	INY
	INY
NoFastSpeed:
        LDA SpeedX,y           
        STA $B6,x

	JSL $01802A             ; update position based on speed values
        JSL $018032             ; interact with other sprites
	LDA $1656,x
	PHA
	AND #$EF
	STA $1656,x
	JSL $01A7DC             ; Interact with Mario
	PLA
	STA $1656,x

	LDA $1588,x
	AND #$04
	BEQ Return1
	LDA $1540,x
	BNE Return1
	INC $C2,x
	STZ $B6,x
	STZ $AA,x
	;; 	LDA #$FF
	;; 	STA $1528,x
	LDA #TimeToPause
	STA $1540,x

Return1:	
	RTS                     ; Return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MaybeStayOnLedges:	
	LDA ExtraProperty1,x	; Stay on ledges if bit is set
	AND #$02                
	BEQ NoFlipDirection
	LDA $1588,x             ; If the sprite is in the air
	ORA $151C,x             ;   and not already turning
	BNE NoFlipDirection
	JSR FlipDirection	;   flip direction
        LDA #$01                ;   set turning flag
	STA $151C,x    
NoFlipDirection:
	RTS
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
MaybeFaceMario:
	;LDA ExtraProperty1,x	; Face Mario if bit is set
	AND #$04
	BEQ Return4	
	LDA $1570,x
	AND #$2F
	BNE Return4
	JSR SubHorzPos
        TYA
        STA $157C,x
Return4:	
	RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
MaybeJumpShells:
	LDA ExtraProperty1,x	; Face Mario if bit is set
	AND #$08
	BEQ Return4
	TXA                       ; \ Process every 4 frames 
        EOR $13                   ;  | 
        AND #$03		  ;  | 
        BNE Return0188AB          ; / 
        LDY #$09		  ; \ Loop over sprites: 
JumpLoopStart:
	LDA $14C8,Y               ;  | 
        CMP #$0A       		  ;  | If sprite status = kicked, try to jump it 
        BEQ HandleJumpOver	  ;  | 
JumpLoopNext:
	DEY                       ;  | 
        BPL JumpLoopStart         ; / 
Return0188AB:
	RTS                       ; Return 

HandleJumpOver:
	LDA $00E4,Y             
        SEC                       
        SBC #$1A                
        STA $00                   
        LDA $14E0,Y             
        SBC #$00                
        STA $08                   
        LDA #$44                
        STA $02                   
        LDA $00D8,Y             
        STA $01                   
        LDA $14D4,Y             
        STA $09                   
        LDA #$10                
        STA $03                   
        JSL GetSpriteClippingA  
        JSL CheckForContact     
        BCC JumpLoopNext          ; If not close to shell, go back to main loop
	LDA $1588,x 		  ; \ If sprite not on ground, go back to main loop 
	AND #$04		  ;  |
        BEQ JumpLoopNext          ; / 
        LDA $157C,Y               ; \ If sprite not facing shell, don't jump 
        CMP $157C,X               ;  | 
        BEQ Return0188EB          ; / 
        LDA #$C0                  ; \ Finally set jump speed 
        STA $AA,X                 ; / 
	;;         STZ $163E,X             
Return0188EB:
	RTS                       ; Return
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
FlipDirection:	
	LDA $B6,x
        EOR #$FF
        INC A
        STA $B6,x
ChangeDirection:	
        LDA $157C,x
        EOR #$01
        STA $157C,x
        RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	

SetWalkTime:
	JSL GetRand
	AND #$3F
	CLC
	ADC #MinTimeToWalk
	STA $1540,x
	RTS
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Draw Sprite
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
Tiles:           	                   
	dcb $A0,$A2,$A0,$A2
	dcb $A2,$C0,$C2,$C4,$A0
		
SubGfx:
	JSL $20CA4F

	LDA $157C,x		; $02 = X flip info
	BNE StoreDirection
	LDA #$40
StoreDirection:	
	STA $02

	LDA #$01
	STA $03

	PHX
	LDA $C2,x
	BEQ WalkingGfx

ThrowingGfx:	
	LDA $1540,x
	LDX #$04
	CMP #Timing4
	BCS DrawBody
	INX
	CMP #Timing3
	BCS DrawBody
	INX
	CMP #Timing2
	BCS DrawBody
	INX
	CMP #Timing1+$01
	BCS DrawBall
	INX
	BRA DrawBody
	
WalkingGfx:	
	LDA $14			; X = Tile index
	LSR
	LSR
	LSR
	;; 	LSR
	CLC
	ADC $15E9	
	;; 	AND #$01
	AND #$03
	TAX
	BRA DrawBody

DrawBall:
	PHX
	LDX $15E9		
	LDA $1656,x		; Can't be stomped on
	AND #$EF
	STA $1656,x
	LDA $1662,x		; 2 tiles high
	ORA #$37
	STA $1662,x
	PLX
	
	INC $03

	LDA $00
        STA $0304,y

	LDA $01
	SEC
        SBC #BallDisplacement
        STA $0305,y   	

	LDA #BallTile
	STA $0306,y

	LDA #$03
        ORA $64                 ; Add in tile priority
        STA $0307,y             
	
DrawBody:	
        LDA $00               
        STA $0300,y           
        
        LDA $01               
        STA $0301,y           

	LDA Tiles,x
	STA $0302,y
	
        PLX           
        LDA $15F6,x             ; Get palette number
        ORA $02
        ORA $64                 ; Add in tile priority
        STA $0303,y             

        LDY #$02		; 16x16 tile
        LDA $03			; $03 = number of tiles drawn
        JSL FinishOAMWrite
NoDraw:	
        RTS	
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

GenerateSprite:	
	LDA $15A0,x            	; Don't generate if off screen
        ORA $186C,x            
        ORA $15D0,x		;   or being eaten
        BNE Return3

        JSL FindFreeSlotLowPri	; Y = free sprite slot
        BMI Return3

        LDA #$08  		; Status = normal
        STA $14C8,y

        PHX
	LDA ExtraBits,x
	AND #$04
	BEQ NextSprite
	LDA #BallSpriteNum
	BRA SetSprite
NextSprite:	
        LDA NewSpriteNum,x
        INC A
SetSprite:	
        TYX
        STA NewSpriteNum,x
        PLX

        LDA $E4,x		; Set X position for new sprite
        STA $00E4,y
        LDA $14E0,x
        STA $14E0,y

        LDA $D8,x		; Set Y position for new sprite
        SEC             
        SBC #BallDisplacement        
        STA $00D8,y     
        LDA $14D4,x     
        SBC #$00        
        STA $14D4,y     

        PHX                     
        TYX                     
        JSL InitSpriteTables
        JSL InitCustomSprTables
        LDA #$08		; Set custom flag
        STA ExtraBits,x
        PLX                  

        LDA $157C,x		
        STA $157C,y

	;; 	TYA			; Save index of new sprite
	;; 	STA $1528,x
	
Return3:
	RTS                   

	;; 	ThrowSprite
	;; 	LDA $1528,x
	;; 	BMI Return3
	;; 	TAY
	;; 	LDA #$01
	;; 	STA $00C2,y
	;; 	RTS
	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; routines below can be shared by all sprites.  they are ripped from SMW
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B829 - vertical mario/sprite position check - shared
; Y = 1 if mario below sprite??
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                    ;org $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
                    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 $0F                ;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 LABEL11            ;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
LABEL11             RTS                    ;A:25FF X:0007 Y:0001 D:0000 DB:03 S:01EA P:envMXdizcHC:0324 VC:085 00 FL:924



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

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