#include "main.h"

//#include "graphics/sprites.raw.c"
//#include "graphics/sprites.pal.c"
//#include "graphics/font.raw.c"

#define PLAYER_EXPLODE_SPEED 8

#define GAMEOVER_TEXT_LEN 5

extern mod_header m;

void write_score(u16* map, u16 map_width, u16 x, u16 y, int val, int pad)
{
	char buf[pad];
	char fmtstr[5];
	int i;

	fmtstr[0] = '%'; fmtstr[1] = '0';
	fmtstr[2] = pad + '0';
	fmtstr[3] = 'd'; fmtstr[4] = 0;
	sprintf(buf, fmtstr, val);

	for(i=0; i < pad; i++)
	{
		map[(y * map_width) + x + i] = buf[i] - ('0' - 1);
	}
}

/* generate a random starfield for scrolling behind the game */
void generate_starfield(u16* map)
{
	int x, y;

	for(y=0; y < 20; y++)
	{
		for(x=0; x < 15; x++)
		{
			u32 star1 = rand() / (RAND_MAX / 60);
			u32 star2 = rand() / (RAND_MAX / 60);
			map[(y * 32) + x] = star1 | (star2 << 8);
			map[(y * 32) + x + 15] = star1 | (star2 << 8);
		}
	}
}
/**
 * Run the game
 * @return player's score
 */
int game_run()
{
	Bg bg, starbg;
	game g;
	
	u16 channels[4];

	s32 loop;
	u16* temp;
	int score, i, mod_pause=0;
	int die = 0;
	char foo[100];

	int wave = 0;
	int wave_timer = 0;
	int wave_length = 300;

	int aliens_per_wave = 5;
	int waves = 10;

	int gameover_sprites[GAMEOVER_TEXT_LEN];
	
	InitialiseSprites();
	SetMode(MODE_1 | BG1_ENABLE | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D);

	bg.number = 1;
	bg.charBaseBlock = 0;
	bg.screenBaseBlock = 24;
	bg.colorMode = BG_COLOR_256;
	bg.size = TEXTBG_SIZE_256x256;
	bg.x_scroll = 0; bg.y_scroll = 0;
	bg.mosaic = 0; bg.wraparound = 0;

	EnableBackground(&bg);
	UpdateBackground(&bg);

	starbg.number = 2;
	starbg.charBaseBlock = 1;
	starbg.screenBaseBlock = 28;
	starbg.colorMode = BG_COLOR_256;
	starbg.size = ROTBG_SIZE_512x512;
	//starbg.size = TEXTBG_SIZE_256x256;
	starbg.x_scroll = 0; starbg.y_scroll = 0;
	starbg.mosaic = 0; starbg.wraparound = 0;
	
	EnableBackground(&starbg);
	UpdateBackground(&starbg);

	/* set starfield background to minimum priority */
	REG_BG2CNT |= 3;

	/* set up palette and tiles for background */
	for(loop = 0; loop < 256; loop++)
		BGPaletteMem[loop] = intro_planet_Palette[loop];

	temp = (u16*)intro_planet_Bitmap;
	for(loop=0; loop < 32 * (30 * 4); loop++)
		starbg.tileData[loop] = temp[loop];
	
	/* copy text images into tile ram */
	temp = (u16*) font_Bitmap;
	for(loop = 0; loop < (4 * 8) * 64; loop++)
		bg.tileData[loop] = temp[loop];

	/* generate a starfield */
	generate_starfield(starbg.mapData);
	
	/* load sprite palette and tile data */
	for(loop = 0; loop < 256; loop++)
	{
		OBJPaletteMem[loop] = sprites_Palette[loop];
	}
	
	temp = (u16*) sprites_Bitmap;
	for(loop = 0; loop < (2 * 16) * (32*4); loop++)
	{
		OAMData[loop] = temp[loop];
	}
	
	g.ship = playership_new();
	g.num_aliens = aliens_per_wave * waves;
	g.aliens = calloc(g.num_aliens, sizeof(alien));
	g.charMap = bg.mapData;
	g.alien_bullets_num = 10;
	g.alien_bullets = aliens_create_bullets(g.alien_bullets_num);

	/* allocate channels */
	for(i=0; i<4; i++)
	{
		channels[i] = sfxSystemAllocChannel();
	}
	m.master_volume = 12;

	sfxSystemInit();

	/* main game loop */
	while(!die)
	{
		u32 keys = *KEYS;

		if(wave_timer == 0)
		{
			aliens_free_wave(&g.aliens[wave * aliens_per_wave], aliens_per_wave);
			memset(&g.aliens[wave * aliens_per_wave], 0, sizeof(alien) * aliens_per_wave);

			if(rand() > (RAND_MAX / 2))
			{
				aliens_create_wave_purple(&g.aliens[wave * aliens_per_wave], aliens_per_wave);
			} else {
				aliens_create_wave_blue(&g.aliens[wave * aliens_per_wave], aliens_per_wave);
			}

			wave_timer = wave_length;
			if(wave_length > 35) wave_length -= 5;

			wave++;
			if(wave == waves) wave = 0;
		}
		wave_timer--;

		playership_read_keys(g.ship, keys);
		aliens_draw(&g);
		playership_draw(&g);
		if(collide_aliens_bullets_ship(&g))
		{
			die = 1;
		}
		
		starbg.x_scroll += 64;
		if(starbg.x_scroll > (256 * 240)) starbg.x_scroll = 0;
		UpdateBackground(&starbg);
		CopyOAM();
		
		sprintf(foo, "%d\n", REG_TM0D);
		//print(foo);

		if(mod_pause == 3)
		{
			mod_play(&m, channels);
			mod_pause = 0;
		}
		mod_pause++;
		
		sfxSystemWorker();
		gba_vsync();
	}

	/* we're dead - do the "game over" thang */
	sfxSystemPlay(&exp_sample);
	for(loop=0; loop < PLAYER_EXPLODE_SPEED * EXPLOSION_FRAMES_NUM; loop++)
	{
		aliens_draw(&g);
		g.ship->sprite.tile = ((loop / PLAYER_EXPLODE_SPEED) + EXPLOSION_FRAMES_START - 1) * (4*2);
		playership_draw(&g);
		
		CopyOAM();
		if(mod_pause == 3)
		{
			mod_play(&m, channels);
			mod_pause = 0;
		}
		mod_pause++;
		sfxSystemWorker();
		gba_vsync();
	}
	
	/* scroll gameover text */
	for(loop=0; loop < GAMEOVER_TEXT_LEN; loop++)
	{
		gameover_sprites[loop] = sprite_alloc();
	}
	
	for(loop=-16; loop < 80-8; loop++)
	{
		int i;
		for(i=0; i < GAMEOVER_TEXT_LEN; i++)
		{
			int s = gameover_sprites[i];
			sprites[s].attribute0 = COLOR_256 | SQUARE | MOSAIC | (loop & 0xff);
			sprites[s].attribute1 = SIZE_16 | (120 - (80/2) + (i * 16));
			sprites[s].attribute2 = ((10 + i) * (4*2));
		}

		aliens_draw(&g);
		g.ship->sprite.tile = (EXPLOSION_FRAMES_START + EXPLOSION_FRAMES_NUM - 1) * (4*2);
		playership_draw(&g);
		
		CopyOAM();
		
		m.master_volume = 12 - ((loop+16) * 12 / (80-8+16));
		if(mod_pause == 3)
		{
			mod_play(&m, channels);
			mod_pause = 0;
		}
		mod_pause++;
		sfxSystemWorker();
		gba_vsync();
	}

	/* let the gameover text sit there for a while */
	for(loop=0; loop < 200; loop++)
	{
		aliens_draw(&g);
		g.ship->sprite.tile = (EXPLOSION_FRAMES_START + EXPLOSION_FRAMES_NUM - 1) * (4*2);
		playership_draw(&g);
		
		CopyOAM();
		sfxSystemWorker();
		gba_vsync();
	}

	for(i=0; i<4; i++)
	{
		sfxSystemFreeChannel(channels[i]);
	}

	sfxSystemStop();

	/* do a neat mosaic fade effect */
	REG_BG1CNT |= BG_MOSAIC_ENABLE;
	REG_BG2CNT |= BG_MOSAIC_ENABLE;
	mosaic_fade(intro_planet_Palette, sprites_Palette);
	
	for(loop=0; loop < GAMEOVER_TEXT_LEN; loop++)
	{
		sprite_free(gameover_sprites[loop]);
	}

	score = g.ship->score;
	free(g.ship);
	free(g.aliens);
	free(g.alien_bullets);

	return(score);
}
