#include "data/tower.h"

#define EG_SCROLL_PREDELAY	60*3
#define EG_TEXT_PREDELAY	192
#define EG_TEXT_DURATION	34
#define EG_HIDE_STARS		(EG_SCROLL_PREDELAY+2048-440)
#define EG_TOAD_FRAME		(EG_SCROLL_PREDELAY+2048-150)
#define EG_SCENE_DURATION	2250


const unsigned char greets_palette_bg [16]={ 0x0f,0x0f,0x01,0x11,0x0f,0x14,0x25,0x36,0x0f,0x09,0x29,0x38,0x0f,0x13,0x21,0x31 };

const unsigned char greets_palette_spr[16]={ 0x0f,0x00,0x10,0x30,0x0f,0x15,0x27,0x37,0x0f,0x05,0x15,0x27,0x0f,0x12,0x21,0x30 };

const unsigned char toad_palette[16]={ 0x0f,0x0f,0x19,0x2a,0x0f,0x00,0x10,0x30,0x0f,0x0f,0x10,0x30,0x0f,0x18,0x28,0x30 };


const unsigned char text_anim_palette[]={
	0x0f,0x00,0x00,0x00,	//fade in
	0x0f,0x10,0x10,0x10,
	0x0f,0x30,0x30,0x30,	//flash
	0x0f,0x10,0x10,0x30,
	0x0f,0x0f,0x10,0x30,	//normal
	0x0f,0x0f,0x00,0x10, 	//fade out
	0x0f,0x0f,0x0f,0x00,
	0x0f,0x0f,0x0f,0x0f,
};



signed char label_offset[EG_TEXT_DURATION]={
	-14,-12,-10,-8,-6,-5,
	-4,-3,-2,
	-2,-1,-1,
	0,0,0,0,0,
	0,0,0,0,0,
	0,0,0,0,0,-1,
	-2,-3,-4,-5,-6,-7
};

signed char label_palette[EG_TEXT_DURATION/2]={
	0,1,2,3,4,4,
	4,4,4,4,4,
	4,4,4,4,5,6,
};
	


//there is some quirk with the bankswitching approach that makes const char* const arrays get allocated into wrong place
//so a hack with 1D string array is used

const char greets_list[]={
	"  CHRV          "
	"SHURAN33        "
	"SAVELIJ         "
	" GIBSON         "
	"MAKSAGOR        "
	" RASMER         "
	"FATAL      SNIPE"
	"   TMK          "
	" LASOFT         "
	"  FLAST         "
	"CITYACEE        "
	" DIMKAM         "
	" VINNNY         "
	"  KGB+          "
	"MOROZ       1999"
	"INTRO       SPEC"
	"PETER   SOVIETOV"
	"DMITRY     QUIET"
	"   UTZ          "
	"ATARI      TUFTY"
	"LYNDON     SHARP"
	"LEHA        TINA"
	"JUST       EVGEN"
	"JAMES    DEIGHAN"
	"ELEAZAR  GALINDO"
	"PINWIZZ         "
	"JOE      VONDAYL"
	"CAST       PIXEL"
	"IGOR R76        "
	" VALET2         "
	" KINAMAN        "
	"DMITRY     LYKIN"
	" KLAXER         "
	"NEIL     BALDWIN"
	" THEFOX         "
	"BRAD       SMITH"
	"  KHAN          "
	" NESDOUG        "
	"ROMAN    SOKOLOV"
	"CORAX89         "
	"DAVID     MURRAY"
	"JIM      LEONARD"
	"ANDERS    JENSEN"
	"NOAH        AMAN"
	"SERGIO  ELISONDO"
	"  JOEY          "
	"  JSR           "
	"TEPPLES         "
	"RUSHJET1        "
	"15KOP     MUSEUM"
	"HYPE        GANG"
	"CAFE    VISITORS"
};


const unsigned char greets_metasprite[]={
	-32,- 8,0x27,3,
	-24,- 8,0x32,3,
	-16,- 8,0x25,3,
	- 8,- 8,0x25,3,
	  0,- 8,0x34,3,
	  8,- 8,0x33,3,
	 24,- 8,0x34,3,
	 32,- 8,0x2f,3,
	128
};

const unsigned char greets_sinetable[32]={
	0,1,3,4,5,6,7,7,
	8,7,7,6,5,4,3,1,
	0,-1,-3,-4,-5,-6,-7,-7,
	-8,-7,-7,-6,-5,-4,-3,-1,
};

const unsigned char toad_metasprite[]={

	-12,-16,0x66,3,
	- 4,-16,0x67,3,
	  4,-16,0x68,3,
	-12,- 8,0x6c,3,
	- 4,- 8,0x6d,3,
	  4,- 8,0x6e,3,
	- 4,  0,0x72,3,
	-12,-24,0x5b,0,
	- 4,-24,0x5c,0,
	  4,-24,0x5d,0,
	-12,-16,0x63,0,
	- 4,-16,0x64,0,
	  4,-16,0x65,0,
	-12,- 8,0x69,0,
	- 4,- 8,0x6a,0,
	  4,- 8,0x6b,0,
	-12,  0,0x6f,0,
	- 4,  0,0x70,0,
	  4,  0,0x71,0,
	-12,  8,0x73,0,
	- 4,  8,0x74,0,
	  4,  8,0x75,0,
	-12, 16,0x76,0,
	- 4, 16,0x77,0,
	  4, 16,0x78,0,
	-20,-40,0x51,2,
	-12,-40,0x52,2,
	- 4,-40,0x53,2,
	  4,-40,0x54,2,
	 12,-40,0x55,2,
	-20,-32,0x56,2,
	-12,-32,0x57,2,
	- 4,-32,0x58,2,
	  4,-32,0x59,2,
	 12,-32,0x5a,2,
	-20,-24,0x5e,2,
	-12,-24,0x5f,2,
	- 4,-24,0x60,2,
	  4,-24,0x61,2,
	 12,-24,0x62,2,
	128
};



#define BGPAL0	0x00	//bin 00000000
#define BGPAL1	0x55	//bin 01010101
#define BGPAL2	0xaa	//bin 10101010
#define BGPAL3	0xff	//bin 11111111

#define LEVEL_HEIGHT_TILE		256
#define LEVEL_HEIGHT_PIXEL		(LEVEL_HEIGHT_TILE*8)



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

unsigned char eg_tile_off;
unsigned int eg_name_adr;
unsigned int eg_attr_adr;
const unsigned char *eg_src;

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


#define EG_STARS_ALL		16
#define EG_FP				4

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

unsigned char eg_star_x    [EG_STARS_ALL];
  signed int  eg_star_y    [EG_STARS_ALL];
  signed char eg_star_dy   [EG_STARS_ALL];
unsigned char eg_star_cnt  [EG_STARS_ALL];
unsigned char eg_star_delay[EG_STARS_ALL];

  signed int  eg_chr_frame_1;
  signed int  eg_chr_frame_2;
  signed int  eg_chr_frame_3;
  signed int  eg_chr_speed_1;
  signed int  eg_chr_speed_2;
  signed int  eg_chr_speed_3;
unsigned char eg_chr_frame_3_dir;

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

	
void eg_prepare_row_update(unsigned char name_row,unsigned int level_row)
{
	if(level_row>=LEVEL_HEIGHT_TILE) return;
	
	level_row=(LEVEL_HEIGHT_TILE)-1-level_row;
	
	if(name_row<30)//calculate tile and attribute row addresses in a nametable
	{
		eg_name_adr=NAMETABLE_A+(name_row<<5);
		eg_attr_adr=NAMETABLE_A+960+((name_row>>2)<<3);
	}
	else
	{
		name_row-=30;

		eg_name_adr=NAMETABLE_C+(name_row<<5);
		eg_attr_adr=NAMETABLE_C+960+((name_row>>2)<<3);
	}

	update_list[0]=MSB(eg_name_adr)|NT_UPD_HORZ;//set nametable update address
	update_list[1]=LSB(eg_name_adr);

	update_list[35]=MSB(eg_attr_adr)|NT_UPD_HORZ;//set attribute table update address
	update_list[36]=LSB(eg_attr_adr);
	
	eg_src=&tower_data[level_row<<5];//tile row offset in the level data

	for(_ptr=3;_ptr<3+32;++_ptr) update_list[_ptr]=*eg_src++;
	
	eg_src=&tower_data[256*32+((level_row>>2)<<3)];	//attribute offset
	
	if(name_row&2) _mask=0xf0; else _mask=0x0f;

	_ptr=38;
	
	if(level_row&2)
	{
		for(_col=0;_col<8;++_col)
		{
			_attr=*eg_src++;
			
			_attr=(_attr&0xf0)|(_attr>>4);
			
			update_list[_ptr]=(update_list[_ptr]&~_mask)|(_attr&_mask);

			++_ptr;
		}
	}
	else
	{
		for(_col=0;_col<8;++_col)
		{
			_attr=*eg_src++;

			_attr=(_attr&0x0f)|(_attr<<4);

			update_list[_ptr]=(update_list[_ptr]&~_mask)|(_attr&_mask);

			++_ptr;
		}
	}
}



void eg_preload_screen(unsigned int level_y)
{
	for(_i=0;_i<30;++_i)
	{
		eg_prepare_row_update(29-_i,level_y>>3);//prepare a row, bottom to top

		flush_vram_update();

		level_y+=8;
	}
}



void eg_greets_show(unsigned char sx,unsigned char sy,const char* str)
{
	sx-=32;
	sy-=8;
	
	_sx=sx;
	_sy=sy;
	
	for(_i=0;_i<16;++_i)
	{
		if(_i==8)
		{
			_sx=sx;
			_sy+=8;
		}
		
		_tile=*str++;

		if(_tile!=' ')
		{
			oam_spr(_sx,_sy,_tile-0x20,0,oam_off);
			oam_off+=4;
		}
		
		_sx+=8;
	}
}



void eg_stars_init(void)
{
	for(_id=0;_id<EG_STARS_ALL;++_id)
	{
		eg_star_cnt  [_id]=64;
		eg_star_delay[_id]=rand8();
	}
}



void eg_stars_update(unsigned char spawn)
{
	unsigned char n,spd,pal;
	
	pal=1+OAM_BEHIND;
	
	for(_id=0;_id<EG_STARS_ALL;++_id)
	{
		++pal;
		
		if(pal>(3+OAM_BEHIND)) pal=1+OAM_BEHIND;
		
		if(eg_star_delay[_id])
		{
			--eg_star_delay[_id];
			continue;
		}
		
		if(eg_star_cnt[_id]>=64)
		{
			if(spawn)
			{
				n=rand8();
				
				if(!(n&128))
				{
					_sx=n&63;
					spd=64-_sx/2;
				}
				else
				{
					_sx=n&31;
					spd=64-(63-_sx*2)/2;
					_sx+=224;
				}
				
				eg_star_x    [_id]=_sx;
				eg_star_y    [_id]=((rand16()&511)-64)<<EG_FP;
				eg_star_dy   [_id]=spd+(rand8()&7);
				eg_star_cnt  [_id]=0;
				eg_star_delay[_id]=rand8()&31;
			}
			
			continue;
		}
		
		if(eg_star_y[_id]>0)
		{
			oam_spr(eg_star_x[_id],eg_star_y[_id]>>EG_FP,0x40+(eg_star_cnt[_id]>>2),pal,oam_off);
			
			oam_off+=4;
		}
		
		eg_star_y[_id]+=eg_star_dy[_id];
		
		++eg_star_cnt[_id];
	}
}



void e_greets(void)
{
	unsigned char chr,ptr,bright_bg,bright_spr,flash;
	unsigned char name_row,text_sx,text_sy,text_delay,text_predelay,text_sine,scroll_predelay;
	unsigned int level_y,frame,text_off;
	int scroll_y;
	
	bank_bg(1);
	bank_spr(0);
	
	oam_clear_fast();
	oam_size(0);

	chr=CHR_GREETS_FONT;
	
	mmc3_chr_bank(chr+0,0);
	mmc3_chr_bank(chr+2,1);
	
	chr=CHR_GREETS_FONT+2;
	
	mmc3_chr_bank(chr+0,2);
	
	mmc3_set_mirroring(M_HORIZONTAL);
	
	set_irq_handler(IRQ_EMPTY);
	set_nmi_handler(NMI_NORMAL);
	
	pal_bg (greets_palette_bg);
	pal_spr(greets_palette_spr);
	pal_bright(0);

	scroll(0,0);
	
	memfill(update_list,NT_UPD_EOF,sizeof(update_list));
	
	update_list[0]=0x20|NT_UPD_HORZ;//horizontal update sequence, dummy address
	update_list[1]=0x00;
	update_list[2]=32;//length of nametable update sequence

	update_list[35]=0x20|NT_UPD_HORZ;
	update_list[36]=0x00;
	update_list[37]=8;//length of attribute update sequence

	update_list[46]=NT_UPD_EOF;
	
	eg_stars_init();
	
	eg_preload_screen(0);//fill the whole screen with beginning of the level
		
	level_y=8*30;//30 lines were already preloaded, advance the level offset
	scroll_y=0;//screen scroll value, it loops in range of 0..479 (240*2-1)
	
	frame=0;
	flash=0x0f;
	bright_bg=0;
	bright_spr=0;
	
	text_sx=0;
	text_sy=0;
	text_off=0;
	text_delay=0;
	text_predelay=EG_TEXT_PREDELAY;
	text_sine=0;
	
	eg_chr_frame_1=0;
	eg_chr_frame_2=0;
	eg_chr_frame_3=0;
	eg_chr_speed_1= 1<<EG_FP;
	eg_chr_speed_2=-1<<EG_FP;
	eg_chr_speed_3=0;
	eg_chr_frame_3_dir=0;
	
	scroll_predelay=EG_SCROLL_PREDELAY;
	
	
	ppu_on_all();
	
	while(1)
	{
		chr=CHR_TOWER_TEXTURE_1+((eg_chr_frame_1>>EG_FP)&15);
		
		mmc3_chr_bank(chr,3);
		
		chr=CHR_TOWER_TEXTURE_2+((eg_chr_frame_2>>EG_FP)&15);
		
		mmc3_chr_bank(chr,4);
		
		chr=CHR_TOWER_TEXTURE_3+((eg_chr_frame_3>>EG_FP)&15);
		
		mmc3_chr_bank(chr,5);

		pal_col(0x00,flash);
		
		if(!(frame&1))
		{
			if(flash==0x30) flash=0x10; else if(flash==0x10) flash=0x00; else if(flash==0x00) flash=0x0f;
		}
		
		if(playdump_sync)
		{
			flash=0x30;
			playdump_sync=0;
		}
		
		oam_clear_fast();		
		
		oam_off=0;

		if(frame>=EG_TOAD_FRAME)
		{
			if(frame==EG_TOAD_FRAME)
			{
				pal_spr(toad_palette);
				bright_spr=0;
			}			
		
			oam_off=oam_meta_spr(148,124,oam_off,toad_metasprite);
		}
		
		if(frame&5)
		{
			if(level_y<LEVEL_HEIGHT_PIXEL)
			{
				oam_off=oam_meta_spr(48,32,oam_off,greets_metasprite);
			}
		}
		
		if(text_predelay)
		{
			--text_predelay;
		}
		else
		{
			if(greets_list[text_off]!=0)
			{
				if(!text_sx)
				{
					text_sx=48+(rand8()&15);
					text_sy=64+rand8()%127;
				}
			
				ptr=label_palette[text_delay>>1]<<2;
				
				pal_col(0x11,text_anim_palette[ptr+1]);
				pal_col(0x12,text_anim_palette[ptr+2]);
				pal_col(0x13,text_anim_palette[ptr+3]);
				
				eg_greets_show(text_sx+label_offset[text_delay],text_sy+greets_sinetable[(text_sine>>1)&31],&greets_list[text_off]);
				
				++text_delay;
				
				if(text_delay>=EG_TEXT_DURATION)
				{
					text_sx=0;
					text_delay=0;
					text_off+=16;
					text_sine=rand8();
				}
			}
		}

		eg_stars_update(frame<EG_HIDE_STARS?1:0);
		
		if(!(level_y&7))//put new row every 8 pixels
		{
			name_row=(scroll_y>>3)+59;//update row just above the visible part of the screen

			if(name_row>=60) name_row-=60;//keep the row number within the limits

			eg_prepare_row_update(name_row,level_y>>3);

			set_vram_update();//the update is handled at next NMI
		}

		if(level_y>=LEVEL_HEIGHT_PIXEL)
		{
			level_y=LEVEL_HEIGHT_PIXEL;//stop scrolling
		}
		else
		{
			if(scroll_predelay)
			{
				--scroll_predelay;
			}
			else
			{
				scroll(0,scroll_y);//scroll value will be applied on the next nmi as well

				++level_y;
			
				--scroll_y;

				if(scroll_y<0) scroll_y=240*2-1;//keep Y within the total height of two nametables
			}
		}
		
		pal_bg_bright (bright_bg);
		pal_spr_bright(bright_spr);
		
		oam_update();
		
		ppu_wait_nmi();

		if(frame<EG_SCENE_DURATION)
		{
			if(!(frame&7))
			{
				if(bright_bg <4) ++bright_bg;
				if(bright_spr<4) ++bright_spr;
			}
		}
		else
		{
			if(!(frame&15))
			{
				if(!bright_bg&&!bright_spr) break;
				
				if(bright_bg >0) --bright_bg;
				if(bright_spr>0) --bright_spr;
			}
		}
		
		eg_chr_frame_1+=eg_chr_speed_1;
		eg_chr_frame_2+=eg_chr_speed_2;
		eg_chr_frame_3+=eg_chr_speed_3;
		
		while(eg_chr_frame_1>=(16<<EG_FP)) eg_chr_frame_1-=16<<EG_FP;
		while(eg_chr_frame_2>=(16<<EG_FP)) eg_chr_frame_2-=16<<EG_FP;
		while(eg_chr_frame_3>=(16<<EG_FP)) eg_chr_frame_3-=16<<EG_FP;
		while(eg_chr_frame_3<  0         ) eg_chr_frame_3+=16<<EG_FP;
		
		if(!eg_chr_frame_3_dir)
		{
			++eg_chr_speed_3;
			
			if(eg_chr_speed_3>=(4<<EG_FP)) eg_chr_frame_3_dir=1;
		}
		else
		{
			--eg_chr_speed_3;
			
			if(eg_chr_speed_3<=-(4<<EG_FP)) eg_chr_frame_3_dir=0;
		}
		
		++frame;
		++text_sine;
	}
	
	ppu_off();
	
	bank_bg(0);
	bank_spr(1);
}