;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Red Piranha Plant, based on the piranha plant disassembly by mikeyk, further changed by
;; Davros.
;;
;; Description: A pipe dwelling plant that ignores Mario if he's near and goes up or down 
;; depending on the extra bit. 
;;
;; Uses first extra bit: YES
;; It will be upsidedown if the first extra bit is set.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Extra Property Byte 1
;;    Bit 0 - short stem
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                    EXTRA_BITS = $7FAB10
                    EXTRA_PROP_1 = $7FAB28

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; pirhana plant -  initialization JSL
; align sprite to middle of pipe
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                    dcb "INIT"
                    LDA $E4,x               ; \ set x position
                    CLC                     ;  |
                    ADC #$08                ;  |
                    STA $E4,x               ; /
                    DEC $D8,x               ; decrease x position (low byte)
                    LDA $D8,x               ; \
                    CMP #$FF                ;  |
                    BNE NO_DEC_HI_Y         ; /
                    DEC $14D4,x             ; decrease x position (high byte)
NO_DEC_HI_Y         RTL                     ;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite code JSL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite main code 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Y_SPEED             dcb $00,$F0,$00,$10     ; rest at bottom, moving up, rest at top, moving down
TIME_IN_POS         dcb $20,$30,$20,$30     ; moving up, rest at top, moving down, rest at bottom
TIME_IN_POS2        dcb $19,$30,$19,$30     ; moving up, rest at top, moving down, rest at bottom


SPRITE_CODE_START   LDA $64                 ; \ call gfx routine with layer priority worked in
                    PHA                     ;  |
                    LDA $15D0,x             ;  | if the sprite is being eaten...
                    BNE SET_GFX             ;  |                   
                    LDA #$10                ;  |
                    STA $64                 ;  |
SET_GFX             JSR SUB_GFX             ;  | graphics routine
                    PLA                     ;  |
                    STA $64                 ; /

OFF_SCREEN          JSR SUB_OFF_SCREEN_X3   ; only process sprite while on screen

SKIP_STATE          LDA $9D                 ; \ if sprites locked, return
                    BNE RETURN              ; /

                    INC $1570,x             ; increase number of frames    
                    LDA $1570,x             ; \ set animated tilemap
                    LSR A                   ;  |
                    LSR A                   ;  |
                    LSR A                   ;  |
                    AND #$01                ;  |
                    STA $1602,x             ; /                 
             
                    JSL $01803A  

TRASFER_STATE       LDA $C2,x               ; \ transfer sprite state into timer  
                    AND #$03                ;  |
                    TAY                     ;  |
                    LDA $1540,x             ;  |
                    BEQ STORE_STATE         ; /
  
                    LDA EXTRA_BITS,x	    ; \ flip sprite if the extra bit is set
		    AND #$04                ;  |
		    BNE UPSIDEDOWN_SPEED    ; /

                    LDA Y_SPEED,y           ; \ set y speed  
	            STA $AA,x               ; /
		    BRA UPDATE_SPEED

UPSIDEDOWN_SPEED    LDA Y_SPEED,y           ; \ set inverted y speed
                    EOR #$FF                ;  |
                    INC A                   ;  |
	            STA $AA,x               ; /
UPDATE_SPEED        JSL $01801A 	    ;
RETURN              RTS                     ; return
              
STORE_STATE         LDA $C2,x               ; \ store sprite state      
                    AND #$03                ;  |
                    STA $00                 ; /

                    LDY $00                 ; set position according to sprite state

                    LDA EXTRA_PROP_1,x      ; \ set short stem if the extra property 1 is set...
		    AND #$01                ;  |
		    BNE TIMER2              ; /    

TIMER               LDA TIME_IN_POS,y       ; \ set time in position
                    BRA STORE_TIMER         ; /

TIMER2              LDA TIME_IN_POS2,y      ; \ set time in position
STORE_TIMER         STA $1540,x             ; /
                    INC $C2,x               ; increase sprite state        
RETURN2             RTS                     ; return       


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; sprite graphics routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


TILEMAP             dcb $CE,$AC,$CE,$AE,$AC,$CE,$AE,$CE
VERT_DISP           dcb $10,$00,$10,$00,$10,$00,$10,$00
PROPERTIES          dcb $0A,$0A,$0A,$0A,$8A,$8A,$8A,$8A	


SUB_GFX             JSL $20CA4F       ; 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)
                    STA $03                 ; /
                    LDA EXTRA_BITS,x        ; \ set upsidedown tilemap if the extra bit is set...
                    AND #$04                ;  |
                    BEQ UPSIDEDOWN_GFX      ; /
                    LDA $03                 ; \ set upsidedown tilemap
                    CLC                     ;  |
                    ADC #$04                ;  |
                    STA $03                 ; /
UPSIDEDOWN_GFX      PHX                     ; push sprite index

                    LDX #$01                ; loop counter = (number of tiles per frame) - 1
LOOP_START          PHX                     ; push current tile number
                    TXA                     ; \ X = index to horizontal displacement
                    ORA $03                 ; / get index of tile (index to first tile of frame + current tile number)
FACING_LEFT         TAX                     ; 
                    
                    LDA $00                 ; \ tile x position = sprite x location ($00)
                    STA $0300,y             ; /
                    
                    LDA $01                 ; \ tile y position = sprite y location ($01) + tile displacement
                    CLC                     ;  |
                    ADC VERT_DISP,x         ;  |
                    STA $0301,y             ; /

                    LDA TILEMAP,x           ; \ store tilemap
                    STA $0302,y             ; / 
        
                    LDA PROPERTIES,x        ; \ get tile properties
	            ORA $64                 ;  |
                    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
                    LDY #$02                ; \ 02, because we didn't write to 460 yet
                    LDA #$01                ;  | A = number of tiles drawn - 1
                    JSL $01B7B3             ; / don't draw if offscreen
                    RTS                     ; return





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; AD30 - horizontal mario/sprite check
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                     
SUB_HORZ_POS1        LDY #$00                ;A:8505 X:0009 Y:0005 D:0000 DB:01 S:01ED P:envMXdizcHC:0464 VC:058 00 FL:138
                     LDA $D1                 ;A:8505 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdiZcHC:0480 VC:058 00 FL:138
                     SEC                     ;A:8500 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdiZcHC:0504 VC:058 00 FL:138
                     SBC $E4,x               ;A:8500 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdiZCHC:0518 VC:058 00 FL:138
                     STA $0F                 ;A:8550 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdizcHC:0548 VC:058 00 FL:138
                     LDA $D2                 ;A:8550 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdizcHC:0572 VC:058 00 FL:138
                     SBC $14E0,x             ;A:8500 X:0009 Y:0000 D:0000 DB:01 S:01ED P:envMXdiZcHC:0596 VC:058 00 FL:138
                     BPL TO_RIGHT            ;A:85FF X:0009 Y:0000 D:0000 DB:01 S:01ED P:eNvMXdizcHC:0628 VC:058 00 FL:138
                     INY                     ;A:85FF X:0009 Y:0000 D:0000 DB:01 S:01ED P:eNvMXdizcHC:0644 VC:058 00 FL:138
TO_RIGHT             RTS                     ;A:85FF X:0009 Y:0001 D:0000 DB:01 S:01ED P:envMXdizcHC:0658 VC:058 00 FL:138


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $B85D - off screen processing code - shared
; sprites enter at different points
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                    ;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                 ;x boundry ;A:0101 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0256 VC:090 00 FL:16953
                    CLC                     ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0280 VC:090 00 FL:16953
                    ADC TABLE4,y            ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0294 VC:090 00 FL:16953
                    ROL $00                 ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0326 VC:090 00 FL:16953
                    CMP $E4,x               ;x pos ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0364 VC:090 00 FL:16953
                    PHP                     ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0394 VC:090 00 FL:16953
                    LDA $1B                 ;x boundry hi ;A:01C0 X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNvMXdizCHC:0416 VC:090 00 FL:16953
                    LSR $00                 ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdiZCHC:0440 VC:090 00 FL:16953
                    ADC TABLE5,y            ;A:0100 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdizcHC:0478 VC:090 00 FL:16953
                    PLP                     ;A:01FF X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNvMXdizcHC:0510 VC:090 00 FL:16953
                    SBC $14E0,x             ;x pos high ;A:01FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0538 VC:090 00 FL:16953
                    STA $00                 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0570 VC:090 00 FL:16953
                    LSR $01                 ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0594 VC:090 00 FL:16953
                    BCC LABEL20             ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0632 VC:090 00 FL:16953
                    EOR #$80                ;A:01FE X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0648 VC:090 00 FL:16953
                    STA $00                 ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0664 VC:090 00 FL:16953
LABEL20             LDA $00                 ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0688 VC:090 00 FL:16953
                    BPL RETURN_2            ;A:017E X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0712 VC:090 00 FL:16953
ERASE_SPRITE        LDA $14C8,x             ; \ if sprite status < 8, permanently erase sprite
                    CMP #$08                ;  |
                    BCC KILL_SPRITE         ; /
                    LDY $161A,x             ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZCHC:0140 VC:071 00 FL:21152
                    CPY #$FF                ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizCHC:0172 VC:071 00 FL:21152
                    BEQ KILL_SPRITE         ;A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0188 VC:071 00 FL:21152
                    LDA #$00                ; \ mark sprite to come back    A:FF08 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0204 VC:071 00 FL:21152
                    STA $1938,y             ; /                             A:FF00 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdiZcHC:0220 VC:071 00 FL:21152
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                ;A:0227 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0228 VC:112 00 FL:1142
                    STA $01                 ;A:0201 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0244 VC:112 00 FL:1142
                    TAY                     ;A:0201 X:0006 Y:00EC D:0000 DB:03 S:01ED P:envMXdizcHC:0268 VC:112 00 FL:1142
                    LDA $1C                 ;A:0201 X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0282 VC:112 00 FL:1142
                    CLC                     ;A:02BD X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0306 VC:112 00 FL:1142
                    ADC TABLE3,y            ;A:02BD X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0320 VC:112 00 FL:1142
                    ROL $00                 ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:enVMXdizCHC:0352 VC:112 00 FL:1142
                    CMP $D8,x               ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:enVMXdizCHC:0390 VC:112 00 FL:1142
                    PHP                     ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNVMXdizcHC:0420 VC:112 00 FL:1142
                    LDA.W $001D             ;A:026D X:0006 Y:0001 D:0000 DB:03 S:01EC P:eNVMXdizcHC:0442 VC:112 00 FL:1142
                    LSR $00                 ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:enVMXdiZcHC:0474 VC:112 00 FL:1142
                    ADC TABLE6,y            ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:enVMXdizCHC:0512 VC:112 00 FL:1142
                    PLP                     ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01EC P:envMXdiZCHC:0544 VC:112 00 FL:1142
                    SBC $14D4,x             ;A:0200 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNVMXdizcHC:0572 VC:112 00 FL:1142
                    STA $00                 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0604 VC:112 00 FL:1142
                    LDY $01                 ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizcHC:0628 VC:112 00 FL:1142
                    BEQ LABEL22             ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0652 VC:112 00 FL:1142
                    EOR #$80                ;A:02FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0668 VC:112 00 FL:1142
                    STA $00                 ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0684 VC:112 00 FL:1142
LABEL22             LDA $00                 ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0708 VC:112 00 FL:1142
                    BPL RETURN_2            ;A:027F X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:0732 VC:112 00 FL:1142
                    BMI ERASE_SPRITE        ;A:0280 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:0170 VC:064 00 FL:1195

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

