;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; SMW Jumping Piranha Plants (sprites 4F & 50), by imamelia
;;
;; This is a disassembly of sprites 4F and 50 in SMW, the Jumping Piranha Plants.
;;
;; Uses first extra bit: YES
;;
;; If the extra bit is clear, the sprite will act like sprite 4F.  If the extra bit is set, it
;; will act like sprite 50, meaning that it will spit fireballs when it jumps.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; defines and tables
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

XDisp:
db $00,$08,$00,$08

YDisp:
db $00,$00,$0B,$0B

XFlip:
db $00,$40,$00,$40

Tilemap:		; the sprite tilemap (the two $CEs are unused for this sprite)
db $AC,$CE,$AE,$CE,$83,$83,$C4,$C4,$83,$83,$C5,$C5

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; init routine
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

print "INIT ",pc
LDA $D8,x
SEC
SBC #$02
STA $1528,x
LDA $E4,x	;
CLC		;
ADC #$08	; shift the sprite's X position to the right 8 pixels
STA $E4,x		;
INC $D8,x	; shift the sprite down 1 pixels
LDA $D8,x	;
CMP #$FF		; if there was overflow...
BNE EndInit	;
INC $14D4,x	; decrement the high byte as well
EndInit:		;
RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; main routine wrapper
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

print "MAIN ",pc
PHB
PHK
PLB
JSR JumpingPiranhaMain
PLB
RTL

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; main routine
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

JumpingPiranhaMain:

;JSL $07F78B	; load sprite tables? I don't know what the purpose of this is...
;JSL $0187A7	; I'd have to include this, too, since this is now a custom sprite.

LDA #$08		;
STA $15F6,x	; Oh, I see now.

LDA $64		;
PHA		; preserve the level's sprite priority
LDA #$10		;
STA $64		; so that it can be set to 10 temporarily

LDA $1570,x	; animation frame counter
AND #$08	;
LSR #2		;
EOR #$02		; make the sprite flip between 2 frames
STA $1602,x	;

JSR JumpingPiranhaGFX1	; draw the head

LDA $15EA,x		;
CLC			;
ADC #$04		; increment the sprite OAM index by 4
STA $15EA,x		;

LDA $151C,x		;
AND #$04		;
LSR #2			;
INC			;
STA $1602,x		; set the frame number for the leaves at the bottom of the plant

LDA $D8,x		;
PHA			; preserve the sprite Y position
CLC			;
ADC #$08		; so we can shift it down 8 pixels
STA $D8,x		;
LDA $14D4,x		;
PHA			;
ADC #$00		;
STA $14D4,x		;

LDA #$0A			;
STA $15F6,x		; set the sprite palette to green

JSR JumpingPiranhaGFX2	; draw the leaves

PLA			;
STA $14D4,x		;
PLA			;
STA $D8,x		;
PLA			;
STA $64			;

LDA $9D			;
BNE Return00		; return if sprites are locked

JSR SubOffscreenX0		;
JSL $01803A		; interact with the player and with other sprites
JSL $01801A		; update sprite Y position without gravity

LDA $C2,x		; sprite state
JSL $0086DF		; execute 16-bit pointer subroutine

dw State00		;
dw State01		;
dw State02		;

Return00:			;
RTS			;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; code for sprite state 00
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

State00:

STZ $AA,x	; set the sprite Y speed to 0
LDA $1540,x	;
BNE Return01	;

JSR SubHorzPos	;

LDA $0F		; horizontal distance between the sprite and the player
CLC		;
ADC #$1B		;
CMP #$37		; if the player is close enough...
BCC Return01	;

LDA #$40		; set the sprite's jumping Y speed
STA $AA,x	;
INC $C2,x	; increment the sprite state
STZ $1602,x	; and set the frame to 0

Return01:		;
RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; code for sprite state 01
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

State01:

LDA $AA,x	; if the sprite's Y speed is negative...
BPL Accelerate	;
CMP #$C0		; or it is positive and less than 40...
BCC NoAccelerate	;
Accelerate:	;
SEC			;
SBC #$02		; add 2 to it to make the sprite accelerate
STA $AA,x	;

NoAccelerate:	;

INC $1570,x	; increment the animation frame counter
LDA $AA,x	; if the sprite's Y speed
CMP #$10		; is between F1 and FF...
BPL Return02	;
LDA #$50		;
STA $1540,x	; set the timer
INC $C2,x	; and increment the sprite state

RTS		;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; code for sprite state 02
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

State02:

LDA $D8,x
CMP $1528,x
BEQ RESET

INC $151C,x	; increment the secondary animation frame counter
LDA $1540,x	; if the timer is set, then skip the next part of code
BNE MaybeSpitFire	; and go to the part where it checks to see whether or not the sprite should spit fireballs

NoFire:		;

INC $1570,x	;

LDA $14		;
AND #$03	; once every 4 frames...
BNE NoAccelerate2	;
LDA $AA,x
CMP #$F8		; if the sprite Y speed is greater than 08...
BMI NoAccelerate2	;
DEC	;
STA $AA,x	; increment the sprite Y speed

NoAccelerate2:	;

JSL $019138	; interact with objects

LDA $1588,x	;
AND #$04		; if the sprite is on the ground...
BEQ Return02
RESET:
STZ $C2,x	; reset the sprite state to 0
LDA #$40		;
STA $1540,x	; and set the time before it checks the player's proximity again

Return02:		;
RTS

MaybeSpitFire:

LDA $7FAB10,x	;
AND #$04	; if the extra bit is not set...
BEQ NoFire	; don't spit fireballs

STZ $1570,x	; reset the animation frame counter

LDA $1540,x	; I had to reload this because of the extra bit check.
CMP #$40		; if the timer isn't at exactly 40...
BNE NoFire	;
LDA $15A0,x	; or the sprite is offscreen horizontally or vertically...
ORA $186C,x	;
BNE NoFire	; don't spit fireballs

LDA #$12		; X speed for the first fireball
JSR SpitFireballs	;
LDA #$EE		; X speed for the second fireball

SpitFireballs:	; It's kind of interesting how they did this, really.

STA $00		; save the X speed value

LDY #$07		; 8 extended sprite indexes to loop through

ExSpriteLoop:	;

LDA $170B,y	; check this slot
BEQ SpawnFire	; if the slot is free, we can use it for a fireball
DEY		; if not, decrement the index
BPL ExSpriteLoop	; and try again

RTS		;

SpawnFire:	;

LDA #$0B		; extended sprite number = 0B
STA $170B,y	; piranha fireball

LDA $E4,x	; sprite X position
CLC		;
ADC #$04	; the fireball spawns 4 pixels to the right of the plant
STA $171F,y	;
LDA $14E0,x	;
ADC #$00	; prevent overflow
STA $1733,y	;

LDA $D8,x	;
STA $1715,y	; same Y position as the plant
LDA $14D4,x	;
STA $1729,y	;

LDA #$30	; extended sprite Y speed = D0
STA $173D,y	;
LDA $00		; $00 had the X speed value from before
STA $1747,y	;

BRA NoFire	; finish up with the regular code

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

JumpingPiranhaGFX1:	; ripped from $0190B2

JSL $20CA4F	;

LDA $157C,x		;
STA $02			;

LDA $1602,x		;
TAX			;
LDA Tilemap,x		; set the sprite tilemap
STA $0302,y		;

LDX $15E9	;
LDA $00		;
STA $0300,y	; no X displacement
LDA $01		;
STA $0301,y	; no Y displacement

LDA $157C,x	;
LSR		; if the sprite is facing right...
LDA $15F6,x	;
BCS NoXFlipTile	; X-flip the tile
EOR #$40		;
NoXFlipTile:	;
ORA $64		;
ORA #$80
STA $0303,y	;

TYA		;
LSR #2		;
TAY		;

LDA #$02		;
ORA $15A0,x	;
STA $0460,y	; set the tile size

PHK		;
PER $0006	;
PEA $8020	;
JML $81A3DF	; set up some stuff in OAM

RTS		;

JumpingPiranhaGFX2:	; ripped from $018042

STA $05			;

LDA $1504,x		;
STA $06			;

JSL $20CA4F	;

LDA $1602,x	;
ASL #2		;
STA $02		;

LDA $15F6,x	;
ORA $64		;
STA $03		;

LDA #$03		;
STA $04		;

PHX		;

GFXLoop:		;

LDX $04		;

LDA $00		;
CLC		;
ADC XDisp,x	;
STA $0300,y	;

LDA $0302,y
CMP #$83		; SCREW YOU TILE 83 BUG!
BNE Reg

LDA #$EF
BRA StoreY

Reg:
LDA $01
SEC
SBC YDisp,x
StoreY:
STA $0301,y

LDA $02		;
CLC		;
ADC $04		;
TAX		;

LDA Tilemap,x	;
STA $0302,y	;

LDX $04		;

LDA XFlip,x	;
ORA $03		;
STA $0303,y	;

INY #4		;
DEC $04		;
BPL GFXLoop	;

PLX		;
LDA #$03		;
LDY #$00		;
JSL $81B7B3	;
RTS		;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; subroutines
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Table1:              db $0C,$1C
Table2:              db $01,$02
Table3:              db $40,$B0
Table6:              db $01,$FF
Table4:              db $30,$C0,$A0,$C0,$A0,$F0,$60,$90,$30,$C0,$A0,$80,$A0,$40,$60,$B0
Table5:              db $01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$00,$01,$FF

SubOffscreenX0:
LDA #$00
;BRA SubOffscreenMain
;SubOffscreenX1:
;LDA #$02
;BRA SubOffscreenMain
;SubOffscreenX2:
;LDA #$04
;BRA SubOffscreenMain
;SubOffscreenX3:
;LDA #$06
;BRA SubOffscreenMain
;SubOffscreenX4:
;LDA #$08
;BRA SubOffscreenMain
;SubOffscreenX5:
;LDA #$0A
;BRA SubOffscreenMain
;SubOffscreenX6:
;LDA #$0C
;BRA SubOffscreenMain
;SubOffscreenX7:
;LDA #$0E

SubOffscreenMain:

STA $03

JSR SubIsOffscreen
BEQ Return2

LDA $5B
LSR
BCS VerticalLevel
LDA $D8,x
CLC
ADC #$50
LDA $14D4,x
ADC #$00
CMP #$02
BPL EraseSprite
LDA $167A,x
AND #$04
BNE Return2
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 Return2

EraseSprite:
LDA $14C8,x
CMP #$08
BCC KillSprite
LDY $161A,x
CPY #$FF
BEQ KillSprite
LDA #$00
STA $1938,y
KillSprite:
STZ $14C8,x
Return2:
RTS

VerticalLevel:

LDA $167A,x
AND #$04
BNE Return2
LDA $13
LSR
BCS Return2
AND #$01
STA $01
TAY
LDA $1C
CLC
ADC Table3,y
ROL $00
CMP $D8,x
PHP
LDA $1D
LSR $00
ADC Table6,y
PLP
SBC $14D4,x
STA $00
LDY $02
BEQ Label22
EOR #$80
STA $00
Label22:
LDA $00
BPL Return2
BMI EraseSprite

SubIsOffscreen:
LDA $15A0,x
ORA $186C,x
RTS


SubHorzPos:

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










