/******************************************************************************
*******************************************************************************

	Bullet Rel Designer
	relminator (Richard Eric M. Lope BSN RN)
	http://rel.betterwebber.com


	main() entry point
	
	Notes: Code in main() is spaghetti city!!!!
	
 
*******************************************************************************
******************************************************************************/


#include <nds.h>
#include <maxmod9.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <fat.h>

#include "Cvector2df32.h"
#include "Csound.h"

#include "Cglsprite.h"
#include "Cgl2d.h"
#include "Cglfont.h"
#include "Coamfont.h"

#include "cearn_atan.h"
#include "Caabb.h"
#include "Cobject.h"
#include "Cbullet.h"
#include "Cturret.h"

#include "barrage.h"



// GRIT headers
#include "main_sprites.h"
#include "font_oam.h"
#include "font_si.h"

// Texture packer headers
#include "uvcoord_main_sprites.h"
#include "uvcoord_font_si.h"

//MAXMOD headers
#include "soundbank_bin.h"
#include "soundbank.h"


#define  FP_PI 16384 

#define MAX_TURRETS 16

struct Tstring
{
	char text[256];
};

struct Tentry
{
	char 	entry[256];
	s32		min;
	s32		max;
	s32		value;
	s32		default_value;
	s32		inc_val;
	char 	help[256];

};

#define MAX_ENTRY 32

class Cmenu
{
	public:
	Cmenu();
	void init(Tentry *_entries, Tstring *_entries_active);
	void print(Coamfont &font);
	void load_params(Cturret &t);
	void load_to_turret(Cturret &t);
	Tentry *entries;
	Tstring *entries_active;
	int active_entry;
	int	start;
	int max;
};

Cmenu::Cmenu()
{
	

	active_entry = 0;
	max = 15;
	start = active_entry;
	


}

void Cmenu::init(Tentry *_entries, Tstring *_entries_active)
{
	entries = _entries;
	entries_active = _entries_active;
}

void Cmenu::print(Coamfont &font)
{
	
	int active_row = active_entry;
	int active_index = active_entry;
	
	start = active_entry;
	if ( start >= (MAX_ENTRY - max) )
		start = MAX_ENTRY - max;
	
	for (int i = 0; i < max; i++)
	{
		int index = start + i;
		if (index >= MAX_ENTRY)
			break;
		if (index == active_entry)
		{
			iprintf("\n");
			active_row = i;
		}
		else
		{
			iprintf(entries[index].entry, entries[index].value);
		}
	}	
	
	//print active
	font.print(0, (active_row) * 8 + (6*8), entries_active[active_index].text, entries[active_index].value);
	
}

void Cmenu::load_params(Cturret &t)
{

	entries[0].value =t.parameters[0].active_time; 
	entries[1].value =t.parameters[0].active;						// non-fp
	entries[2].value =t.parameters[0].smart;							// if targeting or not
	entries[3].value =t.parameters[0].x_radius;						// non-fp
	entries[4].value =t.parameters[0].y_radius;						// non-fp
	entries[5].value =t.parameters[0].angle;
	entries[6].value =t.parameters[0].min_angle;
	entries[7].value =t.parameters[0].max_angle;
	entries[8].value =t.parameters[0].angle_speed;					// + rotation speed
	entries[9].value =t.parameters[0].angle_dir;						// -1 or +1  determines rotation direction
	entries[10].value =t.parameters[0].spread_angle;					// distance of each bullet on a spread
	entries[11].value =t.parameters[0].bullets_per_shot;
	entries[12].value =t.parameters[0].rotation_type;					// non-fp, whether back anf forth or not
	entries[13].value =t.parameters[0].spawn_delay;					// non-fp
	entries[14].value =t.parameters[0].max_spawn_delay;				// non-fp
	

	entries[15].value = t.parameters[0].wavemode;
	
	entries[16].value =t.parameters[0].wave_counter;					// non-fp
	entries[17].value =t.parameters[0].max_wave;						// non-fp maximum bullets per wave
	entries[18].value =t.parameters[0].max_wave_delay;				// non-fp maximum delay for next shot in a wave
	
	// bullets
	entries[19].value =t.parameters[0].bp.speed	;
	entries[20].value =t.parameters[0].bp.speed_delta;				// floattof32(-0.950) if the bullet speed per wave is variable
	entries[21].value =t.parameters[0].bp.offset;						//floattof32(1) // 1 << 12 for normal; Angle offset of each alternate bullet wave
	entries[22].value =t.parameters[0].bp.gx;
	entries[23].value =t.parameters[0].bp.gy;
	entries[24].value =t.parameters[0].bp.delay;						// for changing behavior. ie: normal to target (note that EB_NORMAL can be targeting at start via turret)
	entries[25].value =t.parameters[0].bp.energy;						// non-fp
	entries[26].value =t.parameters[0].bp.state;						// normal, accelerator or inv accelerator
	entries[27].value =t.parameters[0].bp.smart;						// targeting or not (after counter == delay); 			
	
	entries[28].value =t.parameters[0].bp.start_frame;				// non-fp
	entries[29].value =t.parameters[0].bp.num_frames;					// non-fp
	entries[30].value =t.parameters[0].bp.anim_delay;
	entries[31].value =t.parameters[0].bp.death_ID;					// non-fp
	
	
}


void Cmenu::load_to_turret(Cturret &t)
{
	Tturret_params tp;
	
	tp.active_time = entries[0].value; 
	tp.active = entries[1].value;						// non-fp
	tp.smart = entries[2].value;							// if targeting or not
	tp.x_radius = entries[3].value;						// non-fp
	tp.y_radius = entries[4].value;						// non-fp
	tp.angle = entries[5].value;
	tp.min_angle = entries[6].value;
	tp.max_angle = entries[7].value;
	tp.angle_speed = entries[8].value;					// + rotation speed
	tp.angle_dir = entries[9].value;						// -1 or +1  determines rotation direction
	tp.spread_angle = entries[10].value;					// distance of each bullet on a spread
	tp.bullets_per_shot = entries[11].value;
	tp.rotation_type = entries[12].value;					// non-fp, whether back anf forth or not
	tp.spawn_delay = entries[13].value;					// non-fp
	tp.max_spawn_delay = entries[14].value;				// non-fp
	

	tp.wavemode = (E_WAVE_MODE)entries[15].value;
	
	tp.wave_counter = entries[16].value;					// non-fp
	tp.max_wave = entries[17].value;						// non-fp maximum bullets per wave
	tp.max_wave_delay = entries[18].value;				// non-fp maximum delay for next shot in a wave
	
	// bullets
	tp.bp.speed = entries[19].value;
	tp.bp.speed_delta = entries[20].value;				// floattof32(-0.950) if the bullet speed per wave is variable
	tp.bp.offset = entries[21].value;						//floattof32(1) // 1 << 12 for normal; Angle offset of each alternate bullet wave
	tp.bp.gx = entries[22].value;
	tp.bp.gy = entries[23].value;
	tp.bp.delay = entries[24].value;						// for changing behavior. ie: normal to target (note that EB_NORMAL can be targeting at start via turret)
	tp.bp.energy = entries[25].value;						// non-fp
	tp.bp.state = (E_BULLET_TYPE)entries[26].value;						// normal, accelerator or inv accelerator
	tp.bp.smart = entries[27].value;						// targeting or not (after counter == delay); 			
	
	tp.bp.start_frame = entries[28].value;				// non-fp
	tp.bp.num_frames = entries[29].value;					// non-fp
	tp.bp.anim_delay = entries[30].value;
	tp.bp.death_ID = entries[31].value;					// non-fp
	
	t.parameters.clear();
	t.parameters.push_back(tp);
	t.reset(tp);
	
}
/******************************************************************************
*******************************************************************************
	MAIN entry point


*******************************************************************************
******************************************************************************/


void init_gl_screen();

int update_turrets(Cturret *turrets, Csound *sound)
{
	int active_turrets = 0;
	for (int i = 0; i < MAX_TURRETS; i++)
	{
		if (turrets[i].active)
		{
			turrets[i].update();
			active_turrets++;
		}
		
	}
	return active_turrets;
}

void draw_help(Cglfont &font_si)
{
	font_si.print_centered(0, 0, "HELP");
	
	font_si.print(0, 16, "CONTROLS");
	
	font_si.print(0,  32, "UP/DOWN = SCROLL");
	font_si.print(0,  40, "R + RIGHT/LEFT = FAST EDIT");
	font_si.print(0,  48, "L + RIGHT/LEFT = SLOW EDIT");
	font_si.print(0,  56, "RIGHT/LEFT = NORMAL EDIT");
	font_si.print(0,  72, "START = RESET ALL");
	font_si.print(0,  80, "A  = CHANGE BEHAVIOR");
	font_si.print(0,  88, "X  = LOAD DEFAULT VALUE");
	font_si.print(0,  96, "B  = SWITCH SCREEN");
	font_si.print(0, 104, "Y  = CHANGE ACTIVE TURRET");
	font_si.print(0, 120, "TOUCH = CHANGE TURRET POSITION");
	font_si.print(0, 128, "SELECT = HIDE/SHOW HELP");
	font_si.print(0, 144, "R + Y = ADD TURRET");
	font_si.print(0, 152, "L + Y = DELETE TURRET");
	font_si.print(0, 160, "R + L = SAVE BARRAGE");
	
}


void fprint_barrage(char name[], FILE *fp, Cturret &turret, Cmenu &menu)
{

	menu.load_params(turret);
	
	
    const char *entries[] = 
    {
        "tp.active_time         =",         //1
    	"tp.active              =",         //2
    	"tp.smart               =",         //3
    	"tp.x_radius            =",         //4 
    	"tp.y_radius            =",         //5 
    	"tp.angle               =",         //6 
    	"tp.min_angle           =",         //7 
    	"tp.max_angle           =",         //8 
    	"tp.angle_speed         =",         //9 
    	"tp.angle_dir           =",         //10 
    	"tp.spread_angle        =",         //1
    	"tp.bullets_per_shot    =",         //2 
    	"tp.rotation_type       =",         //3 
    	"tp.spawn_delay         =",         //4 
    	"tp.max_spawn_delay     =",         // 5
    	"tp.wavemode            = (E_WAVE_MODE)",         //6
    	"tp.wave_counter        =",         //7 
    	"tp.max_wave            =",         //8 
    	"tp.max_wave_delay      =",         //9 
    	"tp.bp.speed            =",         //20 
    	"tp.bp.speed_delta      =",         //1 
    	"tp.bp.offset           =",         //2 
    	"tp.bp.gx               =",         //3 
    	"tp.bp.gy               =",         //4 
    	"tp.bp.delay            =",         //5 
    	"tp.bp.energy           =",         //6 
    	"tp.bp.state            = (E_BULLET_TYPE)",         //7
    	"tp.bp.smart            =",         //8  			
    	"tp.bp.start_frame      =",         //9 
    	"tp.bp.num_frames       =",         //30 
    	"tp.bp.anim_delay       =",         //31 
    	"tp.bp.death_ID         ="          //32 
    	
    };
    
	fprintf(fp, "\n");
	fprintf(fp, "\n");
	fprintf(fp, "void barrage_%s(Cturret &turret, int active_time, int delay, s32 angle, const Cglsprite *sprites);\n", name);
    fprintf(fp, "\n");
    fprintf(fp, "void barrage_%s(Cturret &turret, int active_time, int delay, s32 angle, const Cglsprite *sprites)\n", name);
    fprintf(fp, "{\n");
    fprintf(fp, "\n");
    fprintf(fp, "\tTturret_params tp;  \n");
    fprintf(fp, "\n");
    
    for (int i = 0; i < 32; i++)
    {
        fprintf(fp, "\t%s %d; \n", entries[i], menu.entries[i].value); 
    }
    
    fprintf(fp, "\n");
    fprintf(fp, "\ttp.bp.width           = sprites[tp.bp.start_frame].width; \n");
	fprintf(fp, "\ttp.bp.height          = sprites[tp.bp.start_frame].height; \n");
    fprintf(fp, "\n");
    fprintf(fp, "\tturret.parameters.push_back(tp); \n");
    fprintf(fp, "\n");
    fprintf(fp, "}\n");
    
}


int text_entry(int x, int y, const char *filler, int length,char *entry, Cgl2d &gl2d, Cglfont &font_si)
{	
	int maxlen = length;
	int k , kh;
	int char_val = 65;
	int pos = 0;
	char asc[2];
	const char *eraser = " ";
	
	for (int i = 0; i < maxlen; i++)
	{
		entry[i] = *filler;
	}
	entry[maxlen] = NULL;
	
	
	do
	{
		scanKeys();
		k = keysDown();
		kh = keysHeld();
		
		if (kh & KEY_R)
		{
			if (kh & KEY_DOWN)
			{
				char_val -= 1;
				if (char_val < 48)
					char_val = 95;
			}
			else if (kh & KEY_UP)
			{
				char_val += 1;
				if (char_val > 95)
					char_val = 48;
				
			}
		}
		
		
		if (k & KEY_DOWN)
		{
			char_val -= 1;
			if (char_val < 48)
				char_val = 95;
		}
		else if (k & KEY_UP)
		{
			char_val += 1;
			if (char_val > 95)
				char_val = 48;
			
		}
		else if (k & KEY_RIGHT)
		{
			if ( pos < maxlen-1)
			{
				
				entry[pos] = char_val; 
				pos++; 
			}
		}
		else if (k & KEY_LEFT)
		{
			if (pos > 0)
			{
				entry[pos] = *filler;
				pos--;
			}
		}
		
		entry[pos] = *eraser;
		
		gl2d.start();
		
		
			font_si.print_centered(x, 10, "------SAVE------");
			font_si.print_centered(x, 40, "PRESS START TO EXIT");
			
			font_si.print(x, y, entry);
			
			asc[0] = char_val;
			asc[1] = NULL;
			font_si.print(x+(pos*8), y,  asc);
			font_si.print(x+(pos*8), y-10,  "a");
			font_si.print(x+(pos*8), y+10,  "a");
			
			
			// test
			//font_si.print(x, y+30, entry);
			
	
		gl2d.end();
		
		glFlush(0);

		swiWaitForVBlank();

	}
	while (!(k & KEY_START));
	
	
	entry[pos] = char_val;
	entry[pos+1] = NULL;
	
	
	return 1;
	
}

int find_active_turret(Cturret *turrets, int start)
{

	for (int i = 1; i < MAX_TURRETS; i++)
	{
		int j = mod32(start + i,MAX_TURRETS);
		if (turrets[j].active)
			return j;
	}
	
	return 0;

}

// sprites
Cglsprite main_sprites[MAIN_SPRITES_NUM_IMAGES];		//  number of frames
Cglsprite font_si_sprites[FONT_SI_NUM_IMAGES];		//  number of frames


Csound audio;

Cgl2d gl2d;

Cbullet_array bullets;
Cturret turrets[MAX_TURRETS];

Cglfont font_si;
Coamfont oamfont;

int Csprite::num_sprites = 0;
int current_song;

Cvector2df32 target;
Cmenu menu;

const int spr_max = MAIN_SPRITES_NUM_IMAGES;
//				entry							 min 		max   		value		default		inc			help

Tentry m[] = {	{"active time = %i        \n",0			, 10000		, 0			,10000		,10			, " Frames to be active"},     // 0
				{"active = %i             \n",0			, 1			, 0			,1			,1			, " Frames to be active"},       // 1
				{"smart = %i              \n",0			, 1			, 0			,0			,1			, " Frames to be active"},       // 2
				{"x-radius = %i           \n",-256		, 256		, 0			,10			,1			, " Frames to be active"},       // 3
				{"y-radius = %i           \n",-256		, 256		, 0			,9			,1			, " Frames to be active"},       // 4
				{"angle = %i              \n",-32767	, 32768		, 0			,0			,64			, " Frames to be active"},       // 5
				{"min angle = %i          \n",-32767	, 32768		, 0			,0			,64			, " Frames to be active"},       // 6
				{"max angle = %i          \n",-32767	, 32768		, 0			,32768		,64			, " Frames to be active"},       // 7
				{"angle speed = %i        \n",0			, 32768		, 0			,256		,64			, " Frames to be active"},       // 8
				{"angle dir = %i          \n",-1		, 1			, 0			,1			,1			, " Frames to be active"},       // 9
				{"spread angle = %i       \n",-32767	, 32768		, 0			,32768/4	,64			, " Frames to be active"},       // 10
				{"bullets per shot = %i   \n",0			, 256		, 0			,4			,1			, " Frames to be active"},       // 11
				{"rotation type = %i      \n",0			, 3			, 0			,0			,1			, " Frames to be active"},       // 12
				{"spawn delay = %i        \n",0			, 1024		, 0			,0			,1			, " Frames to be active"},       // 13
				{"max spawn delay = %i    \n",0			, 1024		, 0			,6			,1			, " Frames to be active"},       // 14
				{"wave mode = %i          \n",0			, 4			, 0			,1			,1			, " Frames to be active"},       // 15
				{"wave counter = %i       \n",0			, 1024		, 0			,0			,1			, " Frames to be active"},       // 16
				{"max wave = %i           \n",0			, 256		, 0			,0			,1			, " Frames to be active"},       // 17
				{"max wave delay = %i     \n",0			, 1024		, 0			,16			,1			, " Frames to be active"},       // 18
				{"bullet speed = %i       \n",-64 << 12	, 64 << 12	, 0			,floattof32(0.75),floattof32(0.01)			, " Frames to be active"},       // 19
				{"bullet speed delta= %i  \n",-16 << 12	, 16 << 12	, 0			,floattof32(0.00),floattof32(0.01)			, " Frames to be active"},       // 20
				{"bullet offset = %i      \n",-16 << 12	, 16 << 12	, 0			,1<<12			,floattof32(0.01)			, " Frames to be active"},       // 21
				{"bullet gravity x= %i    \n",-16 << 12	, 16 << 12	, 0			,0			,1			, " Frames to be active"},       // 22
				{"bullet gravity y= %i    \n",-16 << 12	, 16 << 12	, 0			,0			,1			, " Frames to be active"},       // 23
				{"bullet delay = %i       \n",-1024		, 1024		, 0			,-1			,1			, " Frames to be active"},       // 24
				{"bullet energy= %i       \n",0			, 1024		, 0			,1			,1			, " Frames to be active"},       // 25
				{"bullet state= %i        \n",1			, 3			, 0			,0			,1			, " Frames to be active"},       // 26
				{"bullet smart= %i        \n",0			, 1			, 0			,0			,1			, " Frames to be active"},       // 27
				{"bullet start frame= %i  \n",0			, spr_max	, 0			,54			,1			, " Frames to be active"},       // 28
				{"bullet num frames= %i   \n",1			, spr_max	, 1			,4			,1			, " Frames to be active"},       // 29
				{"bullet animation delay= %i   \n"		,1			, 256		, 1			,3			,1			, " Frames to be active"},       // 30
				{"bullet death ID = %i    \n",0			, 1024		, 0			,0			,1			, " Frames to be active"}        // 31
		   };	

Tstring  m_a[] = {	{"ACTIVE TIME = "},       	// 0
				{"ACTIVE = "},       			// 1
				{"SMART = "},       			// 2
				{"X-RADIUS = "},       			// 3
				{"Y-RADIUS = "},       			// 4
				{"ANGLE = "},       			// 5
				{"MIN ANGLE = "},       		// 6
				{"MAX ANGLE = "},       		// 7
				{"ANGLE SPEED = "},       		// 8
				{"ANGLE DIR = "},       		// 9
				{"SPREAD ANGLE = "},       		// 10
				{"BULLETS PER SHOT = "},     	// 11
				{"ROTATION TYPE = "},       	// 12
				{"SPAWN DELAY = "},       		// 13
				{"MAX SPAWN DELAY = "},       	// 14
				{"WAVE MODE = "},       		// 15
				{"WAVE COUNTER = "},       		// 16
				{"MAX WAVE = "},       			// 17
				{"MAX WAVE DELAY = "},       	// 18
				{"BULLET SPEED = "},       		// 19
				{"BULLET SPEED DELTA= "},     	// 20
				{"BULLET OFFSET = "},       	// 21
				{"BULLET GRAVITY X= "},       	// 22
				{"BULLET GRAVITY Y= "},       	// 23
				{"BULLET DELAY = "},       		// 24
				{"BULLET ENERGY= "},       		// 25
				{"BULLET STATE= "},       		// 26
				{"BULLET SMART= "},       		// 27
				{"BULLET START FRAME= "},     	// 28
				{"BULLET NUM FRAMES= "},      	// 29
				{"BULLET ANIMATION DELAY= "}, 	// 30
				{"BULLET DEATH ID = "}       	// 31
		   };	



mm_word myEventHandler( mm_word msg, mm_word param )
{
   
 switch( msg )
    {
    case MMCB_SONGMESSAGE:
        // Process song message
        break;
    case MMCB_SONGFINISHED:
        // A song has finished playing
		audio.stop_BGM();						// must stop old BGM before unload
		//audio.unload_BGM( current_song );		// unload old BGM
		audio.set_BGM_mode( E_BGM_NORMAL );		// Normal mode
		current_song = mod32(current_song+1, E_BGM_MAX );
		audio.play_BGM( current_song , MM_PLAY_ONCE );	// play new BGM
		break;
    }
	return 0;
	
}

int main(int argc, char *argv[])
{

	fatInitDefault();
	
	FILE *fp;
	char filename[256];
	char entry[256];
	char funk_name[256];			
	char name[] = {"booya"};
	
	sprintf(filename,"%s.cpp", name);
	
	font_si.init(font_si_sprites);
	
	menu.init(m, m_a);
	
	
	//---------------------------------------------------------
	// init maxmod with default settings
	//---------------------------------------------------------
	audio.init( (mm_addr)soundbank_bin );
	
	// switch audio mode
	audio.set_mode( MM_MODE_C );
	
	mmSetEventHandler( myEventHandler );
	
	//---------------------------------------------------------
	// load songs (must be loaded before using with mmStart)
	//---------------------------------------------------------
	audio.load_BGM( MOD_LEVEL01 );
	audio.load_BGM( MOD_LEVEL02 );
	audio.load_BGM( MOD_LEVEL03 );
	audio.load_BGM( MOD_LEVEL04 );
	audio.load_BGM( MOD_LEVEL05 );
	audio.load_BGM( MOD_S1945 );
	audio.load_BGM( MOD_CONTRA );
	audio.load_BGM( MOD_BOSS01 );
	
	audio.load_SFX( SFX_TURRET_SHOOT );
	
	
	
	
	videoSetMode(MODE_5_3D);
	
	
	consoleDemoInit();
	
	

	
	
	//gl2d_init();
	init_gl_screen();
	
	
	vramSetBankA(VRAM_A_TEXTURE);		// 128 kb -> main_sprites(64kb) and enemies(64kb) 
	vramSetBankB(VRAM_B_TEXTURE);		// 64x64 floor/ceiling/glfonts
	vramSetBankD(VRAM_D_SUB_SPRITE);	// oam fonts et al
	
	
	//api: initialize OAM to 1D mapping with XX byte offsets and no external palette
	// SpriteMapping_1D_128 = 8x8 tiling
	oamInit(&oamSub, SpriteMapping_1D_128, false);
	dmaCopy(font_oamPal, SPRITE_PALETTE_SUB, 512);
	oamfont.init(&oamSub, (u8*)font_oamTiles, 8, 8, SpriteSize_8x8, 96);
	
	
	// main sprites
	int main_sprites_textureID;  
	gl2d.load_texture(main_sprites_textureID,GL_RGB256, TEXTURE_SIZE_256 , TEXTURE_SIZE_256, (u8*)main_spritesBitmap);

	int font_si_sprites_textureID;  
	gl2d.load_texture(font_si_sprites_textureID,GL_RGB256, TEXTURE_SIZE_64 , TEXTURE_SIZE_128, (u8*)font_siBitmap);

	
	// load global pal
	// texture pal in VRAM_E?
	gluTexLoadPal(main_spritesPal, 512,GL_RGB256);

		
	// init sprites
	gl2d.init_sprites(main_sprites, MAIN_SPRITES_NUM_IMAGES, main_sprites_texcoords, main_sprites_textureID);
	
	gl2d.init_sprites(font_si_sprites, FONT_SI_NUM_IMAGES, font_si_texcoords, font_si_sprites_textureID);
	
	
	current_song = 0; //qran_range( 0, E_BGM_MAX-1 );
	audio.set_master_volume( 512 );
	audio.play_BGM( current_song, MM_PLAY_ONCE );

	
	int total_frame = 0;
	
	bool finished = false;
	bool show_help = true;
	bool is_saved = false;
	
	touchPosition touch;
	int keys_down, keys_held;
	int active_turrets = 0;
	
	target.x = 0;
	target.y = 100;
	
	int current_turret = 0;
	
	for (int i = 0; i < MAX_TURRETS; i++)
	{
		if (!turrets[i].active)
		{
			turrets[i].active = true;
			turrets[i].set_position(200,100);
			turrets[i].set_target(&target);
			
			barrage_test(turrets[i], 10600, 0, 0, main_sprites);
			
			turrets[i].init(turrets[i].parameters[0], bullets.p_bullets);
			current_turret = i;
			break;
		}
	}
	
	menu.load_params(turrets[current_turret]);
	
	while(!finished)
	{
	
	
		total_frame++;
		
		target.x = ( (20 << 12) + ((cosLerp(total_frame*64) + sinLerp(total_frame*256)) * 10)) >> 12;
		target.y = ( (96 << 12) + ((sinLerp(-total_frame*128) + sinLerp(total_frame*512)) * 40)) >> 12;
		
		scanKeys();
		keys_down = keysDown();
		keys_held = keysHeld();
		
		if (keys_held & KEY_TOUCH)
		{
			touchRead(&touch);
			
			turrets[current_turret].x = touch.px;
			turrets[current_turret].y = touch.py;
			turrets[current_turret].set_position(touch.px,touch.py);
		}
		
		// add
		if (keys_held & KEY_R)
		{
			if (keys_down & KEY_Y)
			{		
				for (int i = 0; i < MAX_TURRETS; i++)
				{
					if (!turrets[i].active)
					{
						turrets[i].active = true;
						turrets[i].set_position(200,100);
						turrets[i].set_target(&target);
						
						barrage_test(turrets[i], 10600, 0, 0, main_sprites);
						
						turrets[i].init(turrets[i].parameters[0], bullets.p_bullets);
						current_turret = i;
						break;
					}
				}
			}
		}
		else
		{
			// delete
			if (keys_held & KEY_L)
			{
				if (keys_down & KEY_Y)
				{
					turrets[current_turret].active = false;
					//if (current_turret > 0) 
					//	current_turret--;
					current_turret = find_active_turret(turrets,current_turret);
				}
			}
			else
			{
				if (keys_down & KEY_Y)
				{
					current_turret = find_active_turret(turrets,current_turret);
					menu.load_params(turrets[current_turret]);
				}
			}
		}
		
		
		
		
		if (keys_down & KEY_B)
		{
			lcdSwap();
		}
		if (keys_down & KEY_SELECT)
		{
			show_help = !show_help;
		}
		// load default value of entry
		if (keys_down & KEY_X)
		{
			menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].default_value;
		}
		
		
		if (keys_held & KEY_R)
		{
			if (keys_held & KEY_RIGHT)
			{	
				menu.entries[menu.active_entry].value += menu.entries[menu.active_entry].inc_val;
				if (menu.entries[menu.active_entry].value > menu.entries[menu.active_entry].max)
					menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].max;
			}
			
			if (keys_held & KEY_LEFT)
			{	
				menu.entries[menu.active_entry].value -= menu.entries[menu.active_entry].inc_val;
				if (menu.entries[menu.active_entry].value < menu.entries[menu.active_entry].min)
					menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].min;
			}
		}
		else
		{
		
			if (keys_held & KEY_L)
			{
				if (keys_down & KEY_RIGHT)
				{	
					menu.entries[menu.active_entry].value++;
					if (menu.entries[menu.active_entry].value > menu.entries[menu.active_entry].max)
						menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].max;
				}
				
				if (keys_down & KEY_LEFT)
				{	
					menu.entries[menu.active_entry].value--;
					if (menu.entries[menu.active_entry].value < menu.entries[menu.active_entry].min)
						menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].min;
				}
			}
			else
			{
				if (keys_down & KEY_RIGHT)
				{	
					menu.entries[menu.active_entry].value += menu.entries[menu.active_entry].inc_val;
					if (menu.entries[menu.active_entry].value > menu.entries[menu.active_entry].max)
						menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].max;
				}
				
				if (keys_down & KEY_LEFT)
				{	
					menu.entries[menu.active_entry].value -= menu.entries[menu.active_entry].inc_val;
					if (menu.entries[menu.active_entry].value < menu.entries[menu.active_entry].min)
						menu.entries[menu.active_entry].value = menu.entries[menu.active_entry].min;
				}
			}

		}
		

		
		
		if (keys_down & KEY_A)
		{	
			menu.load_to_turret(turrets[current_turret]);
		}
		
		// reset
		if (keys_down & KEY_START)
		{
			
			//turrets[current_turret].active_time = 1;
			//turrets[current_turret].parameters.clear();
			
			//barrage_4way_normal(turrets[current_turret], 10600, 0, 0, main_sprites);
			
			//turrets[current_turret].init(turrets[current_turret].parameters[0], bullets.p_bullets);
			//menu.load_params(turrets[current_turret]);	
			
			for (int i = 0; i < MAX_TURRETS; i++)
			{
				if (turrets[i].active)
				{
					turrets[i].reset(turrets[i].parameters[0]);
				}
			}
			
			menu.load_params(turrets[current_turret]);
			
		}
		
		// 
		if (keys_down & KEY_UP)
		{
			if (menu.active_entry > 0)
				menu.active_entry--;
		}
		
		if (keys_down & KEY_DOWN)
		{
			if (menu.active_entry < (MAX_ENTRY-1))
				menu.active_entry++;
		}

		if (keys_held & KEY_R)
		{
			if (keys_down & KEY_L)
			{
				is_saved = true;
				text_entry(40, 100, "-", 20, entry, gl2d, font_si);
				sprintf(filename,"%s.cpp", entry);
				
				fp = fopen(filename, "w");
				int j = 0;
				for (int i = 0; i < MAX_TURRETS; i++)
				{
					if (turrets[i].active)
					{
						j++;
						sprintf(funk_name,"%s_%i", entry, j);
						fprint_barrage(funk_name, fp, turrets[i], menu);
					}
				}
				fclose(fp);
				menu.load_params(turrets[current_turret]);
			}
		}
		
		
		active_turrets = update_turrets(turrets, &audio);
		bullets.update();
		
		
		
		// start 2d mode
		gl2d.start();
			
			
			
			// needs to be called before texturing
			// or sprite gets blended by last glcolor call
			glColor(ARGB16(1,31,31,31)); 
			
			
			main_sprites[16].rotate(target.x, target.y, total_frame * 256);
			
			
			gl2d.increase_depth();
			
			
			main_sprites[138].render((turrets[current_turret].x >> 12)-16, (turrets[current_turret].y >> 12)-16);
			
			
			gl2d.increase_depth();
			
			bullets.render_bullets(main_sprites);
			
			
			
			// fonts
			gl2d.increase_depth();
			
			if (show_help)
				draw_help(font_si);
			
			
			
		gl2d.end();
		
		
		
		
		
		
		
		
		
		
		
		glFlush(0);

		swiWaitForVBlank();
		
		oamfont.clear(); // deactivate every oam per frame
		
		oamfont.print_centered(0, 0, "< Bullet Rel DS >");
		oamfont.print_centered(0, 8, "Relminator");
		oamfont.print_centered(0, 16, "http://rel.betterwebber.com");
		
		
		
		consoleClear();
		
		iprintf("\x1b[3;0HActive Turrets    = %i     ", active_turrets);
		iprintf("\x1b[4;0HBullets on Screen = %i     \n\n", bullets.active_bullets);
		
		menu.print(oamfont);
		
		oamfont.print(0, 8 * 22, "Current Turret =", current_turret);
		
		oamUpdate(&oamSub);
		
		if (is_saved)
			iprintf("\x1b[23;0HSaved: %s", filename);
		
		
	}	// finished loop

	

	return 0;
	
}



void init_gl_screen()
{

	// initialize gl
	glInit();
	
	//enable textures
	glEnable(GL_TEXTURE_2D);
	
	// enable antialiasing
	glEnable(GL_ANTIALIAS);
		
	// setup the rear plane
	glClearColor(0,0,0,31); // BG must be opaque for AA to work
	glClearPolyID(63); // BG must have a unique polygon ID for AA to work
	
	glClearDepth(GL_MAX_DEPTH);

	//this should work the same as the normal gl call
	glViewport(0,0,255,191);
	
	
	//any floating point gl call is being converted to fixed prior to being implemented
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(70, 256.0 / 192.0, 1, 200);
	
	gluLookAt(	0.0, 0.0, 1.0,		//camera possition 
				0.0, 0.0, 0.0,		//look at
				0.0, 1.0, 0.0);		//up

	glMaterialf(GL_AMBIENT, RGB15(31,31,31));
	glMaterialf(GL_DIFFUSE, RGB15(31,31,31));
	glMaterialf(GL_SPECULAR, BIT(15) | RGB15(31,31,31));
	glMaterialf(GL_EMISSION, RGB15(31,31,31));

	//ds uses a table for shinyness..this generates a half-ass one
	glMaterialShinyness();

	//not a real gl function and will likely change
	glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK);
}

