#include "data/kirby_good.h"
#include "data/kirby_evil.h"

const unsigned char kirby_good_palette[16]={ 0x0f,0x13,0x23,0x35,0x0f,0x28,0x26,0x36,0x0f,0x30,0x26,0x36,0x0f,0x05,0x26,0x36 };
const unsigned char kirby_evil_palette[16]={ 0x0f,0x05,0x15,0x27,0x0f,0x00,0x01,0x30,0x0f,0x00,0x18,0x30,0x0f,0x1a,0x2a,0x3a };
const unsigned char kirby_evil_palette_1[16]={ 0x0f,0x05,0x15,0x27,0x0f,0x00,0x01,0x30,0x0f,0x00,0x18,0x30,0x0f,0x18,0x28,0x38 };



const unsigned char kirby_change_mask[4]={1,1,2,2};

#define ETT_CHANGE_TIME			24

#define ETT_FP			4
#define MAX_PIECES		16		//4 sprites per piece

#define BLOCK_IN_DELAY		1
#define BLOCK_IN_BOUNCE		(-16<<ETT_FP)
#define BLOCK_IN_SPEED		(32<<ETT_FP)
#define BLOCK_IN_GRAVITY	17

#define BLOCK_OUT_DELAY		1
#define BLOCK_OUT_BOUNCE	(-16<<ETT_FP)
#define BLOCK_OUT_SPEED		(48<<ETT_FP)
#define BLOCK_OUT_GRAVITY	64

#pragma bssseg (push,"SHAREDRAM2")
#pragma dataseg(push,"SHAREDRAM2")

unsigned char piece_x     [MAX_PIECES];
  signed int  piece_y     [MAX_PIECES];
  signed int  piece_dy    [MAX_PIECES];
unsigned char piece_block [MAX_PIECES];	//4x4 block id, to avoid storing actual offset, 255 no block
unsigned char piece_bounce[MAX_PIECES];
unsigned char piece_pal   [MAX_PIECES];

unsigned char tl_px;
unsigned char tl_tx;
  signed int  tl_ty;
  signed int  tl_py;
  signed int  tl_pdy;
unsigned int  tl_adr;
unsigned int  tl_off;
unsigned char tl_tile1;
unsigned char tl_tile2;
unsigned char tl_tile3;
unsigned char tl_tile4;

unsigned char tl_delay;
  signed int  tl_bounce;
  signed int  tl_speed;
  signed char tl_gravity;
  
unsigned char tl_frame;

#pragma dataseg(pop);
#pragma bssseg (pop);
 


void e_kirby_select(unsigned char n)
{
	unsigned char chr;
	const unsigned char* pal;
	
	if(!(n&1))
	{
		chr=CHR_KIRBY_GOOD;
				
		tl_frame  =0;
		tl_delay  =BLOCK_IN_DELAY;
		tl_bounce =BLOCK_IN_BOUNCE;
		tl_speed  =BLOCK_IN_SPEED;
		tl_gravity=BLOCK_IN_GRAVITY;
		
		pal=kirby_good_palette;

		scroll(0,0);
	}
	else
	{
		chr=CHR_KIRBY_EVIL;
		
		tl_delay  =BLOCK_OUT_DELAY;
		tl_bounce =BLOCK_OUT_BOUNCE;
		tl_speed  =BLOCK_OUT_SPEED;
		tl_gravity=BLOCK_OUT_GRAVITY;
		
		pal=kirby_evil_palette;

		scroll(0,240);
	}
	
	pal_bg (pal);
	pal_spr(pal);
		
	mmc3_chr_bank(chr+0,0);
	mmc3_chr_bank(chr+2,1);
	mmc3_chr_bank(chr+4,2);
	mmc3_chr_bank(chr+5,3);
	mmc3_chr_bank(chr+6,4);
	mmc3_chr_bank(chr+7,5);
}



void e_kirby_anim(void)
{
	unsigned char bank;
	
	bank=tl_frame&8?1:0;

	bank_bg(bank);
	bank_spr(bank^1);
		
	++tl_frame;
}



void e_kirby_delay(unsigned char frames)
{
	while(--frames)
	{
		e_kirby_anim();
		
		ppu_wait_nmi();
	}
}



void e_kirby_effect(const unsigned char* data,unsigned char type)	//type 0 fall in, 1 fall off
{
	unsigned char pal,attr,temp,off1,off2,skip;
	unsigned char block,block_ptr,block_delay,block_cnt;

	for(_id=0;_id<16*15;++_id)
	{
		if(!(_id&15))
		{
			e_kirby_anim();
			ppu_wait_nmi();
		}
		
		split_list[_id]=16*15-1-_id;	//split_list used to store tile sequence list

		if(_id&16) split_list[_id]^=15;
	}
	
	if(type)
	{
		split_list[117]=0;
		split_list[118]=0;
		split_list[133]=0;
		split_list[134]=0;
		split_list[121]=0;
		split_list[122]=0;
		split_list[137]=0;
		split_list[138]=0;
		
		for(_i=0;_i<15;_i+=5)
		{
		
			for(_j=0;_j<16*5;++_j)
			{
				if(!(_j&7))
				{
					e_kirby_anim();
					ppu_wait_nmi();
				}
				
				off1=_i*(16*5)+(rand8()%(16*5));
				off2=_i*(16*5)+(rand8()%(16*5));
				
				temp=split_list[off1];
				split_list[off1]=split_list[off2];
				split_list[off2]=temp;
			}
		}
	}
	
	for(_id=0;_id<MAX_PIECES;++_id) piece_block[_id]=255;	//all slots empty
	
	block_ptr=0;
	block_delay=0;
	block_cnt=16*15;
	skip=0;
	
	while(block_cnt)
	{
		e_kirby_anim();
		
		oam_off=0;
		upd_off=0;
		
		for(_id=0;_id<MAX_PIECES;++_id)
		{
			block=piece_block[_id];
			
			if(block==255)	//spawn a new one
			{
				if(block_delay) continue;

				if(block_ptr>=16*15) continue;

				block=split_list[block_ptr++];
				
				piece_block[_id]=block;
				
				if(!type)					
				{
					piece_bounce[_id]=FALSE;
					
					piece_x [_id]=(rand8()&15)*16;
					piece_y [_id]=-16<<ETT_FP;
					piece_dy[_id]=rand8()&63;
				}
				else
				{
					piece_x [_id]= block<<4;
					piece_y [_id]=(block&0xf0)<<ETT_FP;
					piece_dy[_id]=rand8();
					
					tl_adr=NAMETABLE_C+((block&15)<<1)|((block>>4)<<6);
					
					update_list[upd_off++]=MSB(tl_adr)|NT_UPD_HORZ;
					update_list[upd_off++]=LSB(tl_adr);
					update_list[upd_off++]=2;
					update_list[upd_off++]=0;
					update_list[upd_off++]=0;
					
					tl_adr+=32;
					
					update_list[upd_off++]=MSB(tl_adr)|NT_UPD_HORZ;
					update_list[upd_off++]=LSB(tl_adr);
					update_list[upd_off++]=2;
					update_list[upd_off++]=0;
					update_list[upd_off++]=0;
				}
				
				attr=data[960+((block&15)>>1)+((block>>2)&0xfff8)];
	
				if(!(block&1))
				{
					if(!(block&(1<<4))) pal=attr&3; else pal=(attr>>4)&3;
				}
				else
				{
					if(!(block&(1<<4))) pal=(attr>>2)&3; else pal=(attr>>6)&3;
				}
				
				piece_pal[_id]=pal;
				
				block_delay=tl_delay;
				
				if(type&&skip<8)
				{
					if(block_delay==1)
					{
						++skip;
						block_delay=0;
					}
				}
			}
			
			tl_px =piece_x [_id];
			tl_py =piece_y [_id];
			tl_pdy=piece_dy[_id];
			
			tl_tx=block<<4;
			
			if(!type)
			{
				tl_ty=(block&0xf0)<<ETT_FP;
			}
			else
			{
				tl_ty=240<<ETT_FP;
			}
			
			tl_off=((block&15)<<1)|((block<<2)&0xffc0);
			
			tl_tile1=data[tl_off+0x00];
			tl_tile2=data[tl_off+0x01];
			tl_tile3=data[tl_off+0x20];
			tl_tile4=data[tl_off+0x21];
			
			if(tl_px<tl_tx)
			{
				tl_px+=8;
				
				if(tl_px>tl_tx) tl_px=tl_tx;
			}
			else
			if(tl_px>tl_tx)
			{
				tl_px-=8;
				
				if(tl_px<tl_tx) tl_px=tl_tx;
			}
		
			tl_py+=tl_pdy;
			
			if(tl_pdy<tl_speed) tl_pdy+=tl_gravity;
			
			if(tl_py>=tl_ty)
			{
				tl_py=tl_ty;
				
				if(!type)
				{
					if(!piece_bounce[_id])
					{
						tl_pdy=tl_bounce;		//bounce height
						
						piece_bounce[_id]=TRUE;
					}
					else
					{				
						piece_block[_id]=255;
						
						tl_adr=NAMETABLE_A+((tl_ty>>(ETT_FP+3))<<5)+(tl_tx>>3);
						
						update_list[upd_off++]=MSB(tl_adr)|NT_UPD_HORZ;
						update_list[upd_off++]=LSB(tl_adr);
						update_list[upd_off++]=2;
						update_list[upd_off++]=tl_tile1;
						update_list[upd_off++]=tl_tile2;
						
						tl_adr+=32;
						
						update_list[upd_off++]=MSB(tl_adr)|NT_UPD_HORZ;
						update_list[upd_off++]=LSB(tl_adr);
						update_list[upd_off++]=2;
						update_list[upd_off++]=tl_tile3;
						update_list[upd_off++]=tl_tile4;
						
						--block_cnt;
					}
				}
				else
				{
					piece_block[_id]=255;
					
					--block_cnt;
				}
			}
			
			if(tl_py>=(-16<<ETT_FP))
			{
				_sx= tl_px;
				_sy=(tl_py>>ETT_FP)-1;
				
				_pal=piece_pal[_id];
				
				oam_spr(_sx+0,_sy+0,tl_tile1,_pal,oam_off+0*4);
				oam_spr(_sx+8,_sy+0,tl_tile2,_pal,oam_off+1*4); 
				oam_spr(_sx+0,_sy+8,tl_tile3,_pal,oam_off+2*4);
				oam_spr(_sx+8,_sy+8,tl_tile4,_pal,oam_off+3*4);
				
				oam_off+=4*4;
			}
			
			piece_x [_id]=tl_px;
			piece_y [_id]=tl_py;
			piece_dy[_id]=tl_pdy;
		}
		
		if(oam_off) oam_hide_rest(oam_off);
		
		update_list[upd_off]=NT_UPD_EOF;
		
		oam_update();
		
		set_vram_update();
		
		ppu_wait_nmi();
		
		if(block_delay) --block_delay;
	}
	
	oam_clear_fast();
	oam_update();
	ppu_wait_nmi();
}



void e_kirby(void)
{	
	unsigned char i,bright;
	
	oam_clear_fast();
	oam_update();
	oam_size(0);
	
	mmc3_set_mirroring(M_HORIZONTAL);
	
	set_irq_handler(IRQ_EMPTY);
	set_nmi_handler(NMI_NORMAL);
	
	vram_adr(NAMETABLE_A);
	vram_fill(0,960);
	vram_write((unsigned char*)kirby_good_data+960,64);	//pre-fill attributes
	
	vram_adr(NAMETABLE_C);
	vram_write((unsigned char*)kirby_evil_data,1024);
		
	e_kirby_select(0);

	pal_bright(4);
	
	ppu_on_all();
	
	e_kirby_effect(kirby_good_data,0);
	
	for(i=0;i<ETT_CHANGE_TIME;++i)
	{
		e_kirby_select(i&kirby_change_mask[i>>4]?1:0);
		
		e_kirby_anim();
		
		ppu_wait_nmi();
	}

	e_kirby_effect(kirby_evil_data,1);
	
	for(i=0;i<64;++i)
	{
		pal_bg(i&4?kirby_evil_palette:kirby_evil_palette_1);
		ppu_wait_nmi();
	}
	
	bright=4;
	
	while(bright)
	{
		--bright;
		pal_bright(bright);
		delay(8);
	}
	
	ppu_off();
	
	bank_bg(0);	//for mmc3 interrupts
	bank_spr(1);
}