; BreakTheTargets.asm
;			by Maddy, allegedly

; Created for 'Break the Targets!' in Super "Sonic Saves the World" World
; The player must break all the target blocks within the time limit to progress to the next sublevel
; There are two quirks to this that are enabled by default (but can be disabled in config options):
; 	1. The timer will not begin running until the player moves.
; 	2. Running out of time will not kill the player until they touch the ground
; If the player successfully breaks all of the targets, we trigger the screen exit as assigned in Lunar Magic -
; so be sure that all possible screen exits in the sublevel are assigned correctly!

; Feel free to reuse this code however you want. Credit is appreciated :)

; Usage: This is intended to be used as an UberASM library file, called from many level files.
;		You should also use the included custom blocks, which are the actual targets to be broken.
;		An example level UberASM file is included for reference

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

; if 1, the timer will not start running until the player moves at the start of the level
!wait_for_move = 1

; if 1, running out of time will not kill the player until they touch the ground
!wait_for_ground = 1

; if 1, pressing L+R kills the player for a quick retry
!quick_retry = 1

; ------------------------------ 
; DRAWING OPTIONS
; ------------------------------ 

; if 1, UI will be drawn showing a target icon for each target yet to be destroyed
; this UI can accomodate up to 8 targets in a single sublevel by default and is drawn with 8x8 OAM tiles
!draw_targets_ui = 1

; the first timer digit's x- and y-positions
!timer_x = 2
!timer_y = 2

; the location of the top-left tile of the 'big' timer digit OAM tiles
; the big timer digits are 2 tiles tall and 1 tile wide (8x16)
; the tiles should be arranged horizontally in ascending order from 0 to 9, starting with the zero's top-left tile in this slot
!timer_tiles_big = $C0

; the location of the 'small' timer digit OAM tiles
; the small timer digits are 1 8x8 tile
; the tiles should be arranged horizontally in ascending order from 0 to 9, starting with the zero in this slot
!timer_tiles_small = $E0

; the location of the single '.' decimal OAM tile
!timer_tiles_dot = $F0

; the properties byte to use for the timer OAM tiles before the timer has finished
!timer_props = %00111001

; the properties byte to use for the timer OAM tiles after the timer has finished
!timer_finished_props = %00111011

; the first target icon's x- and y-positions
!target_icons_x = 38
!target_icons_y = 2

; the separation distance in pixels between target icons on the x- and y-axes
!target_icons_x_sep = 10
!target_icons_y_sep = 10

; the amount of target icons to draw per line
!target_icons_per_line = 4

; tile id and properties for target icons
!target_icons_tile = $F1
!target_icons_props = %00111001

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

; the amount of targets the player has destroyed so far in the current sublevel
; -> 1 byte
!RAM_hits = $0F5E

; the total amount of targets in the current sublevel
; -> 1 byte
!RAM_total = $0F5F		

; the amount of seconds left on the timer
; -> 1 byte
!RAM_seconds = $0F60

; the fractions of a second left on the timer (0-59)
; -> 1 byte
!RAM_frames = $0F61

; the current timer state
; 00 = timer not yet running at the start of level, 01 = timer running, 02 = timer finished
; -> 1 byte
!RAM_state = $0F62

; the properties byte to use when drawing the timer OAM tiles
; -> 1 byte
!RAM_props = $0F63

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

; a table of decimal milliseconds digits for all the frame counts 0-60. 
; this was generated by a script and we reference it when drawing the timer's tenths of seconds digit
Milli_Digits:
        dw $0000, $0016, $0033, $0050, $0066, $0083, $0100, $0117, $0133, $0150, $0167, $0183, $0200, $0217, $0233, $0250, $0267, $0283, $0300, $0317, $0333, $0350, $0367, $0383, $0400, $0417, $0433, $0450, $0467, $0483, $0500, $0517, $0533, $0550, $0567, $0583, $0600, $0617, $0633, $0650, $0667, $0683, $0700, $0717, $0733, $0750, $0767, $0783, $0800, $0817, $0833, $0850, $0867, $0883, $0900, $0917, $0933, $0950, $0967, $0983

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

init:
	STZ !RAM_hits	
	STZ $19				; clear powerup	
	STZ $14AF			; clear on/off
	
	LDA #!timer_props
	STA !RAM_props
	
	if !wait_for_move
		STZ !RAM_state
	else
		LDA #$01
		STA !RAM_state
	endif
	
	RTL
	
main:
	LDA $71		; player state check
	BNE draw
	LDA $13D4	; paused check
	BNE draw
	LDA $13FB	; player frozen check
	BNE draw
	
	; quick retry check
	if !quick_retry
		LDA $17
		AND #%00110000
		CMP #%00110000
		BNE +
		JSL $00F606	; kill mario
		+
	endif

	; state branching
	LDA !RAM_state
	BEQ .start_wait
	CMP #$02
	BEQ .timer_done
	
	; state == 01
	; the timer is running
	; {
		; decrement timer
		LDA !RAM_frames
		BEQ +
		DEC !RAM_frames
		BEQ +
		BRA .win_check
		+
		LDA !RAM_seconds
		BNE +
		INC !RAM_state
		LDA #!timer_finished_props
		STA !RAM_props
		BRA .win_check
		+
		DEC !RAM_seconds
		LDA #$3B
		STA !RAM_frames
		BRA .win_check
	; }
	
	; state == 00
	; the timer is not yet running
	; {
		.start_wait
		LDA $7B
		BNE +
		LDA $13EF
		BEQ +
		BRA .win_check
		+
		INC !RAM_state
		BRA .win_check
	; }
	
	; state == 02
	; the timer has finished
	; {
		.timer_done

		if !wait_for_ground
			LDA $72			; ground check
			BNE .win_check
			LDA $74			; climbing check
			BNE .win_check
		endif
		
		JSL $00F606	; kill mario
		BRA draw
	; }
	
	; checks to see if the player has won
	; if they have, trigger the screen exit
	; {
		.win_check
		LDA !RAM_hits
		CMP !RAM_total
		BNE draw
		
		; the player won!
		LDA #$05
		STA $1DF9
		LDA #$06
		STA $71
		STZ $89
		STZ $88
		
		; --> falls through to the draw routine below -->
	; }
	
; ------------------------------ 
; DRAWING CODE
; ------------------------------ 
	
macro nexttile()
	?loop:
	LDA $0201,y
	CMP #$F0
	BEQ ?end
	INY #$4
	CPY #$00
	BNE ?loop
    RTS
	?end:
endmacro

draw:
	; pause check
	LDA $13D4
	BEQ +
	RTL
	+

	LDY #$00
	
	if !draw_targets_ui
	; target icons
	; {
		LDA !RAM_total
		SEC : SBC !RAM_hits
		STA $00
		LDX #$00
		LDA #!target_icons_x
		STA $01
		LDA #!target_icons_y
		STA $02
		
		-
		CPX $00
		BCS .done_targets
		TXA
		
		%nexttile()
		LDA $01
		STA $0200,Y
		LDA $02
		STA $0201,Y
		LDA #!target_icons_tile
		STA $0202,Y
		LDA #!target_icons_props
		STA $0203,Y
		
		; extra bits
		PHY
		TYA
		LSR #2
		TAY
		LDA #$00
		STA $0420,Y
		PLY
		
		INX
		CPX #!target_icons_per_line
		BEQ +
		; advance target x
		LDA $01
		CLC : ADC #!target_icons_x_sep
		STA $01
		BRA -
		+
		; newline
		LDA #!target_icons_x
		STA $01
		LDA $02
		CLC : ADC #!target_icons_y_sep
		STA $02
		BRA -
		.done_targets
	; }
	endif

	; seconds tens
	; {
		LDA !RAM_seconds
		CMP #$0A
		BCC +
		
		LDA #$01
		STA $00
		LDA #!timer_x
		STA $01
		LDA #!timer_y
		STA $02
		JSL draw_big_digit
		+
	; }
	
	; seconds ones
	; {
		LDA !RAM_seconds	
		-
		CMP #$0A
		BCC +
		SEC : SBC #$09
		BRA -
		+
		STA $00
		
		LDA #!timer_x+$08
		STA $01
		LDA #!timer_y
		STA $02
		JSL draw_big_digit		
	; }
	
	; dot
	; {
		%nexttile()
		LDA #!timer_x+$10
		STA $0200,Y
		LDA #!timer_y+$08
		STA $0201,Y
		LDA #!timer_tiles_dot
		STA $0202,Y
		LDA !RAM_props
		STA $0203,Y
		
		; extra bits
		PHY
		TYA
		LSR #2
		TAY
		LDA #$00
		STA $0420,Y
		PLY
	; }
	
	; tenths of a second
	; {
		LDA !RAM_frames
		ASL
		TAX
		
		LDA Milli_Digits+1,X
		STA $00
		LDA #!timer_x+$18
		STA $01
		JSL draw_small_digit
	; }

	RTL
	
; $00 - digit
; $01 - x
; $03 - props
draw_small_digit:
	%nexttile()
	LDA $01
	STA $0200,Y
	LDA #!timer_y+8
	STA $0201,Y
	LDA $00
	CLC : ADC #!timer_tiles_small
	STA $0202,Y
	LDA !RAM_props
	STA $0203,Y
	
	; extra bits
	PHY
	TYA
	LSR #2
	TAY
	LDA #$00
	STA $0420,Y
	PLY
	
	RTL
	
; $00 - digit
; $01 - x
; $02 - y
; $03 - props
draw_big_digit:

	; top
	%nexttile()
	LDA $01
	STA $0200,Y
	LDA $02
	STA $0201,Y
	LDA $00
	CLC : ADC #!timer_tiles_big
	STA $0202,Y
	LDA !RAM_props
	STA $0203,Y
	
	; top extra bits
	PHY
	TYA
	LSR #2
	TAY
	LDA #$00
	STA $0420,Y
	PLY
	
	; bottom
	%nexttile()
	LDA $01
	STA $0200,Y
	LDA $02
	CLC : ADC #$08
	STA $0201,Y
	LDA $00
	CLC : ADC #!timer_tiles_big+$10
	STA $0202,Y
	LDA !RAM_props
	STA $0203,Y
	
	; top extra bits
	PHY
	TYA
	LSR #2
	TAY
	LDA #$00
	STA $0420,Y
	PLY
	
	RTL
	