;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Efreet, by Milk
; Based on the 32x32 Eerie, by Fierce Deity Manuz OW Hacker
; and uses code from imamelia's Piranha/Venus sprites
;
; Originally based on Ersanio's Eerie disassembly
;
; This is a sprite that will travel continuously in one
; direction in a wavy motion and will periodically shoot
; fireballs at Mario.
;
; Extra Bit: If the Extra Bit is set, both the Efreet and
; its projectiles will have a faster x-Speed. It will
; also have a quicker rate of fire.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



!EXTRA_BITS 		= $7FAB10

	print "INIT ",pc
		PHB			;\Sadly, this is needed
		PHK			; |otherwise the sprite would access
		PLB			;/the Xspeedtable in bank 01 instead of the current

		LDA !EXTRA_BITS,x	; \ 
		AND #$04		;  |If the Extra Bit is set,	
		BEQ Slow		; / use the alternate x-speed table

		JSR SubHorzPos
		TYA
		STA $157C,x
		LDA XSpeedtable2,y
		STA $B6,x
		BRA EndInit
Slow:
		JSR SubHorzPos		;\
		TYA			; |
		STA $157C,x		; |setup direction
		LDA XSpeedtable,y	; |Store Eerie's speed
		STA $B6,x		;/depending on which side Mario is

EndInit:
		PLB			;\I wonder what this does!
		RTL			;/

	print "MAIN ",pc

		PHB
		PHK
		PLB
		JSR Eerie
		PLB
		RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Defines
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

XSpeedtable:		db $08,$F8	;X speed table: Right, left
XSpeedtable2:		db $10,$F0	;X speed table: Right, left
YSpeedtable:		db $1A,$E6	;Y speed acceleration table: down, up (?)

YAcceleration:		db $01,$FF	;Y Acceleration stuff

TILEMAP:             	db $80,$82,$A0,$A2,$84,$86,$A4,$A6
                    	db $80,$82,$A0,$A2,$84,$86,$A4,$A6
HORIZ_DISP:          	db $F8,$08,$F8,$08,$F8,$08,$F8,$08
                    	db $08,$F8,$08,$F8,$08,$F8,$08,$F8
VERT_DISP:           	db $F8,$F8,$08,$08,$F8,$F8,$08,$08
                    	db $F8,$F8,$08,$08,$F8,$F8,$08,$08
PROPERTIES:          	db $48,$08,$08,$08             ;xyppccct format

FireXOffsetsLo:
db $0F,$FA,$0E,$00,$0E,$FE,$0D,$FE,$FB,$FB,$FE,$FE,$1D,$1D,$1D,$1D
FireXOffsetsHi:
db $00,$FF,$00,$00,$00,$FF,$00,$FF,$FF,$FF,$FF,$FF,$00,$00,$00,$00
FireYOffsetsLo:
db $09,$09,$FF,$FF,$18,$18,$13,$13,$06,$06,$01,$01,$0A,$0A,$01,$01
FireYOffsetsHi:
db $00,$00,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
FireXSpeeds:
db $0C,$F4,$0C,$F4
FireXSpeeds2:
db $16,$EA,$16,$EA
FireYSpeeds:
db $06,$06,$FA,$FA

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main Routines
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Eerie:		
		JSR SUB_GFX		;Handle graphics
		LDA $14C8,x		;\
		CMP #$08		; |Sprite status. If (so) not normal, return
		BNE Label1		;/
		LDA $9D			;\If sprites locked, return
		BNE Label1		;/

		JSR SpitFire

		JSL $018022		;Update X pos without gravity

		LDA $C2,x		;Load... something
		AND #$01		;AND #$01
		TAY			;Use as index for acceleration table
		LDA $AA,x		;\
		CLC			; |Load Y speed
		ADC YAcceleration,y	; |Accelerate it
		STA $AA,x		;/
		CMP YSpeedtable,y	;If it didn't reach the desired Y speed
		BNE Straight		;Continue processing the sprite
		INC $C2,x		;If it reached the desired speed, change Y direction

Straight:	JSL $01801A		;Update Y pos without gravity
		JSR SUB_OFF_SCREEN_X0	;Handle offscreen situation

		JSL $01A7DC		;Mario<->sprite interact routine
		BCC Label1
		LDA $0E
		CMP #$D8
		BPL Hurt
		LDA $140D
		BEQ Hurt
Hurt:
		JSL $00F5B7
Label1:		
		
		RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Spit Routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SpitFire:
	LDA !EXTRA_BITS,x	; \ 
	AND #$04		;  |If the Extra Bit is set	
	BEQ SlowFire		; / increase the ROF

	LDA $13
	AND #$3F
	BNE Flameless
	JSR DoSpit
SlowFire:
	LDA $13
	AND #$7F
	BNE Flameless
	JSR DoSpit
Flameless:
	RTS
DoSpit:
	JSR FacePlayer

	LDY #$07
ExSpriteLoop:
	LDA $170B,y
	BEQ FoundExSlot
	DEY
	BPL ExSpriteLoop
	RTS

FoundExSlot:

	STY $00

	LDA #$02
	STA $170B,y

	LDA $1510,x
	AND #$03
	ASL
	ASL
	STA $01
	LDA $157C,x
	TSB $01

	LDA $157C,x
	STA $02

	LDA $E4,x
	LDY $01
	CLC
	ADC FireXOffsetsLo,y
	LDY $00
	STA $171F,y
	LDA $14E0,x
	LDY $01
	ADC FireXOffsetsHi,y
	LDY $00
	STA $1733,y

	LDA $D8,x
	LDY $01
	CLC
	ADC FireYOffsetsLo,y
	LDY $00
	STA $1715,y
	LDA $14D4,x
	LDY $01
	ADC FireYOffsetsHi,y
	LDY $00
	STA $1729,y

	LDA !EXTRA_BITS,x	; \ 
	AND #$04		;  |If the Extra Bit is set,	
	BEQ SlowFireSpeeds	; / use the alternate FireXSpeed table

	LDY $02
	LDA FireXSpeeds2,y
	LDY $00
	STA $1747,y
	BRA RetainYSpeeds

SlowFireSpeeds:
	LDY $02
	LDA FireXSpeeds,y
	LDY $00
	STA $1747,y
RetainYSpeeds:
	LDY $02
	LDA FireYSpeeds,y
	LDY $00
	STA $173D,y

	LDA #$FF
	STA $176F,y

	LDA #$06
	STA $1DFC

	RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Face Player
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FacePlayer:			;
	JSR SubVertPos		;
	TYA			;
	ASL			;
	STA $157C,x		;

	JSR SubHorzPos		;
	TYA			; make it face the player
	ORA $157C,x		;
	STA $157C,x		;

	RTS			;

SubHorzPos:
	LDY #$00
	LDA $94
	SEC
	SBC $E4,x
	STA $0F
	LDA $95
	SBC $14E0,x
	BPL $01
	INY
	RTS

SubVertPos:
	LDY #$00
	LDA $96
	SEC
	SBC $D8,x
	STA $0F
	LDA $97
	SBC $14D4,x
	BPL $01
	INY
	RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Graphics Routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SUB_GFX:	JSL $20CA4F

		LDA $14                 ;\ 
                LSR A                   ; |
                LSR A                   ; |
                LSR A                   ; |
                CLC                     ; |Change animation's rate
                ADC $15E9               ; |
                AND #$01                ; |
                ASL A                   ; |
                ASL A  			; |
                STA $1602,x		;/


		LDA $1602,x
                    STA $03                 ; | $03 = index to frame start (0 or 4)                   
                   
                    LDA $157C,x             ; \ $02 = sprite direction
                    STA $02                 ; /
                    BNE NO_ADD
                    LDA $03
                    CLC
                    ADC #$08
                    STA $03
NO_ADD:              PHX                     ; push sprite index

                    LDX #$03                ; loop counter = (number of tiles per frame) - 1
LOOP_START_2:        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)
                    CLC                     ;  |
                    ADC HORIZ_DISP,x        ;  |
                    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 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_2        ; / 

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_OFF_SCREEN
; This subroutine deals with sprites that have moved off screen
; It is adapted from the subroutine at $01AC0D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                    
SPR_T12:            db $40,$B0
SPR_T13:            db $01,$FF
SPR_T14:            db $30,$C0,$A0,$C0,$A0,$F0,$60,$90		;bank 1 sizes
	            db $30,$C0,$A0,$80,$A0,$40,$60,$B0		;bank 3 sizes
SPR_T15:            db $01,$FF,$01,$FF,$01,$FF,$01,$FF		;bank 1 sizes
                    db $01,$FF,$01,$FF,$01,$00,$01,$FF		;bank 3 sizes

SUB_OFF_SCREEN_X1:  LDA #$02                ; \ entry point of routine determines value of $03
                    BRA STORE_03            ;  | (table entry to use on horizontal levels)
SUB_OFF_SCREEN_X2:  LDA #$04                ;  | 
                    BRA STORE_03            ;  |
SUB_OFF_SCREEN_X3:  LDA #$06                ;  |
                    BRA STORE_03            ;  |
SUB_OFF_SCREEN_X4:  LDA #$08                ;  |
                    BRA STORE_03            ;  |
SUB_OFF_SCREEN_X5:  LDA #$0A                ;  |
                    BRA STORE_03            ;  |
SUB_OFF_SCREEN_X6:  LDA #$0C                ;  |
                    BRA STORE_03            ;  |
SUB_OFF_SCREEN_X7:  LDA #$0E                ;  |
STORE_03:           STA $03                 ;  |            
                    BRA START_SUB           ;  |
SUB_OFF_SCREEN_X0:  STZ $03                 ; /

START_SUB:          JSR SUB_IS_OFF_SCREEN   ; \ if sprite is not off screen, return
                    BEQ RETURN_35           ; /
                    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_35           ; /
                    LDA $13                 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0756 VC:176 00 FL:205
                    AND #$01                ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0780 VC:176 00 FL:205
                    ORA $03                 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0796 VC:176 00 FL:205
                    STA $01                 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0820 VC:176 00 FL:205
                    TAY                     ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0844 VC:176 00 FL:205
                    LDA $1A                 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0858 VC:176 00 FL:205
                    CLC                     ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0882 VC:176 00 FL:205
                    ADC SPR_T14,y           ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0896 VC:176 00 FL:205
                    ROL $00                 ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizcHC:0928 VC:176 00 FL:205
                    CMP $E4,x               ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:0966 VC:176 00 FL:205
                    PHP                     ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:0996 VC:176 00 FL:205
                    LDA $1B                 ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizCHC:1018 VC:176 00 FL:205
                    LSR $00                 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdiZCHC:1042 VC:176 00 FL:205
                    ADC SPR_T15,y           ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizcHC:1080 VC:176 00 FL:205
                    PLP                     ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F0 P:eNvMXdizcHC:1112 VC:176 00 FL:205
                    SBC $14E0,x             ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1140 VC:176 00 FL:205
                    STA $00                 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1172 VC:176 00 FL:205
                    LSR $01                 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1196 VC:176 00 FL:205
                    BCC SPR_L31             ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1234 VC:176 00 FL:205
                    EOR #$80                ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1250 VC:176 00 FL:205
                    STA $00                 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1266 VC:176 00 FL:205
SPR_L31:            LDA $00                 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1290 VC:176 00 FL:205
                    BPL RETURN_35           ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1314 VC:176 00 FL:205
ERASE_SPRITE:       LDA $14C8,x             ; \ if sprite status < 8, permanently erase sprite
                    CMP #$08                ; |
                    BCC KILL_SPRITE         ; /    
                    LDY $161A,x             ;A:FF08 X:0007 Y:0001 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1108 VC:059 00 FL:2878
                    CPY #$FF                ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1140 VC:059 00 FL:2878
                    BEQ KILL_SPRITE         ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1156 VC:059 00 FL:2878
                    LDA #$00                ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1172 VC:059 00 FL:2878
                    STA $1938,y             ;A:FF00 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZcHC:1188 VC:059 00 FL:2878
KILL_SPRITE:        STZ $14C8,x             ; erase sprite
RETURN_35:          RTS                     ; return

VERTICAL_LEVEL:     LDA $167A,x             ; \ if "process offscreen" flag is set, return
                    AND #$04                ; |
                    BNE RETURN_35           ; /
                    LDA $13                 ; \
                    LSR A                   ; | 
                    BCS RETURN_35           ; /
                    LDA $E4,x               ; \ 
                    CMP #$00                ;  | if the sprite has gone off the side of the level...
                    LDA $14E0,x             ;  |
                    SBC #$00                ;  |
                    CMP #$02                ;  |
                    BCS ERASE_SPRITE        ; /  ...erase the sprite
                    LDA $13                 ;A:0000 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:1218 VC:250 00 FL:5379
                    LSR A                   ;A:0016 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1242 VC:250 00 FL:5379
                    AND #$01                ;A:000B X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1256 VC:250 00 FL:5379
                    STA $01                 ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1272 VC:250 00 FL:5379
                    TAY                     ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1296 VC:250 00 FL:5379
                    LDA $1C                 ;A:001A X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0052 VC:251 00 FL:5379
                    CLC                     ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0076 VC:251 00 FL:5379
                    ADC SPR_T12,y           ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0090 VC:251 00 FL:5379
                    ROL $00                 ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:enVMXdizCHC:0122 VC:251 00 FL:5379
                    CMP $D8,x               ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0160 VC:251 00 FL:5379
                    PHP                     ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0190 VC:251 00 FL:5379
                    LDA $1D                 ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F2 P:eNVMXdizcHC:0212 VC:251 00 FL:5379
                    LSR $00                 ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdiZcHC:0244 VC:251 00 FL:5379
                    ADC SPR_T13,y           ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdizCHC:0282 VC:251 00 FL:5379
                    PLP                     ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:envMXdiZCHC:0314 VC:251 00 FL:5379
                    SBC $14D4,x             ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0342 VC:251 00 FL:5379
                    STA $00                 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0374 VC:251 00 FL:5379
                    LDY $01                 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0398 VC:251 00 FL:5379
                    BEQ SPR_L38             ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0422 VC:251 00 FL:5379
                    EOR #$80                ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0438 VC:251 00 FL:5379
                    STA $00                 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0454 VC:251 00 FL:5379
SPR_L38:            LDA $00                 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0478 VC:251 00 FL:5379
                    BPL RETURN_35           ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0502 VC:251 00 FL:5379
                    BMI ERASE_SPRITE        ;A:8AFF X:0002 Y:0000 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0704 VC:184 00 FL:5490

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

