;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SMB3 Chain Chomp (v1.1)
; Coded by SMWEdit
;
; Uses first extra bit: NO
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

		CHAINTILE = $05
		OPENMOUTHTILE = $06
		CLOSEDMOUTHTILE = $08

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

		HOLDOUTTIME = $18	; time to hold position after dashing outwards

		MAX_LINK_X = $0D
		MAX_LINK_Y = $0E

		MAX_TOTAL_X = $34
		MAX_TOTAL_Y = $39

		ACTSTATUS = $C2		; 0    - start dashing out
					; 1    - dashing out (checking for max)
					; 2    - reached max, stationary, waiting
					; 3    - falling
					; 4-11 - moving on ground, waiting for time to start another dash (different status means different motion)
		GFXFLIP = $1504
		FRAMECOUNTER = $1528
		TIMER = $163E

		ORIGINXLO = $7F8900
		ORIGINXHI = $7F890C
		ORIGINYLO = $7F8918
		ORIGINYHI = $7F8924

		LINK1XLO = $7F8930
		LINK2XLO = $7F893C
		LINK3XLO = $7F8948
		LINK4XLO = $7F8954

		LINK1YLO = $7F8960
		LINK2YLO = $7F896C
		LINK3YLO = $7F8978
		LINK4YLO = $7F8984

		TMP1 = $00
		TMP2 = $01
		TMP3 = $02
		TMP4 = $03

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; INIT and MAIN JSL targets
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

		dcb "INIT"
		LDA $D8,x		; \
		STA ORIGINYLO,x		;  | set Y low
		STA LINK1YLO,x		;  | byte for
		STA LINK2YLO,x		;  | origin and
		STA LINK3YLO,x		;  | start of links
		STA LINK4YLO,x		; /
		LDA $E4,x		; \
		STA ORIGINXLO,x		;  | set X low
		STA LINK1XLO,x		;  | byte for
		STA LINK2XLO,x		;  | origin and
		STA LINK3XLO,x		;  | start of links
		STA LINK4XLO,x		; /
		LDA $14D4,x		; \ set Y high
		STA ORIGINYHI,x		; / byte for origin
		LDA $14E0,x		; \ set X high
		STA ORIGINXHI,x		; / byte for origin
		RTL

		dcb "MAIN"
		PHB
		PHK
		PLB
		JSR SPRITE_ROUTINE
		PLB
		RTL


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SPRITE_ROUTINE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MAXLINKDISTX	dcb MAX_LINK_X,0-MAX_LINK_X&$FF
MAXLINKDISTY	dcb MAX_LINK_Y,0-MAX_LINK_Y&$FF

MAXTOTALDISTX	dcb MAX_TOTAL_X,0-MAX_TOTAL_X&$FF
MAXTOTALDISTY	dcb MAX_TOTAL_Y,0-MAX_TOTAL_Y&$FF

MAXHIBYTES	dcb $00,$FF

FALLXSPEEDS	dcb $F8,$08

XSPEEDS		dcb $50,$50,$50,$50,$40,$30,$20,$1C
YSPEEDS		dcb $E0,$D0,$C0,$B0,$B0,$B0,$B0,$B0

; ...

LENGTH		dcb $39,$19,$23,$3D,$0D,$39,$41,$19
NEEDRETURN	dcb $01,$00,$01,$01,$00,$01,$01,$01

SPEEDS		dcw ACTION1SPEED&$FFFF,ACTION2SPEED&$FFFF
		dcw ACTION3SPEED&$FFFF,ACTION4SPEED&$FFFF
		dcw ACTION5SPEED&$FFFF,ACTION6SPEED&$FFFF
		dcw ACTION7SPEED&$FFFF,ACTION8SPEED&$FFFF

DIRS		dcw ACTION1DIR&$FFFF,ACTION2DIR&$FFFF
		dcw ACTION3DIR&$FFFF,ACTION4DIR&$FFFF
		dcw ACTION5DIR&$FFFF,ACTION6DIR&$FFFF
		dcw ACTION7DIR&$FFFF,ACTION8DIR&$FFFF

BITES		dcw ACTION1BITE&$FFFF,ACTION2BITE&$FFFF
		dcw ACTION3BITE&$FFFF,ACTION4BITE&$FFFF
		dcw ACTION5BITE&$FFFF,ACTION6BITE&$FFFF
		dcw ACTION7BITE&$FFFF,ACTION8BITE&$FFFF

ACTION1SPEED	dcb $10
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION1DIR	dcb $00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION1BITE	dcb $01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION2SPEED	dcb $00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00

ACTION2DIR	dcb $01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION2BITE	dcb $02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION2BITE	dcb $01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01


ACTION3SPEED	dcb $10,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION3DIR	dcb $00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION3BITE	dcb $01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION4SPEED	dcb $10,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$10,$10,$10,$10
		dcb $10,$10,$10,$10,$10,$10,$10,$10
		dcb $10,$10,$10,$10,$10,$10,$10,$10
		dcb $10,$10,$10,$10,$10,$10,$10,$10
		dcb $10,$10,$10,$10,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION4DIR	dcb $00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION4BITE	dcb $01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION5SPEED	dcb $E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION5DIR	dcb $01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION5BITE	dcb $02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION6SPEED	dcb $10
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $10,$10,$10,$10,$10,$10,$10,$10
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION6DIR	dcb $00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION6BITE	dcb $01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION7SPEED	dcb $10
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $10,$10,$10,$10,$10,$10,$10,$10
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION7DIR	dcb $00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $00,$00,$00,$00,$00,$00,$00,$00
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION7BITE	dcb $01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

ACTION8SPEED	dcb $10
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
		dcb $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0

ACTION8DIR	dcb $00
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01
		dcb $01,$01,$01,$01,$01,$01,$01,$01

ACTION8BITE	dcb $01
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02
		dcb $02,$02,$02,$02,$02,$02,$02,$02

RETURN1		RTS

SPRITE_ROUTINE	JSR SUB_GFX
		LDA $14C8,x		; \
		CMP #$08		;  | don't process when not "normal" status
		BNE RETURN1		; /
		LDA $9D			; \ return if
		BNE RETURN1		; / sprites locked
		JSR OFFSCREENCHK	; custom offscreen checker, range of 0x100 pixels offscreen (the chomps kept vanishing without this)

		JSL $018022             ; Update X position without gravity
        	JSL $01801A             ; Update Y position without gravity
		JSL $01A7DC		; check for mario/sprite contact

		LDA ACTSTATUS,x		; get status
		BEQ BEGINDASH		; go to "begin dash" if it's 0
		DEC A			; next
		BEQ DASHING		; go to "dashing" if it's 1
		DEC A			; next
		BEQ HOLDDASHJMP		; go to "holding dash" if it's 2
		DEC A			; next
		BEQ FALLINGJMP		; go to "falling" if it's 3
		JMP MOVING		; go to "moving" if it's anything else

HOLDDASHJMP	JMP HOLDDASH		; \ a branch to these
FALLINGJMP	JMP FALLING		; / would be out of range

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

BEGINDASH
		JSR SUB_HORZ_POS	; \
		TYA			;  | face mario
		STA $157C,x		; /
		STA GFXFLIP,x		; this flip will also be how the GFX is flipped

		JSR GETRANDOM		; get "random" number 0-7
		TAY			; ... -> Y
		LDA YSPEEDS,y		; \ Y speed from the
		STA $AA,x		; / table of Y speeds
		LDA XSPEEDS,y		; \
		LDY $157C,x		;  | set X speed
		BEQ SETXSPEED		;  | from the table
		EOR #$FF		;  | and flip if
		INC A			;  | necessary
SETXSPEED	STA $B6,x		; /

		INC ACTSTATUS,x		; go to next action

		RTS

; ...

DASHING
		INC FRAMECOUNTER,x
		LDY #$00		; Y=0 means positive, could be changed later
		LDA $E4,x		; \  get distance
		SEC			;  | between position
		SBC ORIGINXLO,x		; /  and origin
		BPL CHKXDIST		; if positive, skip negative code
		INY			; Y=1 (0+1) means negative, this is where it's changed
		EOR #$FF		; \ make negative
		INC A			; / positive
CHKXDIST	CMP #MAX_TOTAL_X	; compare with maximum
		BCC XDISTOK		; skip next bit of code if the distance is within the maximum
		LDA MAXTOTALDISTX,y	; \
		CLC			;  | set position
		ADC ORIGINXLO,x		;  | to maximum
		STA $E4,x		;  |
		LDA ORIGINXHI,x		;  |
		ADC MAXHIBYTES,y	;  |
		STA $14E0,x		; /
		BRA ENDDASH		; branch to code for preparing for next status
XDISTOK

		LDY #$00		; Y=0 means positive, could be changed later
		LDA $D8,x		; \  get distance
		SEC			;  | between position
		SBC ORIGINYLO,x		; /  and origin
		BPL CHKYDIST		; if positive, skip negative code
		INY			; Y=1 (0+1) means negative, this is where it's changed
		EOR #$FF		; \ make negative
		INC A			; / positive
CHKYDIST	CMP #MAX_TOTAL_Y	; compare with maximum
		BCC YDISTOK		; skip next bit of code if the distance is within the maximum
		LDA MAXTOTALDISTY,y	; \
		CLC			;  | set position
		ADC ORIGINYLO,x		;  | to maximum
		STA $D8,x		;  |
		LDA ORIGINYHI,x		;  |
		ADC MAXHIBYTES,y	;  |
		STA $14D4,x		; /
		BRA ENDDASH
YDISTOK

		JSR MOVELINKS		; call custom subroutine to make links move

		RTS

ENDDASH
		STZ $AA,x		; zero Y speed
		STZ $B6,x		; zero X speed
		INC ACTSTATUS,x		; next status
		LDA #HOLDOUTTIME	; \ set timer for
		STA TIMER,x		; / holding dash
		JSR LINEUPLINKS		; call custom subroutine to line up the links
		RTS

; ...

HOLDDASH
		INC FRAMECOUNTER,x	; \
		INC FRAMECOUNTER,x	;  | elapse 3/4 a frame
		INC FRAMECOUNTER,x	; /
		LDA TIMER,x		; \ if timer not expired, then
		BNE RETURNHOLD		; / don't go to next status
		INC ACTSTATUS,x		; go to next status
RETURNHOLD	RTS

; ...

FALLING
		INC FRAMECOUNTER,x	; \ elapse 1/2 a frame
		INC FRAMECOUNTER,x	; /
		JSR SUB_HORZ_POS_H	; \
		TYA			;  | set GFX flip
		STA GFXFLIP,x		; /

		JSR MOVELINKS		; call custom subroutine to make links move

		LDA $D8,x		; \  if Y is at or below origin
		CMP ORIGINYLO,x		;  | (on ground), then this
		BPL ENDFALL		; /  is the end of falling

		INC $AA,x		; \ pseudo-gravity
		INC $AA,x		; /

		LDY $157C,x		; \  set slight
`		LDA FALLXSPEEDS,y	;  | X speed for
		STA $B6,x		; /  when falling

		RTS

ENDFALL
		LDA #$F0		; \ set speed for the slight
		STA $AA,x		; / bounce when it lands
		LDA ORIGINYLO,x		; \
		STA $D8,x		;  | set head at the Y
		LDA ORIGINYHI,x		;  | position of the origin
		STA $14D4,x		; /
		INC ACTSTATUS,x		; next status
		JSR GETRANDOM		; get "random" number
		PHA			; preserve "random" number
		CLC			; \ add to
		ADC ACTSTATUS,x		; / status
		STA ACTSTATUS,x		; set new status
		PLY			; pull "random" number to Y
		LDA LENGTH,y		; get timer length based on what action
		STA TIMER,x		; set timer for movement
		RTS

; ...

MOVING
		LDA ACTSTATUS,x		; \
		SEC			;  | 4-11 are the indexes
		SBC #$04		;  | for movement type
		STA TMP1		; /

		ASL A			; \
		TAY			;  | frame
		LDA BITES,y		;  | rate is
		STA TMP2		;  | determined
		LDA BITES+1,y		;  | by a
		STA TMP3		;  | table
		LDY TIMER,x		;  |
		LDA (TMP2),y		;  |
		CLC			;  |
		ADC FRAMECOUNTER,x	;  |
		STA FRAMECOUNTER,x	; /

		LDA $157C,x		; \ 
		STA TMP4		;  | get flip
		LDY TIMER,x		;  | for motion
		BNE NO_OVERRIDE_DIR	;  |
		LDY TMP1		;  |
		LDA NEEDRETURN,y	;  |
		BEQ NO_OVERRIDE_DIR	;  |
		LDY #$00		;  |
		LDA $E4,x		;  |
		CMP ORIGINXLO,x		;  |
		LDA $14E0,x		;  |
		SBC ORIGINXHI,x		;  |
		BMI SETNEWDIR		;  |
		INY			;  |
SETNEWDIR	STY TMP4		; /
NO_OVERRIDE_DIR

		LDA TMP1		; \
		ASL A			;  | set X speed
		TAY			;  | based on
		LDA SPEEDS,y		;  | table and
		STA TMP2		;  | flip set
		LDA SPEEDS+1,y		;  | in above
		STA TMP3		;  | code
		LDY TIMER,x		;  |
		LDA (TMP2),y		;  |
		LDY TMP4		;  |
		BEQ SETXSPEED2		;  |
		EOR #$FF		;  |
		INC A			;  |
SETXSPEED2	STA $B6,x		; /

		LDY TMP1		; \  if this motion doesn't require a return
		LDA NEEDRETURN,y	;  | to the origin to start another dash,
		BEQ DIRFROMTABLE	; /  always get the GFX flip from table
		LDA TIMER,x		; \ if the timer is expired,
		BEQ FACEORIGIN		; / then face the origin
DIRFROMTABLE	TYA			; motion index is in Y, transfer to A
		ASL A			; x2
		TAY			; back to Y
		LDA DIRS,y		; \
		STA TMP2		;  | get GFX
		LDA DIRS+1,y		;  | flip from
		STA TMP3		;  | table of
		LDY TIMER,x		;  | directions
		LDA (TMP2),y		; /
		EOR $157C,x		; flip if sprite direction is flipped
		STA GFXFLIP,x		; set GFX flip
		BRA END_GFX_DIR		; branch over other GFX flip settings
FACEORIGIN	JSR SUB_HORZ_POS_H	; \  set GFX flip
		TYA			;  | as facing
		STA GFXFLIP,x		; /  towards origin
END_GFX_DIR

		LDA $D8,x		; \  if Y is at or below origin
		CMP ORIGINYLO,x		;  | (on ground), then there
		BPL ATGROUND		; /  should be no falling
		INC $AA,x		; \ pseudo-gravity
		INC $AA,x		; /
		BRA ENDGRAVITY		; skip ground code
ATGROUND	STZ $AA,x		; zero Y speed
		LDA ORIGINYLO,x		; \
		STA $D8,x		;  | set head at the Y
		LDA ORIGINYHI,x		;  | position of the origin
		STA $14D4,x		; /
ENDGRAVITY

		LDA TIMER,x		; \ if the timer's expired,
		BNE NO_START_DASH	; / then don't start new dash
		LDY TMP1		; \  if this movement doesn't
		LDA NEEDRETURN,y	;  | need to return to origin,
		BEQ BEGINNEWDASH	; /  then start a new dash
		LDA $E4,x		; \  if not at origin
		CMP ORIGINXLO,x		;  | do not start a
		BNE NO_START_DASH	; /  new dash
BEGINNEWDASH	STZ ACTSTATUS,x		; status: start dash
		STZ $B6,x		; zero X speed
		STZ $AA,x		; zero Y speed
NO_START_DASH

		JSR DROPLINKS		; call custom subroutine to make the links fall
		JSR MOVELINKS		; call custom subroutine to make links move

		RTS

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

OFFSCREENCHK	LDA $5B			; \  skip to vertical level
		AND #%00000001		;  | check if the level is
		BNE OFFSCREENCHKV	; /  a vertical level

OFFSCREENCHKH	LDA $E4,x		; \
		CMP $1A			;  | horizontal
		STA TMP1		;  | level check
		LDA $14E0,x		;  |
		SBC $1B			;  |
		BMI BEFORESCREENH	;  |
AFTERSCREENH	CMP #$02		;  |
		BCS OFFSCREEN		;  |
		BRA NOTOFFSCREENH	;  |
BEFORESCREENH	CMP #$FF		;  |
		BCC OFFSCREEN		; /
NOTOFFSCREENH	RTS

OFFSCREENCHKV	LDA $D8,x		; \
		CMP $1C			;  | vertical
		STA TMP1		;  | level check
		LDA $14D4,x		;  |
		SBC $1D			;  |
		BMI BEFORESCREENV	;  |
AFTERSCREENV	CMP #$01		;  |
		BCS OFFSCREEN		;  |
		BRA NOTOFFSCREENV	;  |
BEFORESCREENV	CMP #$FF		;  |
		BCC OFFSCREEN		; /
NOTOFFSCREENV	RTS

OFFSCREEN	LDA #$00		; \  kill sprite,
		LDY $161A,x		;  | but allow
		STA $1938,y		;  | sprite to
		STZ $14C8,x		; /  reload again
		RTS

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

GETRANDOM	LDA $13			; frame counter so it's different for each frame
		ASL A			; * 2
		CLC			; \ + sprite's frame counter
		ADC FRAMECOUNTER,x	; /
		CLC			; \ + sprite index so it's different for each sprite
		ADC $15E9		; /
		CLC			; \ + X position because it appears to prevent some repetition
		ADC $E4,x		; /
		CLC			; \ + Y position because it appears to prevent some repetition
		ADC $D8,x		; /
		CLC			; \ + Mario X position so it slightly changes dash patterns when he moves
		ADC $94			; /
		CLC			; \ + Timer frame counter to remove some more repetition
		ADC $0F30		; /
		AND #%00000111		; wrap at 8
		RTS

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

DROPLINKS	LDA ORIGINYLO,x		; \
		CLC			;  | set max Y position
		ADC #$05		;  | for the links
		STA TMP1		; /

DROPLINK1	LDA LINK1YLO,x		; \
		CLC			;  | Link 1
		ADC #$02		;  |
		STA LINK1YLO,x		;  |
		LDA LINK1YLO,x		;  |
		CMP TMP1		;  |
		BMI DROPLINK2		;  |
		LDA TMP1		;  |
		STA LINK1YLO,x		; /

DROPLINK2	LDA LINK2YLO,x		; \
		CLC			;  | Link 2
		ADC #$02		;  |
		STA LINK2YLO,x		;  |
		LDA LINK2YLO,x		;  |
		CMP TMP1		;  |
		BMI DROPLINK3		;  |
		LDA TMP1		;  |
		STA LINK2YLO,x		; /

DROPLINK3	LDA LINK3YLO,x		; \
		CLC			;  | Link 3
		ADC #$02		;  |
		STA LINK3YLO,x		;  |
		LDA LINK3YLO,x		;  |
		CMP TMP1		;  |
		BMI DROPLINK4		;  |
		LDA TMP1		;  |
		STA LINK3YLO,x		; /

DROPLINK4	LDA LINK4YLO,x		; \
		CLC			;  | Link 4
		ADC #$02		;  |
		STA LINK4YLO,x		;  |
		LDA LINK4YLO,x		;  |
		CMP TMP1		;  |
		BMI ENDLINKDROP		;  |
		LDA TMP1		;  |
		STA LINK4YLO,x		; /
		
ENDLINKDROP	RTS

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

LINEUPLINKS	LDY #$00		; \
		LDA $E4,x		;  | set positive
		SEC			;  | X distance
		SBC ORIGINXLO,x		;  |
		BPL SETXLINE		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
SETXLINE	STA TMP1		; /

		ASL A			; \
		CLC			;  | Link 1 X
		ADC TMP1		;  |
		LSR A			;  | Math: DIST*3/4
		LSR A			;  |
		CPY #$00		;  |
		BEQ SETL1XPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL1XPOS	CLC			;  |
		ADC ORIGINXLO,x		;  |
		STA LINK1XLO,x		; /

		LDA TMP1		; \
		LSR A			;  | Link 2 X
		CPY #$00		;  |
		BEQ SETL2XPOS		;  | Math: DIST/2 (DIST*2/4)
		EOR #$FF		;  |
		INC A			;  |
SETL2XPOS	CLC			;  |
		ADC ORIGINXLO,x		;  |
		STA LINK2XLO,x		; /

		LDA TMP1		; \
		LSR A			;  | Link 3 X
		LSR A			;  |
		CPY #$00		;  | Math: DIST/4 (DIST*1/4)
		BEQ SETL3XPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL3XPOS	CLC			;  |
		ADC ORIGINXLO,x		;  |
		STA LINK3XLO,x		; /

		LDA ORIGINXLO,x		; \ Link 4 X
		STA LINK4XLO,x		; / X will always be 0 apart from origin

		LDY #$00		; \
		LDA $D8,x		;  | Set positive
		SEC			;  | Y distance
		SBC ORIGINYLO,x		;  |
		BPL SETYLINE		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
SETYLINE	STA TMP1		; /

		ASL A			; \
		ASL A			;  | Link 1 Y
		STA $4204		;  |
		STZ $4205		;  | Math: DIST*4/5
		LDA #$05		;  |
		STA $4206		;  |
		LDA $4214		;  |
		CPY #$00		;  |
		BEQ SETL1YPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL1YPOS	CLC			;  |
		ADC ORIGINYLO,x		;  |
		STA LINK1YLO,x		; /

		LDA TMP1		; \
		ASL A			;  | Link 2 Y
		CLC			;  |
		ADC TMP1		;  | Math: DIST*3/5
		STA $4204		;  |
		STZ $4205		;  |
		LDA #$05		;  |
		STA $4206		;  |
		LDA $4214		;  |
		CPY #$00		;  |
		BEQ SETL2YPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL2YPOS	CLC			;  |
		ADC ORIGINYLO,x		;  |
		STA LINK2YLO,x		; /

		LDA TMP1		; \
		ASL A			;  | Link 3 Y
		STA $4204		;  |
		STZ $4205		;  | Math: DIST*2/5
		LDA #$05		;  |
		STA $4206		;  |
		LDA $4214		;  |
		CPY #$00		;  |
		BEQ SETL3YPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL3YPOS	CLC			;  |
		ADC ORIGINYLO,x		;  |
		STA LINK3YLO,x		; /

		LDA TMP1		; \
		STA $4204		;  | Link 4 Y
		STZ $4205		;  |
		LDA #$05		;  | Math: DIST/5 (DIST*1/5)
		STA $4206		;  |
		LDA $4214		;  |
		CPY #$00		;  |
		BEQ SETL4YPOS		;  |
		EOR #$FF		;  |
		INC A			;  |
SETL4YPOS	CLC			;  |
		ADC ORIGINYLO,x		;  |
		STA LINK4YLO,x		; /

		RTS

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

MOVELINKS
BEGINLINK1X	LDY #$00		; \
		LDA LINK1XLO,x		;  | check Link 1 X
		SEC			;  | vs. Head X
		SBC $E4,x		;  |
		BPL CHKLINK1X		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK1X	CMP #MAX_LINK_X		; /
		BCC BEGINLINK2X		; if in range, skip to next link X
		LDA MAXLINKDISTX,y	; \
		CLC			;  | set position
		ADC $E4,x		;  | to maximum
		STA LINK1XLO,x		; /

BEGINLINK2X	LDY #$00		; \
		LDA LINK2XLO,x		;  | Check Link 2 X
		SEC			;  | vs. Link 1 X
		SBC LINK1XLO,x		;  |
		BPL CHKLINK2X		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK2X	CMP #MAX_LINK_X		; /
		BCC BEGINLINK3X		; if in range, skip to next link X
		LDA MAXLINKDISTX,y	; \
		CLC			;  | set position
		ADC LINK1XLO,x		;  | to maximum
		STA LINK2XLO,x		; /

BEGINLINK3X	LDY #$00		; \
		LDA LINK3XLO,x		;  | Check Link 3 X
		SEC			;  | vs. Link 2 X
		SBC LINK2XLO,x		;  |
		BPL CHKLINK3X		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK3X	CMP #MAX_LINK_X		; /
		BCC BEGINLINK4X		; if in range, skip to next link X
		LDA MAXLINKDISTX,y	; \
		CLC			;  | set position
		ADC LINK2XLO,x		;  | to maximum
		STA LINK3XLO,x		; /

BEGINLINK4X	LDY #$00		; \
		LDA LINK4XLO,x		;  | Check Link 4 X
		SEC			;  | vs. Link 3 X
		SBC LINK3XLO,x		;  |
		BPL CHKLINK4X		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK4X	CMP #MAX_LINK_X		; /
		BCC BEGINLINK1Y		; if in range, skip to first link Y
		LDA MAXLINKDISTX,y	; \
		CLC			;  | set position
		ADC LINK3XLO,x		;  | to maximum
		STA LINK4XLO,x		; /

BEGINLINK1Y	LDY #$00		; \
		LDA LINK1YLO,x		;  | Check Link 1 Y
		SEC			;  | vs. Head Y
		SBC $D8,x		;  |
		BPL CHKLINK1Y		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK1Y	CMP #MAX_LINK_Y		; /
		BCC BEGINLINK2Y		; if in range, skip to next link Y
		LDA MAXLINKDISTY,y	; \
		CLC			;  | set position
		ADC $D8,x		;  | to maximum
		STA LINK1YLO,x		; /

BEGINLINK2Y	LDY #$00		; \
		LDA LINK2YLO,x		;  | Check Link 2 Y
		SEC			;  | vs. Link 1 Y
		SBC LINK1YLO,x		;  |
		BPL CHKLINK2Y		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK2Y	CMP #MAX_LINK_Y		; /
		BCC BEGINLINK3Y		; if in range, skip to next link Y
		LDA MAXLINKDISTY,y	; \
		CLC			;  | set position
		ADC LINK1YLO,x		;  | to maximum
		STA LINK2YLO,x		; /

BEGINLINK3Y	LDY #$00		; \
		LDA LINK3YLO,x		;  | Check Link 3 Y
		SEC			;  | vs. Link 2 Y
		SBC LINK2YLO,x		;  |
		BPL CHKLINK3Y		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK3Y	CMP #MAX_LINK_Y		; /
		BCC BEGINLINK4Y		; if in range, skip to next link Y
		LDA MAXLINKDISTY,y	; \
		CLC			;  | set position
		ADC LINK2YLO,x		;  | to maximum
		STA LINK3YLO,x		; /

BEGINLINK4Y	LDY #$00		; \
		LDA LINK4YLO,x		;  | Check Link 4 Y
		SEC			;  | vs. Link 3 Y
		SBC LINK3YLO,x		;  |
		BPL CHKLINK4Y		;  |
		INY			;  |
		EOR #$FF		;  |
		INC A			;  |
CHKLINK4Y	CMP #MAX_LINK_Y		; /
		BCC ENDCHAINMOVE	; if in range, skip to end
		LDA MAXLINKDISTY,y	; \
		CLC			;  | set position
		ADC LINK3YLO,x		;  | to maximum
		STA LINK4YLO,x		; /

ENDCHAINMOVE	RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GRAPHICS ROUTINE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

		GFXTMP1 = $02
		GFXTMP2 = $03

TILES		dcb OPENMOUTHTILE,CLOSEDMOUTHTILE

SUB_GFX		JSR GET_DRAW_INFO
		LDA GFXFLIP,x		; \ set head's
		STA GFXTMP1		; / X flip
		STZ GFXTMP2		; default: not dying
		LDA $14C8,x		; \
		CMP #$03		;  | skip next code if not dying
		BCS HEADGFX		; /
		INC GFXTMP2		; set death mode
		STZ FRAMECOUNTER,x	; always have open mouth
HEADGFX		LDA $00			; \ Head X
		STA $0300,y		; / position
		LDA $01			; \ Head Y
		STA $0301,y		; / position
		LDA FRAMECOUNTER,x	; \
		LSR A			;  | switch tile
		LSR A			;  | every 8 frames
		LSR A			;  | in sprite's
		AND #%00000001		;  | framecounter
		PHY			;  |
		TAY			;  |
		LDA TILES,y		;  |
		PLY			;  |
		STA $0302,y		; /
		LDA $15F6,x		; get sprite palette info
		PHX			; \
		LDX GFXTMP1		;  | Flip X if
		BEQ NO_FLIP_1		;  | chomp is
		ORA #%01000000		;  | set to
NO_FLIP_1	;PLX			; /
		;PHX			; \
		LDX GFXTMP2		;  | Then flip X
		BEQ NO_FLIP_2		;  | and Y if chain
		EOR #%11000000		;  | chomp is dying
NO_FLIP_2	PLX			; /
		ORA $64                 ; add in priority bits
		STA $0303,y             ; set properties
		PHX			; \
		TYA			;  | Set tile
		LSR A			;  | as 16x16
		LSR A			;  |
		TAX			;  |
		LDA #$02		;  | -> #$02 means 16x16
		STA $0460,x		;  |
		PLX			; /
		INY			; \
		INY			;  | Next OAM
		INY			;  | Index
		INY			; /
		LDA GFXTMP2		; \ If not dying, then
		BEQ CHAINGFX		; / go to chain GFX
		LDY #$FF		; #$FF means the tile sizes were set when the tiles were drawn
		LDA #$00		; This means we drew one tile
		JSL $01B7B3		; don't draw if offscreen
		RTS			; early return
CHAINGFX	LDA $00			; get X position
		CLC			; \
		ADC LINK1XLO,x		;  | add Link 1 X position
		SEC			;  | relative to the head
		SBC $E4,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0300,y		; set X position
		LDA $01			; get Y position
		CLC			; \
		ADC LINK1YLO,x		;  | add Link 2 X position
		SEC			;  | relative to the head
		SBC $D8,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0301,y		; set Y position
		LDA #CHAINTILE		; \ set
		STA $0302,y		; / tile
		LDA $15F6,x		; get sprite palette info
		ORA $64                 ; add in priority bits
		STA $0303,y             ; set properties
		PHX			; \
		TYA			;  | Set tile
		LSR A			;  | as 8x8
		LSR A			;  |
		TAX			;  |
		LDA #$00		;  | -> #$00 means 8x8
		STA $0460,x		;  |
		PLX			; /
		INY			; \
		INY			;  | Next OAM
		INY			;  | Index
		INY			; /
		LDA $00			; get X position
		CLC			; \
		ADC LINK2XLO,x		;  | add Link 1 X position
		SEC			;  | relative to the head
		SBC $E4,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0300,y		; set X position
		LDA $01			; get Y position
		CLC			; \
		ADC LINK2YLO,x		;  | add Link 2 X position
		SEC			;  | relative to the head
		SBC $D8,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0301,y		; set Y position
		LDA #CHAINTILE		; \ set
		STA $0302,y		; / tile
		LDA $15F6,x		; get sprite palette info
		ORA $64                 ; add in priority bits
		STA $0303,y             ; set properties
		PHX			; \
		TYA			;  | Set tile
		LSR A			;  | as 8x8
		LSR A			;  |
		TAX			;  |
		LDA #$00		;  | -> #$00 means 8x8
		STA $0460,x		;  |
		PLX			; /
		INY			; \
		INY			;  | Next OAM
		INY			;  | Index
		INY			; /
		LDA $00			; get X position
		CLC			; \
		ADC LINK3XLO,x		;  | add Link 1 X position
		SEC			;  | relative to the head
		SBC $E4,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0300,y		; set X position
		LDA $01			; get Y position
		CLC			; \
		ADC LINK3YLO,x		;  | add Link 2 X position
		SEC			;  | relative to the head
		SBC $D8,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0301,y		; set Y position
		LDA #CHAINTILE		; \ set
		STA $0302,y		; / tile
		LDA $15F6,x		; get sprite palette info
		ORA $64                 ; add in priority bits
		STA $0303,y             ; set properties
		PHX			; \
		TYA			;  | Set tile
		LSR A			;  | as 8x8
		LSR A			;  |
		TAX			;  |
		LDA #$00		;  | -> #$00 means 8x8
		STA $0460,x		;  |
		PLX			; /
		INY			; \
		INY			;  | Next OAM
		INY			;  | Index
		INY			; /
		LDA $00			; get X position
		CLC			; \
		ADC LINK4XLO,x		;  | add Link 1 X position
		SEC			;  | relative to the head
		SBC $E4,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0300,y		; set X position
		LDA $01			; get Y position
		CLC			; \
		ADC LINK4YLO,x		;  | add Link 2 X position
		SEC			;  | relative to the head
		SBC $D8,x		; /
		CLC			; \ add 4 because
		ADC #$04		; / it's an 8x8
		STA $0301,y		; set Y position
		LDA #CHAINTILE		; \ set
		STA $0302,y		; / tile
		LDA $15F6,x		; get sprite palette info
		ORA $64                 ; add in priority bits
		STA $0303,y             ; set properties
		PHX			; \
		TYA			;  | Set tile
		LSR A			;  | as 8x8
		LSR A			;  |
		TAX			;  |
		LDA #$00		;  | -> #$00 means 8x8
		STA $0460,x		;  |
		PLX			; /
		LDY #$FF		; #$FF means the tile sizes were set when the tiles were drawn
		LDA #$04		; This means we drew 5 tiles
		JSL $01B7B3		; don't draw if offscreen
		RTS



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ROUTINES FROM THE LIBRARY ARE PASTED BELOW
; You should never have to modify this code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GET_DRAW_INFO
; This is a helper for the graphics routine.  It sets off screen flags, and sets up
; variables.  It will return with the following:
;
;       Y = index to sprite OAM ($300)
;       $00 = sprite x position relative to screen boarder
;       $01 = sprite y position relative to screen boarder  
;
; It is adapted from the subroutine at $03B760
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_OFF_SCREEN
; This subroutine deals with sprites that have moved off screen
; It is adapted from the subroutine at $01AC0D
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                    
SPR_T12             dcb $40,$B0
SPR_T13             dcb $01,$FF
SPR_T14             dcb $30,$C0,$A0,$C0,$A0,$F0,$60,$90		;bank 1 sizes
		            dcb $30,$C0,$A0,$80,$A0,$40,$60,$B0		;bank 3 sizes
SPR_T15             dcb $01,$FF,$01,$FF,$01,$FF,$01,$FF		;bank 1 sizes
					dcb $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.W $001D             ;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


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_HORZ_POS
; This is a modification of the normal SUB_HORZ_POS routine to check the chain chomp origin
; instead of its current position
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SUB_HORZ_POS	LDY #$00
		LDA $94
		SEC
		SBC ORIGINXLO,x
		;STA $0F
		LDA $95
		SBC ORIGINXHI,x
		BPL SPR_L16
		INY
SPR_L16		RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SUB_HORZ_POS_H
; This checks the head's position vs. the origin
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SUB_HORZ_POS_H	LDY #$00
		LDA ORIGINXLO,x
		SEC
		SBC $E4,x
		;STA $0F
		LDA ORIGINXHI,x
		SBC $14E0,x
		BPL SPR_L16
		INY
SPR_L16		RTS

