/*******************************************************
 * Author Jonatan Hedborg                              *
 * Spread it, edit it, do whatever with it.            *
 * Just don't think you'll learn good coding from it :)*
 *******************************************************/
 
 /*******************
  * AAAAAAARGH THE STRESS
  *****************/

/********************
 * Includes         *
 ********************/
#include <allegro.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#define MAX_COINS 100

/********************************************
 * Globals. Ugly as sin but this is a hack	*
 ********************************************/
typedef struct
{
	float x,y;
} POINT;

typedef struct
{
	POINT pos;
	int active;
} COIN;

typedef struct
{
	POINT pos;
	POINT vel;
} BALL;

volatile int ticker;
int running;
BITMAP *buffer;
BITMAP *mouse_pointer;
BITMAP *player_bmp;
BITMAP *enemy_bmp;
BITMAP *coin_bmp;

BALL player_ball,enemy_ball;
COIN coins[MAX_COINS];
int time_to_spawn;
int score;

void ticker_func(void)
{
	ticker++;
}
END_OF_FUNCTION(my_timer_handler)

void generate_graphics(void)
{
	buffer = create_bitmap(640,480);
	
	mouse_pointer = create_bitmap(20,20);
	clear_to_color(mouse_pointer,makecol(255,0,255));
	hline(mouse_pointer,0,10,20,makecol(255,0,0));
	vline(mouse_pointer,10,0,20,makecol(255,0,0));

	player_bmp = create_bitmap(22,22);
	clear_to_color(player_bmp,makecol(255,0,255));
	circlefill(player_bmp,10,10,10,makecol(200,200,0));
	circlefill(player_bmp,6,6,3,makecol(255,255,0));
	
	enemy_bmp = create_bitmap(42,42);
	clear_to_color(enemy_bmp,makecol(255,0,255));
	circlefill(enemy_bmp,20,20,20,makecol(180,180,180));
	circlefill(enemy_bmp,12,12,5,makecol(220,220,220));
	
	coin_bmp = create_bitmap(11,11);
	clear_to_color(coin_bmp,makecol(255,0,255));
	circlefill(coin_bmp,5,5,5,makecol(0,210,0));
	circlefill(coin_bmp,3,3,2,makecol(0,255,0));
}

void destroy_graphics(void)
{
	destroy_bitmap(buffer);
	destroy_bitmap(player_bmp);
	destroy_bitmap(enemy_bmp);
	destroy_bitmap(coin_bmp);
}


int game_over(void)
{
	char out[1024];
	sprintf(out,"Game over. Score: %d. Press Right LB to try again, RB to quit",score);
	clear(screen);
	textout_ex(screen,font,out,1,1,makecol(255,255,255),-1);
	while(1)
	{
		if( mouse_b&1 ) return 0;
		else if( mouse_b&2 ) return 1;
	}
}

int count_coins(void)
{
	int c = 0;
	int i;
	
	for(i=0; i<MAX_COINS; i++)
		if( coins[i].active == 1 ) c++;
		
	return c;
}

int is_overlapping(POINT p1, float s1, POINT p2, float s2)
{
	POINT d;
	d.x = p1.x-p2.x;
	d.y = p1.y-p2.y;
	if( d.x*d.x + d.y*d.y < (s1+s2) *(s1+s2) ) return 1;
	else return 0;
}

float get_distance(POINT p1, POINT p2)
{
	return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) );
}

void add_coin(void)
{
	time_to_spawn = (rand()%50)+25;
	if( count_coins() < 100 )
	{
		int i;
		for(i=0; i<MAX_COINS; i++)
			if( coins[i].active == 0 ) break;
		
		coins[i].pos.x = (rand()%600)+20;	
		coins[i].pos.y = (rand()%440)+20;
		coins[i].active = 1;
	}
}

void take_coin(int i)
{
	coins[i].active = 0;
	score += 1;
	
}

void run_game(void)
{
	add_coin();
	while( running )
	{
		while( ticker > 0 )
		{
			ticker--;
			
			float angle_to_mouse = atan2(mouse_y - player_ball.pos.y, mouse_x - player_ball.pos.x);
			float angle_to_player = atan2(player_ball.pos.y - enemy_ball.pos.y, player_ball.pos.x - enemy_ball.pos.x);
			
			
			player_ball.vel.x += cos(angle_to_mouse)*25;
			player_ball.vel.y += sin(angle_to_mouse)*25;
			player_ball.vel.x *= 0.985; //"Friction"
			player_ball.vel.y *= 0.985;
			
			player_ball.pos.x += player_ball.vel.x/100;
			player_ball.pos.y += player_ball.vel.y/100;
			
			float dist_player = get_distance(player_ball.pos,enemy_ball.pos);
			if( dist_player < 200 ) dist_player = 200;
			enemy_ball.vel.x += cos(angle_to_player)*0.07*dist_player;
			enemy_ball.vel.y += sin(angle_to_player)*0.07*dist_player;
			enemy_ball.pos.x += enemy_ball.vel.x/100;
			enemy_ball.pos.y += enemy_ball.vel.y/100;
			enemy_ball.vel.x *= 0.98; //"Friction"
			enemy_ball.vel.y *= 0.98;
			
			if( player_ball.pos.x < 10 || player_ball.pos.x > 620 )
				player_ball.vel.x = -player_ball.vel.x;

			if( player_ball.pos.y < 10 || player_ball.pos.y > 460 )
				player_ball.vel.y = -player_ball.vel.y;

			if( enemy_ball.pos.x < 20 || enemy_ball.pos.x > 600 )
				enemy_ball.vel.x = -enemy_ball.vel.x;

			if( enemy_ball.pos.y < 20 || enemy_ball.pos.y > 440 )
				enemy_ball.vel.y = -enemy_ball.vel.y;

	
			if( is_overlapping( player_ball.pos, 10, enemy_ball.pos, 20 ) == 1 ) 
				running = 0;
				
			
			time_to_spawn--;
			if( time_to_spawn <= 0 )
				add_coin();
				
			int i;
			for(i=0; i<MAX_COINS; i++)
			{
				if( coins[i].active == 1 )
				{
					if( is_overlapping( player_ball.pos, 10, coins[i].pos, 5 ) == 1 )
						take_coin(i);
				}
			}	
		}
		
		/* Redraw here */
		draw_sprite(buffer,player_bmp,player_ball.pos.x-10,player_ball.pos.y-10);
		draw_sprite(buffer,enemy_bmp,enemy_ball.pos.x-20,enemy_ball.pos.y-20);
		
		draw_sprite(buffer,mouse_pointer,mouse_x-10,mouse_y-10);		
		int i;
		for(i=0; i<MAX_COINS; i++)
		{
			if( coins[i].active == 1 ) 
				draw_sprite(buffer, coin_bmp,coins[i].pos.x-5, coins[i].pos.y-5);
		}
		
		char text[1024];
		sprintf(text,"Score: %d",score);
		textout_ex(buffer,font,text,1,1,makecol(255,255,255),-1);	
		
		/* And show the buffer */
		blit(buffer,screen,0,0,0,0,640,480);
		clear(buffer);
	}
}

void init_vars(void)
{
	running = 1;
	ticker = 0;
	
	player_ball.pos.x = 50;
	player_ball.pos.y = 50;
	player_ball.vel.x = 0;
	player_ball.vel.y = 0;
	
	enemy_ball.pos.x = 590;
	enemy_ball.pos.y = 440;
	enemy_ball.vel.x = 0;
	enemy_ball.vel.y = 0;

	score = 0;

	int i;
	for(i=0; i<MAX_COINS; i++)
		coins[i].active = 0;	
}

int main(void)
{
	allegro_init();
	
	srand(time(0));
	
	LOCK_VARIABLE(ticker);
	LOCK_FUNCTION(ticker_func);
	install_int_ex(ticker_func,BPS_TO_TIMER(50));

	install_mouse();
	
	set_color_depth(16);
	set_gfx_mode(GFX_AUTODETECT_WINDOWED,640,480,0,0);
	
	generate_graphics();
	
	do {
		init_vars();
		run_game();
	} while( !game_over() );
	
	destroy_graphics();
	return 0;
}
END_OF_MAIN()
