;BuildCPC equ 1
;org &4000

StateIdle 	equ 0
StateLaunch 	equ 1
StateExplode 	equ 2

speedscale 	equ 128	;Move speed

XposL 		equ 0
XposH 		equ 1
YposL 		equ 2		
YposH 		equ 3		
Xacc 		equ 4	
Yacc 		equ 5
ParticleState 	equ 6
StateTime 	equ 7


useMode0 equ 1
particles equ  32
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Fireworks:

WaitforRelease:
	call &BB1e	;KeyTest
	cp ' '
	jr z,WaitforRelease

	ld bc,&0000	;Black
	call &bc38	;border

	ld hl,palette	
	ld a,0
PaletteAgain:
	ld b,(hl)
	ld c,(hl)
	inc hl
	push hl
	push af
		call &bc32	;ink
	pop af
	pop hl
	inc a
	cp 16
	jr nz,PaletteAgain

	ld a,0
	call &BC0E	;Screen Mode

	ld b,particles
	ld ix,ParticleArray
NextRandomF:
	push bc	
	call RandomizeFirst
	ld bc,8
	add ix,bc
	pop bc 
	djnz NextRandomF
FireworkLoop:

	call &BB1b		;Return if space is pressed
	cp ' '
	ret z

	ld a,(SoundTimeout)
	or a
	jr z,Silence
	dec a
	ld (SoundTimeout),a
	jr z,Silence2		;Just hit 0? then silence sound

	ld a,(SoundFX)
	add 2			;Alter Pitch
	ld (SoundFX),a
Silence2:
	call ChibiSound
Silence:

	ld b,particles
	ld ix,ParticleArray	
NextFirework:

	push bc	
MoreFireworks:
	ld a,(globaltick)	;See if we're processing logic changes?
	dec a
	jr nz,NoTick
  
	ld a,(ix+ParticleState)
	cp StateIdle
	jp z,IdleParticle	;Idle particle does nothing
	
	dec (ix+StateTime)
	jr nz,NoTick

	call ReRandomizeF	;Particle expired - update particle type
NoTick:
	ld a,(ix+ParticleState)
	cp StateIdle
	jp z,IdleParticle

	ld a,(ix+XposH)
	cp 160			;<160
	jp c,Xok
	cp 170			;<0
	jp c,XZero
	ld a,159		;Lock Xpos Right
	ld (ix+XposH),a
	jp Xok
XZero:
	ld a,0			;Lock Xpos Left
	ld (ix+XposH),a
Xok:
	ld b,a
	ld a,(ix+YposH)		;ypos
	ld c,a
	cp 200			;Off bottom of screen?
	jp nc,IdleParticle

	push bc
		call GetPixelMask
		ld a,15			;Draw new pixel
		call GetColorMaskNum
		and e		
		ld e,a
		ld a,(hl)
		and d
		or e
		ld (hl),a
		ld d,0	;Change flag

		ld b,0
		ld c,(ix+Xacc)	;x accel
		bit 7,c
		jr z,Xpositive
		ld b,255	;Set Top Byte -
Xpositive:
		ld l,(ix+XposL)	;xpos
		ld h,(ix+XposH)
		ld a,h
		add hl,bc
		cp h
		jr z,NoChangeX
		inc d		;Top byte changed!
NoChangeX:	
		ld (ix),l
		ld (ix+XposH),h

		ld l,(ix+YposL)
		ld h,(ix+YposH)	;ypos
		ld a,h
		ld b,0
		ld c,(ix+Yacc)	;y accel
		bit 7,c
		jr z,Ypositive
		ld b,255	;Set Top Byte -
Ypositive:
		add hl,bc
		cp h
		jr z,NoChangeY
		inc d		;Top byte changed!
NoChangeY:
		ld (ix+2),l
		ld (ix+YposH),h
	pop bc
	ld a,d			;Has particle moved?
	or a
	call nz,clearfirework	;Yes? then clear particle

FireWorkUnchanged:
IdleParticle:
	ld bc,8
	add ix,bc		;Move to next particle
	pop bc
	dec b
	jp nz, NextFirework	;Repeat for next particle

	ld hl,globaltick	;Update global tick
	ld a,(hl)
	dec a
	and %00001111		;Shorter=Faster explosions
	ld (hl),a
	jp FireworkLoop

clearfirework2:
	ld a,(ix+XposH)	;xpos
	ld b,a
	ld a,(ix+YposH)	;ypos
	cp 200
	ret nc
	ld c,a
clearfirework:
	call GetPixelMask

	ld a,(ix+ParticleState)
	ld b,8			;Burst Trail
	cp StateExplode
	jr z,colorDecided
	ld a,13 		;Launch Trail
	ld b,a
colorDecided:
	ld a,b
	call GetColorMaskNum
	and e		
	ld e,a
	ld a,(hl)
	and d
	or e
	ld (hl),a
	ret

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

ReRandomizeF:

	ld a,(ix+ParticleState)	;state
	cp StateLaunch
	jr nz,RandomizeFirst

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Burst Particle

	push ix
	push bc
		ld a,%11000000
		ld (SoundFX),a
		ld a,30
		ld (SoundTimeout),a
	pop bc
	pop ix

	push bc		;1=Particles Explode
	call dorandom
	and 7
	add 8
	ld d,a
	ld b,particles
	ld iy,ParticleArray	;Explode!
BurstNextParticle:
	ld a,(ix+XposL)
	ld (iy+0),a	

	ld a,(ix+XposH)
	ld (iy+XposH),a

	ld a,(ix+YposL)
	ld (iy+2),a

	ld a,(ix+YposH)
	ld (iy+YposH),a

	ld a,d
	ld (iy+StateTime),a		;State Time
	
	ld a,StateExplode
	ld (iy+ParticleState),a		;State
	push bc
		ld bc, 8
		add iy,bc
	pop bc
	djnz BurstNextParticle
	pop bc
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Launching particle

RandomizeFirst:			;Randmomize First Firework
	push bc

	call clearfirework2

	ld a,0			;LowBytes
	ld (ix+XposL),a
	ld (ix+YposL),a

	ld a,199
	ld (ix+YposH),a		;Starting Ypos

	call dorandom
	and 63
	add 48			
	ld (ix+XposH),a		;Starting Xpos

	call dorandom
	and speedscale-1
	sub speedscale/2
	ld (ix+Xacc),a		;Xacc

	call dorandom
	and speedscale-1
	inc a
	sub speedscale
	ld (ix+Yacc),a		;Yacc
	
	pop bc
	ld c,StateLaunch 	;Launching
	ld a,b
	cp particles
	jr z,StateFirst
	ld c,StateIdle		;Set All but first to idle

	ld a,(ix+Yacc)	;flip y
	add speedscale/2
	ld (ix+Yacc),a
	jr SetState	
StateFirst:
	push bc
		call ColorShift
	pop bc

SetState:
	ld (ix+ParticleState),c		;State
	call dorandom
	and 7
	add 24
	ld (ix+7),a		;State Time
	ret

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

	read "CA_DoRandom.asm"
Randoms1:
	db &0A,&9F,&F0,&1B,&69,&3D,&E8,&52,&C6,&41,&B7,&74,&23,&AC,&8E,&D5
Randoms2:
	db &9C,&EE,&B5,&CA,&AF,&F0,&DB,&69,&3D,&58,&22,&06,&41,&17,&74,&83
RandomSeed: dw 0



ByteToColorMask: ;Fill whole byte with color - 
;eg %00001000 to %00001111 (when B=0)
;or %00000100 to %00001111 (when B=1)
		 ;A=Color pixel... B=pixel pos (Xpos)
	ld c,a
	ld a,b
	ifndef useMode0
		and %00000011	;4 pixels per byte in Mode 1
	else
		and %00000001	;2 pixels per byte in Mode 0
	endif
	jr z,ByteToColorMaskNoShift ;Zero pos=no shift
	ld b,a
ByteToColorMaskLeftShift:
	sla c			;Shift C B times (color to far right
	djnz ByteToColorMaskLeftShift
ByteToColorMaskNoShift:
	ld a,c
	ifndef useMode0
		rrca		;Fill all the pixels with the same color
		or c
		rrca
		or c
	endif
	rrca
	or c
	ret				;All pixels in A now the same color


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

GetColorMaskNum:
	ifndef useMode0
		and %00000011	;4 colors in Mode 1
	else
		and %00001111	;16 colors in Mode 0
	endif
	push bc
		ld bc,ColorLookup ;Get Color from LUT
		add c
		ld c,a 
		ld a,(bc)
	pop bc
	ret
	


GetPixelMask:	;(AB,C) = (X,Y)
;Returns HL=Mempos... D=Mask to keep background - E= pixel to select
	push af
		push bc	
			;rra		;2; pixels per byte in mode 0
			srl b
			ifndef useMode0
				;rra	;4 pixels per byte in mode 1
				srl b	
			endif
			call GetScreenPos ;Get Byte Position
		pop bc
		push bc
			ld a,b
			ifndef useMode0
				and %00000011 ;4 pixels per byte in Mode 1
			else 
				and %00000001 ;2 pixels per byte in Mode 0
			endif
			ld bc,PixelBitLookup	;Lookup table of single pixel bytemask
			add c
			ld c,a 
			ld a,(bc)	;Get Pixel Mask for X position
			ld e,a
			cpl
			ld d,a	
		pop bc
	pop af
	ret 



ifndef useMode0	;Mode 1

	Align 4
PixelBitLookup:	;Pixel positions
	db %10001000,%01000100,%00100010,%00010001
ColorLookup:	;Colors (all pixels one color)
	db %00000000,%11110000,%00001111,%11111111

else		;Mode 0
	Align 16
PixelBitLookup:	;Pixel positions
	db %10101010,%01010101
ColorLookup:	;Colors (all pixels one color)
	db %00000000,%00000011,%00001100,%00001111,%00110000,%00110011,%00111100,%00111111,%11000000,%11000011,%11001100,%11001111,%11110000,%11110011,%11111100,%11111111
endif

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

GetScreenPos:	;return memory pos in HL of screen co-ord B,C (X,Y)
;	; Input  BC= XY (x=bytes - so 80 across)
;	; output HL= screen mem pos
;	; de is wiped
;

;Looking at Y line (in C) - we need to take each set of bits, and work with them separately:
;YYYYYYYY	Y line number (0-200)
;-----YYY	(0-7)  - this part needs to be multiplied by &0800 and added to the total
;YYYYY---	(0-31) - This part needs to be multiplied by 80 (&50)



;YYYYY---	(0-31) - This part needs to be multiplied by 80 (&50)
	push de
		;screen is 80 bytes wide = -------- %01010000
		ld a,C		; 00000000 01010000
		and %11111000 	; -------- -YYYY---
		ld h,0
		ld l,a
				; 00000000 01010000
		
		sla l		; -------- YYYY----
		rl h
		
		ld d,h		;value is in first bit position -add it
		ld e,l	
				; 00000000 01010000
		sla e		; -------Y YYY-----
		rl d		;	    
		sla e		; ------YY YY------
		rl d
		
		add hl,de	;value is in 2nd bit position - add it
		;We've now effectively multiplied by 80 (&50)

	;-----YYY	(0-7)  - this part needs to be multiplied by &0800 and added to the total
		ld a,C
		and %00000111	
		
		rlca		;X8
		rlca
		rlca

		ld d,a		;Load into top byte, and add as 16 bit
		ld e,0

		add hl,de
		;We've now effectively multiplied by 8

	;Screen Base
		ld a,&C0	;Add the screen Base &C000
		ld d,a

	;X position
		ld e,B		;Add the X pos 
		add hl,de
	pop de

	ret 		;return memory location in hl
	
GetNextLine:
	push af

		ld a,h		;Add &08 to H (each CPC line is &0800 bytes below the last
		add &08
		ld h,a
			;Every 8 lines we need to jump back to the top of the memory range to get the correct line
			;The code below will check if we need to do this - yes it's annoying but that's just the way the CPC screen is!
		bit 7,h		;Change this to bit 6,h if your screen is at &8000!
		jp nz,GetNextLineDone
		push bc
			ld bc,&c050	;if we got here we need to jump back to the top of the screen - the command here will do that
			add hl,bc
		pop bc
	GetNextLineDone:
	pop af
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Fade out colors 

ColorShift:
	ld hl,&C000	;Destination is top of the screen
	push hl
		call ColorShiftOne
	pop hl
	inc hl 
	push hl
		call ColorShiftOne
	pop hl
	inc hl 
	push hl
		call ColorShiftOne
	pop hl
		ret

macro shiftone
		srl (hl)
		srl (hl)
		inc hl
		inc hl
		inc hl
endm
ColorShiftOne:
		shiftone
		shiftone
		shiftone
		shiftone
		shiftone
		shiftone
		shiftone
		shiftone
		ld a,h
		or a
		jr nz,ColorShiftOne
	ret

	read "\SrcALL\Multiplatform_ChibiSound.asm"

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

palette:
	db  0, 6, 9, 4, 2, 7,10, 9
	db 1,20,12,15,23,17,25,26

SoundTimeout: db 1
SoundFX: db %11000000


globaltick:
	db 0

ParticleArray:
ds 256,255

