; FloatLikeAPrincess.asm
;			by Maddy, allegedly
;			modified from Peach's Floating Ability by Ladida, found here: https://www.smwcentral.net/?p=section&a=details&id=20818

; Created for 'Float like a Princess' in Super "Sonic Saves the World" World
; The player may float like Princess Toadstool in Super Mario Bros. 2 USA by holding the jump button
; When the float timer is almost consumed, the player's palette will flash - below this threshold, the player cannot initiate a new float
; Touching the ground or bouncing on something refills the float counter

; Feel free to reuse this code however you want. Ladida should be credited. Crediting me is appreciated too :)

; Usage: This is intended to be used as an UberASM library file, called from many level files
;	     Call the float routine from your levels' main routines
;		 There are also included "crown" block files which refill the player's float timer when collected

; ------------------------------ 
; CONFIG OPTIONS
; ------------------------------ 

; player's vertical speed oscillates between +/- this while floating
!float_speed = $03

; how long floating lasts before falling
!float_time = $40   

; if time is under this, the player cannot stop and restart floating
; this is also the threshold under which the player palette begins flashing, if that is enabled
!used_time = $14	 

; if 1, flash the player palette when the float timer is low
; this requires another patch (Manual Player Palette Update Patch, by imamelia, https://www.smwcentral.net/?p=section&a=details&id=4517)
; I'm using a special version of this patch with modifications by DtotheFourth, so I've disabled this option by default
; if you know what you're doing, you should be able to get it working though!
!set_palette = 0

; ------------------------------
; FreeRAM ADDRESSES
; make sure these don't overlap with RAM already in use by other ASM in these levels
; ------------------------------

; float timer remaining
; -> 1 byte
!RAM_counter = $0F5E

; have I floated this jump?
; -> 1 byte
!RAM_used = $0F5F

; when this is set, the palette will be uploaded
; This must match the address in Manual Player Palette Update Patch
; -> 1 byte
!RAM_PalUpdateFlag = $7FB200

; a pointer to the player palette to upload
; This must match the address in Manual Player Palette Update Patch
; -> 2 bytes
!RAM_PlayerPalPtr = $7FB202

; ------------------------------
; DATA
; ------------------------------

; don't touch this. It's just used for convenient access in the code
yspeed:
        db -!float_speed, !float_speed

if !set_palette
	; default player palette, and the palette to flash when the float timer is low
	Palette:
		dw $635F, $581D, $000A, $623D, $44C4, $733D, $733D, $599D, $623D, $03FF
	Palette_Low:
		dw $FFFF, $FFFF, $FFFF, $FFFF, $FFFF, $FFFF, $FFFF, $FFFF, $FFFF, $FFFF
endif

; ------------------------------ 
; GAME LOGIC CODE
; ------------------------------ 

float:

	if !set_palette
		; palette
		LDA #$01
		STA !RAM_PalUpdateFlag
		LDA #Palette>>16
		STA !RAM_PlayerPalPtr+2
		
		; decide which palette to use
		LDA $71
		BNE +
		LDA !RAM_used
		BEQ +
		LDA $14
		AND #%00000100
		BEQ +
		
		REP #$20
		LDA.w #Palette_Low
		STA !RAM_PlayerPalPtr
		SEP #$20
		BRA ++
		+
		REP #$20
		LDA.w #Palette
		STA !RAM_PlayerPalPtr
		SEP #$20
		++	
	endif

	; cape check
	LDA $19
	CMP #$02
	BNE +
	RTL
	+
	
	; anim check
	LDA $71
	CMP #$05
	BCC +
	RTL
	+
	
	; climb refill
	LDA $74
	BEQ +
	LDA #!float_time
	STA !RAM_counter	
	STZ !RAM_used
	+
	
	; other checks
	LDA $74		; climbing
	ORA $75		; swimming
	ORA $9D		; locked
	ORA $1891	; p-balloon
	ORA $187A	; yoshi
	ORA $1493	; end level
	ORA $13D4	; paused
	BEQ +
	RTL
	+
 
	; on ground check
	LDA $77
	AND #$04
	BEQ +
	LDA #!float_time
	STA !RAM_counter
	STZ !RAM_used
	RTL
	+
	
	; check if we should float
	LDA $7D
	BMI .skip_float
	LDA !RAM_counter
	BEQ .skip_float
	LDA $15
	BPL .skip_float
	
	; perform float
	LDA $14
	AND #%00000111
	BNE +
	JSL glitter
	+	
	DEC !RAM_counter
	LDA !RAM_counter
	CMP #!used_time
	BCS +
	LDA #$01
	STA !RAM_used
	+
	LDA $14
	LSR #4
	AND #$01
	TAX
	LDA.l yspeed,x
	STA $7D
	BRA .after_float
				
	.skip_float
	
	; check if we should zero the counter because you used once this jump already
	LDA !RAM_used
	BEQ .after_float
	LDA $15
	BMI .after_float
	STZ !RAM_counter
		
	.after_float
		
	; check if bounced
	LDA $7D
	BPL +
	CMP #-!float_speed-1
	BCS +
	LDA #!float_time
	STA !RAM_counter	
	STZ !RAM_used
	+

    RTL


glitter:
	LDY.b #$03
	.LoopStart
	LDA.w $17C0,Y
	BEQ .CreateGlitter
	DEY
	BPL .LoopStart

	.CreateGlitter
	LDA #$05
	STA $17C0,Y
	LDA $94
	STA $17C8,Y
	LDA $96
	CLC : ADC #$10
	STA $17C4,Y
	LDA #$10
	STA $17CC,Y
	RTL

