#include <allegro5/allegro5.h>

#ifdef ALLEGRO_WINDOWS
	#include <allegro5/winalleg.h>
	#include <d3d9.h>
	#include <d3dx9.h>
#endif

/* Allegro add-ons */
#include <allegro5/a5_iio.h>
#include <allegro5/a5_font.h>
#include <allegro5/kcm_audio.h>
#include <allegro5/acodec.h>
#include <stdio.h>
#include <math.h>

/* my add-ons */
#include "ocd3d.h"
#include "ocdfont.h"

/* program includes */
#include "main.h"
#include "shield.h"
#include "threat.h"
#include "ship.h"
#include "particle.h"

/* Allegro data */
ALLEGRO_DISPLAY * rw_display;
ALLEGRO_TIMER * rw_timer;
ALLEGRO_EVENT_QUEUE * rw_queue;
ALLEGRO_STREAM * rw_stream = NULL;

/* intro data */
float rw_intro_z = -700.0;
float rw_intro_planet_z = 40.0;
float rw_intro_planet_angle = 0.0;
float rw_intro_planet_vangle = 0.0;
int   rw_intro_state = 0;
int   rw_intro_ticker = 0;
float rw_start_alpha = 0.0;
float rw_logo_z = 0.0;

/* game data */
int rw_ticks = 0;
int rw_quit = 0;
ALLEGRO_BITMAP * rw_bitmap[RW_MAX_BITMAPS] = {NULL};
ALLEGRO_FONT * rw_font = NULL;
ALLEGRO_SAMPLE * rw_sample[RW_MAX_SAMPLES] = {NULL};
int rw_score = 0;
int rw_high_score = 1800;
bool rw_new_high_score = false;
int rw_threat_count = 0;
int rw_level = 0;
int rw_damage = 0;
int rw_damage_time = 0;
int rw_alert_ticks = 0;
int rw_alert_audio_ticks = 0;
float rw_camera_z = 0.0;
float rw_camera_target_z = 0.0;
int rw_state = RW_STATE_INTRO;
bool rw_music_on = true;

RW_SHIELD_GENERATOR rw_shield_generator;
RW_THREAT rw_threat[RW_MAX_THREATS];
RW_SHIP rw_ship[RW_MAX_SHIPS];
RW_SHOT rw_shot[RW_MAX_SHOTS];
RW_PARTICLE rw_particle[RW_MAX_PARTICLES];

/* the eight ways from which to die */
float rw_eight_ways[8] = 
{
	((2.0 * ALLEGRO_PI) / 8.0) * 5.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 6.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 7.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 8.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 9.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 10.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 11.0,
	((2.0 * ALLEGRO_PI) / 8.0) * 12.0,
};

/* level variables */
int rw_level_threat_ticks[RW_MAX_LEVELS] =  {60,   58,    56,    54,    52,    50,    48,    46,    44,    42,    40,    38,   36,    34,    32,    30,    28,    26,    24,    20};
int rw_level_prob_total[RW_MAX_LEVELS] =   {100,  100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100,   100};
int rw_level_prob[RW_MAX_LEVELS] =          {50,   51,    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,    66,    67,    68,    70};
float rw_level_camera_z[RW_MAX_LEVELS] =   {0.0, -10.0, -20.0, -30.0, -40.0, -50.0, -60.0, -70.0, -80.0, -90.0, -100.0, -110.0, -120.0, -130.0, -140.0, -150.0, -160.0, -170.0, -180.0, -190.0};

#define RS_SCALE (1.0 / (1.0 + RAND_MAX))
double drand (void)
{
	double d;
	do
	{
		d = (((rand () * RS_SCALE) + rand ()) * RS_SCALE + rand ()) * RS_SCALE;
	} while (d >= 1); /* Round off */
	return d;
}

int rw_save_high_score(char * fn)
{
	ALLEGRO_FS_ENTRY * fp;
	
	fp = al_fopen(fn, "wb");
	if(!fp)
	{
		return 0;
	}
	al_fwrite32le(fp, rw_high_score);
	al_fputc(fp, rw_music_on);
	al_fclose(fp);
	return 1;
}

int rw_load_high_score(char * fn)
{
	ALLEGRO_FS_ENTRY * fp;
	
	fp = al_fopen(fn, "rb");
	if(!fp)
	{
		return 0;
	}
	rw_high_score = al_fread32le(fp);
	rw_music_on = al_fgetc(fp);
	al_fclose(fp);
	return 1;
}

void rw_play_music(char * fn)
{
	if(rw_music_on)
	{
		rw_stream = al_stream_from_file(4, 4096, fn);
		al_set_stream_enum(rw_stream, ALLEGRO_AUDIOPROP_LOOPMODE, ALLEGRO_PLAYMODE_LOOP);
		al_attach_stream_to_mixer(al_get_default_mixer(), rw_stream);
	}
}

void rw_stop_music(void)
{
	if(rw_stream)
	{
		al_stop_timer(rw_timer);
		al_drain_stream(rw_stream);
		al_destroy_stream(rw_stream);
		rw_stream = NULL;
		al_start_timer(rw_timer);
	}
}

void rw_toggle_music(void)
{
	if(rw_music_on)
	{
		if(rw_stream)
		{
			rw_stop_music();
		}
		rw_music_on = false;
	}
	else
	{
		rw_music_on = true;
		switch(rw_state)
		{
			case RW_STATE_INTRO:
			case RW_STATE_TITLE:
			case RW_STATE_GAME_OUT:
			{
				rw_play_music("data/intromusic.ogg");
				break;
			}
			case RW_STATE_GAME_IN:
			case RW_STATE_GAME:
			case RW_STATE_GAME_OVER:
			{
				rw_play_music("data/gamemusic.ogg");
				break;
			}
		}
	}
}

float rw_distance(float x1, float y1, float x2, float y2)
{
	return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}

void rw_generate_threat(void)
{
	int i;
	int r;
	float rs;
	float a;
	float ar;
	
	for(i = 0; i < RW_MAX_THREATS; i++)
	{
		if(!rw_threat[i].active)
		{
			r = rand() % 8;
			rs = 1.6 + (float)(rand() % 100) / 40.0;
			ar = (float)(rand() % 100) / 1000.0 - 0.05;
			a = rw_eight_ways[r] + (drand() - 0.5) / 10.0;
			rw_threat[i].x = 320.0 + cos(a) * 400.0;
			rw_threat[i].y = 240.0 + sin(a) * 400.0;
			rw_threat[i].vx = cos(a) * -rs;
			rw_threat[i].vy = sin(a) * -rs;
			rw_threat[i].angle = 0.0;
			rw_threat[i].vangle = (float)((float)(rand() % 100) / 400.0 - 0.125);
			rw_threat[i].type = r;
			rw_threat[i].active = true;
			rw_threat_count++;
			break;
		}
	}
}

void rw_generate_particle(float x, float y, float min_angle, float max_angle)
{
	int i;
	float a, r;
	
	if(min_angle > max_angle)
	{
		min_angle -= ALLEGRO_PI * 2.0;
	}
	for(i = 0; i < RW_MAX_PARTICLES; i++)
	{
		if(!rw_particle[i].active)
		{
			rw_particle[i].x = x;
			rw_particle[i].y = y;
			a = drand() * (max_angle - min_angle) + min_angle;
			r = drand() * (1.5 - 0.5) + 0.5;
			rw_particle[i].vx = cos(a) * r;
			rw_particle[i].vy = sin(a) * r;
			rw_particle[i].life = 30 + rand() % 15;
			rw_particle[i].tlife = rw_particle[i].life;
			rw_particle[i].active = true;
			break;
		}
	}
}

void rw_destroy_everything(void)
{
	int i, j;
	int c = 0;
	
	for(i = 0; i < RW_MAX_THREATS; i++)
	{
		if(rw_threat[i].active)
		{
			for(j = 0; j < 8; j++)
			{
				rw_generate_particle(rw_threat[i].x, rw_threat[i].y, 0.0, ALLEGRO_PI * 2.0);
			}
			c++;
			rw_threat[i].active = false;
		}
	}
	for(i = 0; i < RW_MAX_SHOTS; i++)
	{
		if(rw_shot[i].active)
		{
			for(j = 0; j < 6; j++)
			{
				rw_generate_particle(rw_shot[i].x, rw_shot[i].y, 0.0, ALLEGRO_PI * 2.0);
			}
			c++;
			rw_shot[i].active = false;
		}
	}
	for(i = 0; i < RW_MAX_SHIPS; i++)
	{
		if(rw_ship[i].active)
		{
			for(j = 0; j < 16; j++)
			{
				rw_generate_particle(rw_ship[i].x, rw_ship[i].y, 0.0, ALLEGRO_PI * 2.0);
			}
			c++;
			rw_ship[i].active = false;
		}
	}
	if(c)
	{
		al_play_sample(rw_sample[RW_SAMPLE_DAMAGE], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
	}
}

void rw_logic(void)
{
	int i, j, r;
	float min_angle = 0.0, max_angle = 0.0;
	int dt = 0;
	
	switch(rw_state)
	{
		case RW_STATE_INTRO:
		{
			switch(rw_intro_state)
			{
				case 0:
				{
					rw_intro_z += 10.0;
					if(rw_intro_z >= 0.0)
					{
						rw_intro_z = 0.0;
						rw_intro_state = 1;
						rw_intro_ticker = 0;
					}
					break;
				}
				case 1:
				{
					rw_intro_ticker++;
					if(rw_intro_ticker >= 120)
					{
						al_play_sample(rw_sample[RW_SAMPLE_LOGO_OUT], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
						rw_intro_state = 2;
						rw_intro_ticker = 30;
					}
					break;
				}
				case 2:
				{
					rw_intro_z += 10.0;
					rw_intro_ticker--;
					if(rw_intro_ticker <= 0)
					{
						rw_intro_state = 3;
					}
					break;
				}
				case 3:
				{
					rw_intro_planet_z -= 10.0;
					if(rw_intro_planet_z <= -400.0)
					{
						rw_intro_planet_z = -400.0;
						rw_state = RW_STATE_TITLE;
					}
					rw_intro_planet_angle += 0.01;
					break;
				}
			}
			break;
		}
		case RW_STATE_TITLE:
		{
			rw_intro_planet_angle += 0.01;
			if(rw_intro_planet_angle >= ALLEGRO_PI * 2.0)
			{
				rw_intro_planet_angle -= ALLEGRO_PI * 2.0;
			}
			rw_start_alpha += 0.025;
			if(rw_start_alpha > 1.0)
			{
				rw_start_alpha = 0.0;
			}
			rw_logo_z -= 0.1;
			if(rw_logo_z <= -10.0)
			{
				rw_logo_z = 0.0;
			}
			break;
		}
		case RW_STATE_GAME_IN:
		{
			rw_intro_planet_z += 10.0;
			if(rw_intro_planet_z >= 0.0)
			{
				rw_state = RW_STATE_GAME;
			}
			rw_intro_planet_angle += rw_intro_planet_vangle;
			break;
		}
		case RW_STATE_GAME_OUT:
		{
			rw_intro_planet_z -= 10.0;
			rw_intro_planet_angle += 0.01;
			if(rw_intro_planet_z <= -400.0)
			{
				rw_intro_planet_z = -400.0;
				rw_state = RW_STATE_TITLE;
			}
			break;
		}
		case RW_STATE_GAME_OVER:
		{
			int pcount = 0;
			for(i = 0; i < RW_MAX_PARTICLES; i++)
			{
				if(rw_particle[i].active)
				{
					rw_particle[i].x += rw_particle[i].vx;
					rw_particle[i].y += rw_particle[i].vy;
					rw_particle[i].life--;
					if(rw_particle[i].life <= 0)
					{
						rw_particle[i].active = false;
					}
					pcount++;
				}
			}
			if(pcount <= 0)
			{
				rw_stop_music();
				rw_play_music("data/intromusic.ogg");
				rw_state = RW_STATE_GAME_OUT;
			}
			
			for(i = 0; i < RW_MAX_SHIELDS; i++)
			{
				if(rw_shield_generator.shield[i].life > 0)
				{
					rw_shield_generator.shield[i].life--;
					if(rw_shield_generator.shield[i].life <= 0)
					{
						rw_shield_generator.shield[i].active = false;
					}
				}
			}
			switch(rw_damage)
			{
				case 0:
				{
					dt = 0;
					break;
				}
				case 1:
				{
					dt = 5;
					break;
				}
				case 2:
				{
					dt = 10;
					break;
				}
				case 3:
				{
					dt = 15;
					break;
				}
				case 4:
				{
					dt = 20;
					break;
				}
			}
			if(rw_damage_time > dt)
			{
				rw_damage_time--;
			}
			break;
		}
		case RW_STATE_GAME:
		{
			/* camera logic */
			if(rw_camera_z > rw_level_camera_z[rw_level])
			{
				rw_camera_z -= 0.5;
			}
			
			for(i = 0; i < RW_MAX_PARTICLES; i++)
			{
				if(rw_particle[i].active)
				{
					rw_particle[i].x += rw_particle[i].vx;
					rw_particle[i].y += rw_particle[i].vy;
					rw_particle[i].life--;
					if(rw_particle[i].life <= 0)
					{
						rw_particle[i].active = false;
					}
				}
			}
			
			for(i = 0; i < RW_MAX_SHIELDS; i++)
			{
				if(rw_shield_generator.shield[i].life > 0)
				{
					rw_shield_generator.shield[i].life--;
					if(rw_shield_generator.shield[i].life <= 0)
					{
						rw_shield_generator.shield[i].active = false;
					}
				}
			}
			switch(rw_damage)
			{
				case 0:
				{
					dt = 0;
					break;
				}
				case 1:
				{
					dt = 5;
					break;
				}
				case 2:
				{
					dt = 10;
					break;
				}
				case 3:
				{
					dt = 15;
					break;
				}
				case 4:
				{
					dt = 20;
					break;
				}
			}
			if(rw_damage_time > dt)
			{
				rw_damage_time--;
			}
			if(rw_damage >= 4)
			{
				rw_alert_ticks++;
				if(rw_alert_ticks > 20)
				{
					rw_alert_ticks = 0;
				}
				if(rw_alert_audio_ticks == 0)
				{
					al_play_sample(rw_sample[RW_SAMPLE_ALERT], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
				}
				rw_alert_audio_ticks++;
				if(rw_alert_audio_ticks >= 60)
				{
					rw_alert_audio_ticks = 0;
				}
			}
			for(i = 0; i < RW_MAX_THREATS; i++)
			{
				if(rw_threat[i].active)
				{
					rw_threat[i].x += rw_threat[i].vx;
					rw_threat[i].y += rw_threat[i].vy;
					rw_threat[i].angle += rw_threat[i].vangle;
					if(rw_distance(320.0, 240.0, rw_threat[i].x, rw_threat[i].y) < 36.0)
					{
						al_play_sample(rw_sample[RW_SAMPLE_DAMAGE], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
						if(rw_threat[i].type == 0)
						{
							min_angle = rw_eight_ways[7];
							max_angle = rw_eight_ways[1];
						}
						else if(rw_threat[i].type == 7)
						{
							min_angle = rw_eight_ways[6];
							max_angle = rw_eight_ways[0];
						}
						else
						{
							min_angle = rw_eight_ways[rw_threat[i].type - 1];
							max_angle = rw_eight_ways[rw_threat[i].type + 1];
						}
						for(j = 0; j < 8; j++)
						{
							rw_generate_particle(rw_threat[i].x, rw_threat[i].y, min_angle, max_angle);
						}
						rw_threat[i].active = 0;
						rw_damage++;
						rw_damage_time = 20;
						if(rw_damage > 4)
						{
							rw_destroy_everything();
							rw_state = RW_STATE_GAME_OVER;
							rw_intro_planet_z = rw_camera_z;
							rw_alert_ticks = 0;
						}
					}
					else if(rw_distance(320.0, 240.0, rw_threat[i].x, rw_threat[i].y) < 48.0)
					{
						if(rw_shield_generator.shield[rw_threat[i].type].active)
						{
							al_play_sample(rw_sample[RW_SAMPLE_HIT], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
							if(rw_threat[i].type == 0)
							{
								min_angle = rw_eight_ways[7];
								max_angle = rw_eight_ways[1];
							}
							else if(rw_threat[i].type == 7)
							{
								min_angle = rw_eight_ways[6];
								max_angle = rw_eight_ways[0];
							}
							else
							{
								min_angle = rw_eight_ways[rw_threat[i].type - 1];
								max_angle = rw_eight_ways[rw_threat[i].type + 1];
							}
							for(j = 0; j < 5; j++)
							{
								rw_generate_particle(rw_threat[i].x, rw_threat[i].y, min_angle, max_angle);
							}
							rw_threat[i].active = 0;
							rw_shield_generator.shield[rw_threat[i].type].active = 0;
							rw_shield_generator.shield[rw_threat[i].type].life = RW_SHIELD_MAX_LIFE;
						}
					}
				}
			}
			
			for(i = 0; i < RW_MAX_SHOTS; i++)
			{
				if(rw_shot[i].active)
				{
					rw_shot[i].x += rw_shot[i].vx;
					rw_shot[i].y += rw_shot[i].vy;
					if(rw_distance(320.0, 240.0, rw_shot[i].x, rw_shot[i].y) < 36.0)
					{
						al_play_sample(rw_sample[RW_SAMPLE_HIT], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
						if(rw_shot[i].type == 0)
						{
							min_angle = rw_eight_ways[7];
							max_angle = rw_eight_ways[1];
						}
						else if(rw_shot[i].type == 7)
						{
							min_angle = rw_eight_ways[6];
							max_angle = rw_eight_ways[0];
						}
						else
						{
							min_angle = rw_eight_ways[rw_shot[i].type - 1];
							max_angle = rw_eight_ways[rw_shot[i].type + 1];
						}
						for(j = 0; j < 5; j++)
						{
							rw_generate_particle(rw_shot[i].x, rw_shot[i].y, min_angle, max_angle);
						}
						rw_shot[i].active = 0;
						rw_damage++;
						rw_damage_time = 20;
						if(rw_damage > 4)
						{
							rw_state = RW_STATE_GAME_OVER;
						}
					}
					else if(rw_distance(320.0, 240.0, rw_shot[i].x, rw_shot[i].y) < 48.0)
					{
						if(rw_shield_generator.shield[rw_shot[i].type].active)
						{
							al_play_sample(rw_sample[RW_SAMPLE_HIT], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
							if(rw_shot[i].type == 0)
							{
								min_angle = rw_eight_ways[7];
								max_angle = rw_eight_ways[1];
							}
							else if(rw_shot[i].type == 7)
							{
								min_angle = rw_eight_ways[6];
								max_angle = rw_eight_ways[0];
							}
							else
							{
								min_angle = rw_eight_ways[rw_shot[i].type - 1];
								max_angle = rw_eight_ways[rw_shot[i].type + 1];
							}
							for(j = 0; j < 3; j++)
							{
								rw_generate_particle(rw_shot[i].x, rw_shot[i].y, min_angle, max_angle);
							}
							rw_shot[i].active = 0;
							rw_shield_generator.shield[rw_shot[i].type].active = 0;
							rw_shield_generator.shield[rw_shot[i].type].life = RW_SHIELD_MAX_LIFE;
		//					rw_score += 25;
						}
					}
				}
			}
			
			for(i = 0; i < RW_MAX_SHIPS; i++)
			{
				if(rw_ship[i].active)
				{
					rw_ship[i].angle += rw_ship[i].vangle;
					if(rw_ship[i].vangle > 0.0)
					{
						if(rw_ship[i].way == 0)
						{
							if(rw_ship[i].angle >= rw_eight_ways[rw_ship[i].way] + ALLEGRO_PI * 2.0)
							{
								rw_ship[i].angle = rw_eight_ways[rw_ship[i].way];
								rw_ship[i].vangle = 0.0;
							}
						}
						else
						{
							if(rw_ship[i].angle >= rw_eight_ways[rw_ship[i].way])
							{
								rw_ship[i].angle = rw_eight_ways[rw_ship[i].way];
								rw_ship[i].vangle = 0.0;
							}
						}
					}
					else if(rw_ship[i].vangle < 0.0)
					{
						if(rw_ship[i].way == 7)
						{
							if(rw_ship[i].angle <= rw_eight_ways[rw_ship[i].way] - ALLEGRO_PI * 2.0)
							{
								rw_ship[i].angle = rw_eight_ways[rw_ship[i].way];
								rw_ship[i].vangle = 0.0;
							}
						}
						else
						{
							if(rw_ship[i].angle <= rw_eight_ways[rw_ship[i].way])
							{
								rw_ship[i].angle = rw_eight_ways[rw_ship[i].way];
								rw_ship[i].vangle = 0.0;
							}
						}
					}
					rw_ship[i].dist += rw_ship[i].vdist;
					if(rw_ship[i].dist <= rw_ship[i].dest)
					{
						rw_ship[i].vdist = 0.0;
					}
					rw_ship[i].x = 320.0 + cos(rw_ship[i].angle) * rw_ship[i].dist;
					rw_ship[i].y = 240.0 + sin(rw_ship[i].angle) * rw_ship[i].dist;
					if(rw_ship[i].vangle == 0.0 && rw_ship[i].vdist == 0.0)
					{
						rw_ship[i].ticks++;
						if(rw_ship[i].ticks == 15)
						{
							r = rand() % 100;
							if(r < 75)
							{
								for(j = 0; j < RW_MAX_SHOTS; j++)
								{
									if(!rw_shot[j].active)
									{
										rw_shot[j].x = 320.0 + cos(rw_ship[i].angle) * rw_ship[i].dist;
										rw_shot[j].y = 240.0 + sin(rw_ship[i].angle) * rw_ship[i].dist;
										rw_shot[j].vx = cos(rw_ship[i].angle) * -3.0;
										rw_shot[j].vy = sin(rw_ship[i].angle) * -3.0;
										rw_shot[j].type = rw_ship[i].way;
										rw_shot[j].active = true;
										break;
									}
								}
							}
						}
						if(rw_ship[i].ticks > 30)
						{
							r = rand() % 100;
							if(r < 75)
							{
								rw_ship[i].way++;
								if(rw_ship[i].way > 7)
								{
									rw_ship[i].way = 0;
								}
								rw_ship[i].vangle = 0.005;
							}
							else
							{
								rw_ship[i].way--;
								if(rw_ship[i].way < 0)
								{
									rw_ship[i].way = 7;
								}
								rw_ship[i].vangle = -0.005;
							}
							rw_ship[i].ticks = 0;
						}
					}
				}
			}
			
			rw_ticks++;
			rw_score++;
			if(rw_score > rw_high_score)
			{
				rw_high_score = rw_score;
				if(!rw_new_high_score)
				{
					al_play_sample(rw_sample[RW_SAMPLE_HIGH_SCORE], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_new_high_score = true;
				}
			}
			
			/* generate enemies */
			if(rw_ticks > rw_level_threat_ticks[rw_level] && rand() % rw_level_prob_total[rw_level] < rw_level_prob[rw_level])
			{
				rw_generate_threat();
				if(rw_threat_count > 15 && rw_level < 19)
				{
					rw_threat_count = 0;
					al_play_sample(rw_sample[RW_SAMPLE_LEVEL_UP], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_level++;
					if(rw_level == 9)
					{
						rw_ship[0].way = rand() % 8;
						rw_ship[0].angle = rw_eight_ways[rw_ship[0].way];
						rw_ship[0].vangle = 0.0;
						rw_ship[0].dist = 320.0;
						rw_ship[0].dest = 200.0;
						rw_ship[0].vdist = -2.5;
						rw_ship[0].ticks = 0;
						rw_ship[0].active = true;
					}
					if(rw_level == 14)
					{
						rw_ship[1].way = rand() % 8;
						rw_ship[1].angle = rw_eight_ways[rw_ship[1].way];
						rw_ship[1].vangle = 0.0;
						rw_ship[1].dist = 320.0;
						rw_ship[1].dest = 160.0;
						rw_ship[1].vdist = -2.5;
						rw_ship[1].ticks = 0;
						rw_ship[1].active = true;
					}
				}
				rw_ticks = 0;
			}
			break;
		}
	}
}

void rw_render(void)
{
	int i;
	ALLEGRO_STATE old_blender;
	
	switch(rw_state)
	{
		case RW_STATE_INTRO:
		{
			al_clear(al_map_rgb(0, 0, 0));
			switch(rw_intro_state)
			{
				case 0:
				case 1:
				{
					ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_T3_LOGO], al_get_display_width() / 2 - al_get_bitmap_width(rw_bitmap[RW_BITMAP_T3_LOGO]) / 2, al_get_display_height() / 2 - al_get_bitmap_height(rw_bitmap[RW_BITMAP_T3_LOGO]) / 2, rw_intro_z);
					break;
				}
				case 2:
				{
					al_store_state(&old_blender, ALLEGRO_STATE_BLENDER);
					al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, (float)rw_intro_ticker / 30.0));
					ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_T3_LOGO], al_get_display_width() / 2 - al_get_bitmap_width(rw_bitmap[RW_BITMAP_T3_LOGO]) / 2, al_get_display_height() / 2 - al_get_bitmap_height(rw_bitmap[RW_BITMAP_T3_LOGO]) / 2, rw_intro_z);
					al_restore_state(&old_blender);
					break;
				}
				case 3:
				{
					al_store_state(&old_blender, ALLEGRO_STATE_BLENDER);
					al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, -(rw_intro_planet_z - 40.0) / (400.0 + 40.0)));
					ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_WORLD], al_get_display_width() / 2, al_get_display_height() / 2, rw_intro_planet_z, rw_intro_planet_angle);
					al_restore_state(&old_blender);
					break;
				}
			}
			break;
		}
		case RW_STATE_TITLE:
		{
			al_clear(al_map_rgb(0, 0, 0));
			al_store_state(&old_blender, ALLEGRO_STATE_BLENDER);
			al_font_textprintf(rw_font, 320 - al_font_text_width(rw_font, "HIGH SCORE - 0:00:00", -1) / 2, 0, "HIGH SCORE - %d:%02d:%02d", rw_high_score / 3600, (rw_high_score / 60) % 60, (int)(((float)(rw_high_score % 60) / 60.0) * 100.0) % 100);
			ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_WORLD], al_get_display_width() / 2, al_get_display_height() / 2, rw_intro_planet_z, rw_intro_planet_angle);
			al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, -rw_logo_z / 10.0));
			ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_LOGO], 320.0 - (float)al_get_bitmap_width(rw_bitmap[RW_BITMAP_LOGO]) / 2, 64.0, rw_logo_z + 10.0);
			al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, 1.0 + rw_logo_z / 10.0));
			ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_LOGO], 320.0 - (float)al_get_bitmap_width(rw_bitmap[RW_BITMAP_LOGO]) / 2, 64.0, rw_logo_z);
			al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, rw_start_alpha));
			ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_START], al_get_display_width() / 2 - al_get_bitmap_width(rw_bitmap[RW_BITMAP_START]) / 2.0, 400.0, 0.0);
			al_restore_state(&old_blender);
			break;
		}
		case RW_STATE_GAME_IN:
		case RW_STATE_GAME_OUT:
		{
			al_clear(al_map_rgb(0, 0, 0));
			al_font_textprintf(rw_font, 320 - al_font_text_width(rw_font, "HIGH SCORE - 0:00:00", -1) / 2, 0, "HIGH SCORE - %d:%02d:%02d", rw_high_score / 3600, (rw_high_score / 60) % 60, (int)(((float)(rw_high_score % 60) / 60.0) * 100.0) % 100);
			ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_WORLD], al_get_display_width() / 2, al_get_display_height() / 2, rw_intro_planet_z, rw_intro_planet_angle);
			break;
		}
		case RW_STATE_GAME:
		case RW_STATE_GAME_OVER:
		{
			al_clear(al_map_rgb(0, 0, 0));
			al_store_state(&old_blender, ALLEGRO_STATE_BLENDER);
			if(rw_damage >= 4)
			{
				al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0 - (float)rw_damage_time / 20.0, 1.0 - (float)rw_damage_time / 20.0, 1.0 - (float)rw_alert_ticks / 80.0));
			}
			else
			{
				al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0 - (float)rw_damage_time / 20.0, 1.0 - (float)rw_damage_time / 20.0, 1.0));
			}
			ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_WORLD], al_get_display_width() / 2 - al_get_bitmap_width(rw_bitmap[RW_BITMAP_WORLD]) / 2, al_get_display_height() / 2 - al_get_bitmap_height(rw_bitmap[RW_BITMAP_WORLD]) / 2, rw_camera_z);
			for(i = 0; i < 8; i++)
			{
				if(rw_shield_generator.shield[i].life > 0)
				{
					al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, rw_shield_generator.shield[i].active ? 1.0 : 0.0, rw_shield_generator.shield[i].active ? 1.0 : 0.0, (float)rw_shield_generator.shield[i].life / (float)(RW_SHIELD_MAX_LIFE)));
					ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_SHIELD_0 + i], al_get_display_width() / 2 - al_get_bitmap_width(rw_bitmap[RW_BITMAP_SHIELD_0 + i]) / 2, al_get_display_height() / 2 - al_get_bitmap_height(rw_bitmap[RW_BITMAP_SHIELD_0 + i]) / 2, rw_camera_z);
				}
			}
			for(i = 0; i < RW_MAX_PARTICLES; i++)
			{
				if(rw_particle[i].active)
				{
		//			ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_PARTICLE], rw_particle[i].x, rw_particle[i].y, rw_particle[i].angle, rw_camera_z);
					al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, (float)rw_particle[i].life / (float)rw_particle[i].tlife));
					ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_PARTICLE], rw_particle[i].x, rw_particle[i].y, rw_camera_z);
				}
			}
			al_restore_state(&old_blender);
			for(i = 0; i < RW_MAX_THREATS; i++)
			{
				if(rw_threat[i].active)
				{
					ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_THREAT], rw_threat[i].x, rw_threat[i].y, rw_camera_z, rw_threat[i].angle);
				}
			}
			for(i = 0; i < RW_MAX_SHOTS; i++)
			{
				if(rw_shot[i].active)
				{
					ocd3d_draw_bitmap(rw_bitmap[RW_BITMAP_SHOT], rw_shot[i].x - (float)al_get_bitmap_width(rw_bitmap[RW_BITMAP_SHOT]) / 2, rw_shot[i].y - (float)al_get_bitmap_height(rw_bitmap[RW_BITMAP_SHOT]) / 2, rw_camera_z);
				}
			}
			for(i = 0; i < RW_MAX_SHIPS; i++)
			{
				if(rw_ship[i].active)
				{
					ocd3d_rotate_bitmap(rw_bitmap[RW_BITMAP_SHIP], rw_ship[i].x, rw_ship[i].y, rw_camera_z, -rw_ship[i].angle);
				}
			}
			al_font_textprintf(rw_font, 320 - al_font_text_width(rw_font, "HIGH SCORE - 0:00:00", -1) / 2, 0, "HIGH SCORE - %d:%02d:%02d", rw_high_score / 3600, (rw_high_score / 60) % 60, (int)(((float)(rw_high_score % 60) / 60.0) * 100.0) % 100);
			al_font_textprintf(rw_font, 320 - al_font_text_width(rw_font, "SCORE - 0:00:00", -1) / 2, 16, "SCORE - %d:%02d:%02d", rw_score / 3600, (rw_score / 60) % 60, (int)(((float)(rw_score % 60) / 60.0) * 100.0) % 100);
			al_font_textprintf_centre(rw_font, 320, 32, "LEVEL - %d", rw_level + 1);
		//	al_font_textprintf_centre(rw_font, 320, 32, "%d : %f : %f : %f", rw_ship[0].way, rw_eight_ways[rw_ship[0].way], rw_ship[0].angle, rw_ship[0].vangle);
			break;
		}
	}
	al_flip_display();
}

void rw_initialize_game(void)
{
	int i;
	
	for(i = 0; i < RW_MAX_SHIELDS; i++)
	{
		rw_shield_generator.shield[i].life = 0;
		rw_shield_generator.shield[i].charge = 0;
	}
	rw_shield_generator.power = 0;
	
	for(i = 0; i < RW_MAX_THREATS; i++)
	{
		rw_threat[i].active = false;
	}
	
	for(i = 0; i < RW_MAX_SHIPS; i++)
	{
		rw_ship[i].active = false;
	}
	
	for(i = 0; i < RW_MAX_SHOTS; i++)
	{
		rw_shot[i].active = false;
	}
	
	for(i = 0; i < RW_MAX_PARTICLES; i++)
	{
		rw_particle[i].active = false;
	}
	
	rw_score = 0;
	rw_new_high_score = false;
	rw_threat_count = 0;
	rw_level = 0;
	rw_damage = 0;
	rw_damage_time = 0;
	rw_alert_ticks = 0;
	rw_camera_z = 0.0;
	rw_camera_target_z = 0.0;
	rw_alert_audio_ticks = 0;
}

void rw_control_game(ALLEGRO_EVENT * event)
{
	switch(rw_state)
	{
		case RW_STATE_TITLE:
		{
			switch(event->keyboard.keycode)
			{
				case ALLEGRO_KEY_1:
				case ALLEGRO_KEY_PAD_1:
				{
					al_play_sample(rw_sample[RW_SAMPLE_GAME_START], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_stop_music();
					rw_intro_planet_vangle = rw_intro_planet_angle / (rw_intro_planet_z / 10.0);
					rw_initialize_game();
					rw_state = RW_STATE_GAME_IN;
					rw_play_music("data/gamemusic.ogg");
					break;
				}
			}
			break;
		}
		case RW_STATE_GAME:
		{
			switch(event->keyboard.keycode)
			{
				case ALLEGRO_KEY_ESCAPE:
				{
					rw_destroy_everything();
					rw_state = RW_STATE_GAME_OVER;
					rw_intro_planet_z = rw_camera_z;
					break;
				}
				case ALLEGRO_KEY_PAD_7:
				case ALLEGRO_KEY_Q:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.25, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[0].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[0].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_8:
				case ALLEGRO_KEY_W:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[1].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[1].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_9:
				case ALLEGRO_KEY_E:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.75, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[2].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[2].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_6:
				case ALLEGRO_KEY_D:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.85, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[3].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[3].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_3:
				case ALLEGRO_KEY_C:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.75, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[4].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[4].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_2:
				case ALLEGRO_KEY_X:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[5].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[5].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_1:
				case ALLEGRO_KEY_Z:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.25, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[6].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[6].active = true;
					break;
				}
				case ALLEGRO_KEY_PAD_4:
				case ALLEGRO_KEY_A:
				{
					al_play_sample(rw_sample[RW_SAMPLE_SHIELD], 0.5, 0.15, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
					rw_shield_generator.shield[7].life = RW_SHIELD_MAX_LIFE;
					rw_shield_generator.shield[7].active = true;
					break;
				}
			}
			break;
		}
	}
	if(event->keyboard.keycode == ALLEGRO_KEY_M)
	{
		rw_toggle_music();
	}
}

int rw_initialize(int argc, char * argv[])
{
	int i;
	
	al_init();
	if(!al_iio_init())
	{
		return 0;
	}
	al_font_init();
	if(!al_install_keyboard())
	{
		return 0;
	}
	if(al_install_audio(ALLEGRO_AUDIO_DRIVER_AUTODETECT))
	{
		printf("Could not init sound!\n");
		return 0;
	}
	if(!al_reserve_samples(16))
	{
		printf("Could not set up voice and mixer.\n");
		return 0;
	}

	rw_display = al_create_display(640, 480);
	if(!rw_display)
	{
		return 0;
	}
	al_set_window_title("Eight Ways to Die");
	
	ocd3d_set_projection(1.0, 1.0, 320, 240, 640, 640);
	
	rw_timer = al_install_timer(1.000 / 60);
	if(!rw_timer)
	{
		return 0;
	}
	rw_queue = al_create_event_queue();
	if(!rw_queue)
	{
		return 0;
	}
	al_register_event_source(rw_queue, (ALLEGRO_EVENT_SOURCE *)al_get_keyboard());
	al_register_event_source(rw_queue, (ALLEGRO_EVENT_SOURCE *)rw_display);
	al_register_event_source(rw_queue, (ALLEGRO_EVENT_SOURCE *)rw_timer);
	
	rw_bitmap[RW_BITMAP_WORLD] = al_iio_load("data/world.png");
	rw_bitmap[RW_BITMAP_SHIELD_0] = al_iio_load("data/shield0.png");
	rw_bitmap[RW_BITMAP_SHIELD_1] = al_iio_load("data/shield1.png");
	rw_bitmap[RW_BITMAP_SHIELD_2] = al_iio_load("data/shield2.png");
	rw_bitmap[RW_BITMAP_SHIELD_3] = al_iio_load("data/shield3.png");
	rw_bitmap[RW_BITMAP_SHIELD_4] = al_iio_load("data/shield4.png");
	rw_bitmap[RW_BITMAP_SHIELD_5] = al_iio_load("data/shield5.png");
	rw_bitmap[RW_BITMAP_SHIELD_6] = al_iio_load("data/shield6.png");
	rw_bitmap[RW_BITMAP_SHIELD_7] = al_iio_load("data/shield7.png");
	rw_bitmap[RW_BITMAP_THREAT] = al_iio_load("data/threat.png");
	rw_bitmap[RW_BITMAP_SHIP] = al_iio_load("data/ship.png");
	rw_bitmap[RW_BITMAP_SHOT] = al_iio_load("data/shot.png");
	rw_bitmap[RW_BITMAP_PARTICLE] = al_iio_load("data/particle.png");
	rw_bitmap[RW_BITMAP_LOGO] = al_iio_load("data/logo.png");
	rw_bitmap[RW_BITMAP_T3_LOGO] = al_iio_load("data/t3.png");
	rw_bitmap[RW_BITMAP_START] = al_iio_load("data/start.png");
	rw_bitmap[RW_BITMAP_ICON] = al_iio_load("data/icon.png");
	for(i = RW_BITMAP_WORLD; i <= RW_BITMAP_ICON; i++)
	{
		if(!rw_bitmap[i])
		{
			printf("Error loading image %d!\n", i);
			return 0;
		}
	}
	
	al_set_display_icon(rw_bitmap[RW_BITMAP_ICON]);
	
	rw_font = ocd_load_font("data/gamefont.pcx");
	if(!rw_font)
	{
		printf("Error loading font!\n");
		return 0;
	}
	
	rw_sample[RW_SAMPLE_DAMAGE] = al_load_sample("data/damage.ogg");
	rw_sample[RW_SAMPLE_HIT] = al_load_sample("data/hit.ogg");
	rw_sample[RW_SAMPLE_SHIELD] = al_load_sample("data/shield.ogg");
	rw_sample[RW_SAMPLE_ALERT] = al_load_sample("data/alert.ogg");
	rw_sample[RW_SAMPLE_LEVEL_UP] = al_load_sample("data/levelup.ogg");
	rw_sample[RW_SAMPLE_HIGH_SCORE] = al_load_sample("data/highscore.ogg");
	rw_sample[RW_SAMPLE_LOGO] = al_load_sample("data/logo.ogg");
	rw_sample[RW_SAMPLE_GAME_START] = al_load_sample("data/gamestart.ogg");
	rw_sample[RW_SAMPLE_LOGO_OUT] = al_load_sample("data/logoout.ogg");
	for(i = RW_SAMPLE_DAMAGE; i <= RW_SAMPLE_LOGO_OUT; i++)
	{
		if(!rw_sample[i])
		{
			printf("Error loading sound %d!\n", i);
			return 0;
		}
	}

//	al_set_display_icon(lingo_image[LINGO_IMAGE_ICON]);
	
	#ifdef ALLEGRO_WINDOWS
		LPDIRECT3DDEVICE9 dev = al_d3d_get_device(rw_display);
		IDirect3DDevice9_SetSamplerState(dev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	#endif
	
	rw_load_high_score("rw.cfg");
	
	srand(time(0));
	return 1;
}

int rw_exit(void)
{
	int i;
	
	rw_save_high_score("rw.cfg");
	rw_stop_music();
	for(i = 0; i < RW_MAX_BITMAPS; i++)
	{
		if(rw_bitmap[i])
		{
			al_destroy_bitmap(rw_bitmap[i]);
		}
	}
	for(i = 0; i < RW_MAX_SAMPLES; i++)
	{
		if(rw_sample[i])
		{
			al_destroy_sample(rw_sample[i]);
		}
	}
	al_font_destroy_font(rw_font);
	return 1;
}

void rw_event_handler(ALLEGRO_EVENT * event)
{
	switch(event->type)
	{
		/* Was the X button on the window pressed? */
		case ALLEGRO_EVENT_DISPLAY_CLOSE:
		{
			rw_quit = 1;
		}

		/* Was a key pressed? */
		case ALLEGRO_EVENT_KEY_DOWN:
		{
			rw_control_game(event);
			if(event->keyboard.keycode == ALLEGRO_KEY_1)
			{
			}
            break;
		}
		case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
		{
			break;
		}
		case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
		{
			break;
		}
		case ALLEGRO_EVENT_MOUSE_AXES:
		{
			break;
		}
			/* Is it time for the next timer tick? */
		case ALLEGRO_EVENT_TIMER:
		{
			
			/* logic goes here */
			rw_logic();
			rw_render();
			break;
		}
	}
}

int main(int argc, char * argv[])
{
	ALLEGRO_EVENT event;
	
	if(!rw_initialize(argc, argv))
	{
		return -1;
	}
	rw_play_music("data/intromusic.ogg");
	al_start_timer(rw_timer);
	al_play_sample(rw_sample[RW_SAMPLE_LOGO], 0.5, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
	while(!rw_quit)
	{
		al_wait_for_event(rw_queue, &event);
		rw_event_handler(&event);
	}
	rw_exit();
	return 0;
}
END_OF_MAIN()
