#include "engine.h"
#include "py_classes.h"

extern int SCREEN_WIDTH;
extern int SCREEN_HEIGHT;

extern PyMethodDef fftMethods[];
extern PyMethodDef catchMethods[];

extern PyTypeObject pyship_type;

PyObject *module;
PyObject *mainModule;
PyObject *catchmodule;
//PyObject *objectiveModule;

Engine::Engine()
{
	Log::WriteVerbose("Initializing Engine");
	showfps=false;
	running=false;
	incontrol=false;
	mainship=0;
	mainscen=0;
	maininput=0;
	mainmap=0;
	mainmodule="";
	fonts.clear();
	guis.clear();
	sounds.clear();
	surfaces.clear();
	starfields.clear();
	Py_Initialize();
	Log::WriteVerbose("Loading FFTrader Python Library");
	PyImport_AddModule("fft");
	module = Py_InitModule3("fft", fftMethods, "fft standard module.\n");

	PyImport_AddModule("catch");
	catchmodule = Py_InitModule3("catch", catchMethods, "catch sysout and syserr.\n");

	PyRun_SimpleString("import sys; sys.path.insert(0, './scenario')");

	PyObject *sysModule = PyImport_ImportModule("sys");
	PyObject_SetAttrString(sysModule, "stdout", catchmodule);
	PyObject_SetAttrString(sysModule, "stderr", catchmodule);

	Init_ShipType();
	Py_INCREF(&pyship_type);
	PyModule_AddObject(module, "Ship", (PyObject*)&pyship_type);
}
Engine::~Engine()
{
	this->Quit();
}
void Engine::Quit()
{
	int i;
	for(i=0; i<(int)sounds.size(); i++)
	{
		Mix_FreeChunk(sounds[i].sound);
	}
	for(i=0; i<(int)fonts.size(); i++)
	{
		TTF_CloseFont(fonts[i].font);
	}
	for(i=0; i<(int)surfaces.size(); i++)
	{
		SDL_FreeSurface(surfaces[i].surface);
	}
	delete mainmap;
	delete mainship;
	delete mainscen;
	delete maininput;
	fonts.clear();
	guis.clear();
	sounds.clear();
	surfaces.clear();
	starfields.clear();

	Mix_CloseAudio();
	this->CleanUpGame();
	//Py_XDECREF(module);
	//Py_XDECREF(catchmodule);
	//Py_XDECREF(objectiveModule);
	Py_Finalize();
	PHYSFS_deinit();
	TTF_Quit();
	SDL_Quit();
	Log::Write("Thank you for playing!");
}
bool Engine::StartGame()
{
	PyObject* sysModule = PyImport_ImportModule("sys");
	PyObject_SetAttrString(sysModule, "stdout", catchmodule);
	PyObject_SetAttrString(sysModule, "stderr", catchmodule);
	if (!strcmp(mainmodule.c_str(),""))
	{
		Log::Write("The main module hasn't been set yet");
		return false;
	}
	PyObject *pModuleName = PyString_FromString(mainmodule.c_str());
	if (PyErr_Occurred())
	{
		Log::Write("Could not create Python string from %s",mainmodule.c_str());
		PyErr_Print();
		return false;
	}
	else
	{
		Log::Write("**********************\nLoading module: %s\n",mainmodule.c_str());
		running=true;
	}
	mainModule = PyImport_Import(pModuleName);
	if (mainModule == NULL) running=false;
	return running;
}
int Engine::InGameMenu()
{
	Log::WriteVerbose("InGameMenu()");
	SDL_Event event;
	SDL_Surface *screen=SDL_GetVideoSurface();
	int w=screen->w;
	int h=screen->h;
	SDL_Surface *bg = SDL_CreateRGBSurface(0, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
	SDL_Rect dest;
	dest.x = 0;
	dest.y = 0;
	SDL_BlitSurface(screen, NULL, bg, &dest);
	GUI *optionsGUI=new GUI;
	optionsGUI->Init();
	optionsGUI->MakeWindow(60, 120, w-120, 220);
	optionsGUI->MakeStatic(60,126,w-120,20,"Menu");
	int sControls=optionsGUI->MakeButton(100,160,w-200, "Controls");
	int sCancel=optionsGUI->MakeButton(100,280,200, "Back to Game");
	int sExit=optionsGUI->MakeButton(w-300,280,200, "Exit Game");

	int done=0;
	int getx, gety;
	int click=-1;
	while(!done)
	{
		Slock();
		while (SDL_PollEvent(&event))
		{
			// an event was found
			switch (event.type) {
			// close button clicked
			case SDL_QUIT:
				done=-1;
				break;

			// handle the keyboard
			case SDL_KEYDOWN:
				switch (event.key.keysym.sym) {
				case SDLK_ESCAPE:
					done=AskToQuitGame(w,h);
					if (done==-1) done=1;
					break;
				default:
					break;
				}
				break;
			case SDL_MOUSEMOTION:
				SDL_GetMouseState(&getx, &gety);
				optionsGUI->SendMouseMotion(getx,gety);
				break;
			case SDL_MOUSEBUTTONDOWN:
				SDL_GetMouseState(&getx, &gety);
				click = optionsGUI->SendMouseClick(getx, gety);
				break;
			case SDL_MOUSEBUTTONUP:
				SDL_GetMouseState(&getx, &gety);
				if (click!=-1 && click==optionsGUI->SendMouseClick(getx, gety))
				{
					SDL_FillRect(screen,0,0);
					DrawIMG(bg,0,0);
					optionsGUI->Draw();
					Sulock();
					SDL_Flip(screen);
					if (click==sControls)
					{
						done=ControlChanging(w,h,bg,false);
						if (done==1) done=0;
					}
					if (click==sCancel)
					{
						done=2;
					}
					if (click==sExit)
					{
						done=AskToQuitGame(w, h);
						if (done==-1) done=1;
					}
				}
				optionsGUI->UpdateButtons();
				break;
			default:
				break;
			}
		}
		SDL_FillRect(screen,0,0);
		DrawIMG(bg,0,0);
		optionsGUI->Draw();
		Sulock();
		SDL_Flip(screen);
	}
	delete optionsGUI;
	SDL_FreeSurface(bg);
	if (done!=1 && done!=-1) done=0;
	return done;
}
int Engine::MainLoop()
{
	Log::WriteVerbose("Main Loop begin");
	SDL_Event event;
	SDL_Surface *screen=SDL_GetVideoSurface();
	SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
	SDL_Color yellow = { 0xFF, 0xFF, 0x00, 0 };
	SDL_Color black = { 0x00, 0x00, 0x00, 0 };
	int done=0;
	char disp[100];
	//int getx, gety;
	//int click=-1;
	//int ingameok=gui2->GetButtonID(150,300,SCREEN_WIDTH-300,"Go!");
	int x, y, angle, speed, starx, stary, starx2, stary2, shipx, shipy, sx, sy, savespeed, range;
	int fps, fpscount;
	int targetx=0;
	int targety=0;
	bool engage, disengage;
	angle=mainship->GetAngle();
	x=mainship->GetX();
	y=mainship->GetY();
	double dx=mainship->GetDX();
	double dy=mainship->GetDY();
	int maxspeed=mainship->GetMaxSpeed();
	speed=mainship->GetSpeed();
	bool atwarp=mainship->AtWarp();
	starx=0;
	stary=0;
	starx2=0;
	stary2=0;
	fpscount=0;
	int aiunit=-1;
	int aiunits=mainmap->GetUnitCount();
	fps=0;
	range=3;
	savespeed=0;
	__ship_slot curslot=mainship->GetCurWeaponSlot();
	engage=false;
	disengage=false;
	bool paused=false;
	//setup for GUI stuff
	shipx=(SCREEN_WIDTH/2)-(mainship->GetImageWidth()/2);
	shipy=(SCREEN_HEIGHT/2)-(mainship->GetImageHeight()/2);
	starx=(int)(-dx/10);
	stary=(int)(-dy/10);
	starx2=(int)(-dx/20);
	stary2=(int)(-dy/20);
	sx=mainship->GetSectorX();
	sy=mainship->GetSectorY();
	mainmap->SetTarget(aiunit);
	mainmap->CheckSectors(sx, sy);
	float zoom=0.5;
	//Log::WriteVerbose("Variables set, displaying opening message");
	TTF_Font *font9=TTF_OpenFont("fonts/arial.ttf", 9);
	TTF_Font *font14=this->GetFont("font14");
	TTF_Font *font10=this->GetFont("font10");
	/*
	while(!done)
	{
		Slock();
		SDL_FillRect(screen,0,0);
		stars->Display(starx, stary);
		stars2->Display(starx2, stary2);
		mainmap->DisplayOnScreenObjects(x,y,SCREEN_WIDTH,SCREEN_HEIGHT);
		mainship->Display(shipx,shipy);
		mainmap->DisplayMinimap(4,10,x,y,range);
		sprintf(disp, "%d sectors", range);
		centerString(font, 34, 80, "Sensor radius:", white);
		centerString(font, 34, 90, disp, white);
		mainship->StatusDisplay(SCREEN_WIDTH-125, SCREEN_HEIGHT-195, 120, 190, font9);
		mainmap->DisplayAITarget(5, SCREEN_HEIGHT-125,120,120,font9,targetx,targety);
		while (SDL_PollEvent(&event))
		{
			switch (event.type) {
			// close button clicked
			case SDL_QUIT:
				return -1;
				break;

			// handle the keyboard
			case SDL_KEYDOWN:
				switch (event.key.keysym.sym) {
				case SDLK_RETURN:
					done = 1;
					break;
				case SDLK_ESCAPE:
					done = 1;
					break;
				default:
					break;
				}
				break;
			case SDL_MOUSEMOTION:
				SDL_GetMouseState(&getx, &gety);
				gui2->SendMouseMotion(getx,gety);
				break;
			case SDL_MOUSEBUTTONDOWN:
				SDL_GetMouseState(&getx, &gety);
				click = gui2->SendMouseClick(getx, gety);
				break;
			case SDL_MOUSEBUTTONUP:
				SDL_GetMouseState(&getx, &gety);
				if (click!=-1 && click==gui2->SendMouseClick(getx, gety))
				{
					if (click==ingameok)
					{
						gui2->Draw();
						gui2->UpdateButtons();
						Sulock();
						SDL_Flip(screen);
						done=1;
					}
				}
				gui2->UpdateButtons();
				break;
			default:
				break;
			}
		}
		gui2->Draw();
		Sulock();
		SDL_Flip(screen);
	}
	done=0;
	*/
	FPSmanager *FPS = new FPSmanager;
	SDL_initFramerate(FPS);
	SDL_setFramerate(FPS, 60);
	Uint32 time=SDL_GetTicks();
	Uint32 pausetime=0;
	Uint32 lastpausetime=SDL_GetTicks();
	Uint32 turntime=SDL_GetTicks();
	Uint32 checktime=SDL_GetTicks();
	char disppause[100];
	sprintf(disppause, "Press '%s' to unpause", maininput->GetPauseStr().c_str());
	Log::WriteVerbose("Entering gameplay loop");
	while(!done)
	{
		while (SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT) { done=-1; }
			else if(event.type == SDL_ACTIVEEVENT)
			{
				if(event.active.state==SDL_APPACTIVE || event.active.state==SDL_APPINPUTFOCUS)
				{
					if(event.active.gain==0)
					{
						paused=true;
						Log::WriteVerbose("Game was paused because the window lost focus");
						if (paused)
						{
							centerString(font14, SCREEN_WIDTH/2-1, SCREEN_HEIGHT/2-8-1, "Game Paused", black);
							centerString(font14, SCREEN_WIDTH/2, SCREEN_HEIGHT/2-8, "Game Paused", yellow);
							centerString(font14, SCREEN_WIDTH/2-1, SCREEN_HEIGHT/2+8-1, disppause, black);
							centerString(font14, SCREEN_WIDTH/2, SCREEN_HEIGHT/2+8, disppause, yellow);
							SDL_Flip(screen);
						}
					}
				}
			}
			else if(event.type == SDL_KEYDOWN)
			{
				if(event.key.keysym.sym == maininput->GetCancel())
				{
					done = this->InGameMenu();
				}
				else if((event.key.keysym.sym == maininput->GetWarp1() || event.key.keysym.sym == maininput->GetWarp2()) && !paused && incontrol)
				{
					if (mainship->AtWarp() && mainship->WarpEnabled()) { engage=false; disengage=true; }
					else if (!mainship->AtWarp() && mainship->WarpEnabled()) { disengage=false; engage=true; mainship->SetWarp(true); }
				}
				else if((event.key.keysym.sym == maininput->GetFire1() || event.key.keysym.sym == maininput->GetFire2()) && !paused && incontrol)
				{
					if (!mainship->AtWarp())
					{
						int tempspeed=speed+maxspeed;
						if (speed<0) tempspeed=maxspeed;
						//mainmap->SpawnBullet(mainship->GetShootX(), mainship->GetShootY(), tempspeed, angle, curslot.fn, curslot.fpk, aiunit, curslot.id);
						if (curslot.image)
						{
							mainmap->SpawnBullet(mainship->GetShootX(), mainship->GetShootY(), tempspeed, angle, curslot.fn, curslot.fpk, curslot.image, aiunit, curslot.id);
							Mix_PlayChannel(0,shot,0);
						}
					}
				}
				else if(event.key.keysym.sym == maininput->GetMiniMapZoomIn() && !paused && incontrol)
				{
					if (range*2 < 20) { range=range*2; }
				}
				else if(event.key.keysym.sym == maininput->GetMiniMapZoomOut() && !paused && incontrol)
				{
					if (range/2 > 1) { range=range/2; }
				}
				else if(event.key.keysym.sym == maininput->GetZoomIn() && !paused && incontrol)
				{
					if (zoom+0.25 <= 1)
					{
						zoom+=0.25;
						Log::WriteVerbose("Zooming ship");
						mainship->SetZoom(zoom);
						Log::WriteVerbose("Loading Ship images");
						mainship->ReloadImages();
						Log::WriteVerbose("Zooming map");
						mainmap->SetZoom(zoom);
					}
				}
				else if(event.key.keysym.sym == maininput->GetZoomOut() && !paused && incontrol)
				{
					if (zoom-0.25 >=0.5)
					{
						zoom-=0.25;
						Log::WriteVerbose("Zooming ship");
						mainship->SetZoom(zoom);
						Log::WriteVerbose("Loading Ship images");
						mainship->ReloadImages();
						Log::WriteVerbose("Zooming map");
						mainmap->SetZoom(zoom);
					}
				}
				else if(event.key.keysym.sym == maininput->GetPrevWeapon() && !paused && incontrol)
				{
					mainship->PrevWeapon();
					if (strcmp(mainship->GetCurWeaponSlot().holdweapon.c_str(),"heatseeking")) aiunit=-1;
					else aiunit=0;
					mainmap->SetTarget(aiunit);
				}
				else if(event.key.keysym.sym == maininput->GetNextWeapon() && !paused && incontrol)
				{
					mainship->NextWeapon();
					if (strcmp(mainship->GetCurWeaponSlot().holdweapon.c_str(),"heatseeking")) aiunit=-1;
					else aiunit=0;
					mainmap->SetTarget(aiunit);
				}
				else if(event.key.keysym.sym == maininput->GetDock() && !paused && incontrol)
				{
					mainmap->Dock(x,y);
					if(aiunit==-1 && !strcmp(mainship->GetCurWeaponSlot().holdweapon.c_str(),"heatseeking"))
					{
						aiunit=0;
						mainmap->SetTarget(aiunit);
					}
				}
				else if(event.key.keysym.sym == maininput->GetPrevTarget() && !paused && aiunit!=-1 && incontrol)
				{
					if (aiunit+1<aiunits) aiunit++;
					else aiunit=0;
					mainmap->SetTarget(aiunit);
				}
				else if(event.key.keysym.sym == maininput->GetNextTarget() && !paused && aiunit!=-1 && incontrol)
				{
					if (aiunit-1>=0) aiunit--;
					else aiunit=aiunits-1;
					mainmap->SetTarget(aiunit);
				}
				else if(event.key.keysym.sym == maininput->GetPause())
				{
					paused=!paused;
					if (paused)
					{
						centerString(font14, SCREEN_WIDTH/2-1, SCREEN_HEIGHT/2-8-1, "Game Paused", black);
						centerString(font14, SCREEN_WIDTH/2, SCREEN_HEIGHT/2-8, "Game Paused", yellow);
						centerString(font14, SCREEN_WIDTH/2-1, SCREEN_HEIGHT/2+8-1, disppause, black);
						centerString(font14, SCREEN_WIDTH/2, SCREEN_HEIGHT/2+8, disppause, yellow);
						SDL_Flip(screen);
					}
				}
			}
		}
		if (!paused)
		{
			if(pausetime)
			{
				mainmap->SendPauseTime(pausetime);
				pausetime=0;
			}
			fpscount+=1;
			bool overheated=mainship->IsOverHeated();
			int hullhits=mainship->GetHullHits();
			int maxhullhits=mainship->GetMaxHullHits();
			shipx=(SCREEN_WIDTH/2)-(mainship->GetImageWidth()/2);
			shipy=(SCREEN_HEIGHT/2)-(mainship->GetImageHeight()/2);
			mainship->Move(0,0);
			x=mainship->GetX();
			y=mainship->GetY();
			dx=mainship->GetDX();
			dy=mainship->GetDY();
			angle=mainship->GetAngle();
			speed=mainship->GetSpeed();
			sx=mainship->GetSectorX();
			sy=mainship->GetSectorY();
			curslot=mainship->GetCurWeaponSlot();
			aiunits=mainmap->GetUnitCount();
			if (curslot.image)
			{
				if (strcmp(curslot.holdweapon.c_str(),"heatseeking")) aiunit=-1;
			}
			if (aiunit<aiunits && aiunit!=-1)
			{
				targetx=mainmap->GetUnitX(aiunit);
				targety=mainmap->GetUnitY(aiunit);
			}
			else
			{
				targetx=0;
				targety=0;
				aiunit=-1;
				mainmap->SetTarget(aiunit);
			}
			Slock();
			SDL_FillRect(screen,0,0);
			if (engage && speed<50)
			{
				mainship->SetSpeed(speed+1);
			}
			if (engage && speed>=50)
			{
				engage=false;
			}
			if (disengage && speed>savespeed)
			{
				mainship->SetSpeed(speed-1);
			}
			if (disengage && speed<=savespeed)
			{
				disengage=false;
				mainship->SetWarp(false);
			}
			speed=mainship->GetSpeed();
			mainmap->MoveBullets();
			mainmap->MoveAI(x,y);
			mainmap->CheckSectors(sx, sy);
			atwarp=mainship->AtWarp();
			if (!atwarp)
			{
				int i;
				for(i=0; i<(int)starfields.size(); i++)
				{
					starx=(int)(-dx/starfields[i].factor);
					stary=(int)(-dy/starfields[i].factor);
					starfields[i].stars->Display(starx, stary);
				}
				mainmap->DisplayOnScreenObjects(x,y,SCREEN_WIDTH,SCREEN_HEIGHT);
				if (hullhits<maxhullhits && !overheated) mainship->Display(shipx,shipy);
				savespeed=speed;
				if (savespeed<0) { savespeed=0; }
			}
			else if (atwarp)
			{
				int i;
				for(i=0; i<(int)starfields.size(); i++)
				{
					if (!starfields[i].above)
					{
						starx=(int)(-dx/starfields[i].factor);
						stary=(int)(-dy/starfields[i].factor);
						starfields[i].stars->DisplayWarp(starx, stary, angle, (int)((float)speed/2.5));
					}
				}
				mainmap->DisplayOnScreenObjects(x,y,SCREEN_WIDTH,SCREEN_HEIGHT);
				if (hullhits<maxhullhits && !overheated) mainship->Display(shipx,shipy);
				for(i=0; i<(int)starfields.size(); i++)
				{
					if (starfields[i].above)
					{
						starx=(int)(-dx/starfields[i].factor);
						stary=(int)(-dy/starfields[i].factor);
						starfields[i].stars->DisplayWarp(starx, stary, angle, (int)((float)speed/2.5));
					}
				}
			}
			if (showfps)
			{
				sprintf(disp, "FPS: %d", fps);
				drawString(font14, SCREEN_WIDTH-80, 10, disp, white);
			}
			if (incontrol)
			{
				mainmap->DisplayMinimap(4,10,x,y,range);
				sprintf(disp, "%d sectors", range);
				centerString(font10, 34, 80, "Sensor radius:", white);
				centerString(font10, 34, 90, disp, white);
				mainship->StatusDisplay(SCREEN_WIDTH-125, SCREEN_HEIGHT-195, 120, 190, font9);
				mainmap->DisplayAITarget(5, SCREEN_HEIGHT-125,120,120,font9,targetx,targety);
			}
			if (SDL_GetTicks()>=time+1000)
			{
				fps=fpscount;
				fpscount=0;
				time=SDL_GetTicks();
			}
			Sulock();
			SDL_Flip(screen);
			Uint8* keys = SDL_GetKeyState(NULL);
			// If the keys UP, DOWN, LEFT and RIGHT have been pressed
			if(keys[maininput->GetUp()] && incontrol)
			{
				if (fpscount%2==0 && !atwarp && !engage && !disengage)
				{
					if (speed<mainship->GetMaxSpeed())
					{
						mainship->SetSpeed(speed+1);
					}
				}
				if (fpscount%2==0 && atwarp && !engage && !disengage)
				{
					if (speed<mainship->GetMaxWarp())
					{
						mainship->SetSpeed(speed+1);
					}
				}
			}
			if(keys[maininput->GetDown()] && incontrol)
			{
				if (fpscount%2==0 && !atwarp && !engage && !disengage)
				{
					if (speed>-mainship->GetMaxSpeed())
					{
						mainship->SetSpeed(speed-1);
					}
				}
				if (fpscount%2==0 && atwarp && !engage && !disengage)
				{
					if (speed>50)
					{
						mainship->SetSpeed(speed-1);
					}
				}
			}
			if(keys[maininput->GetAllStop()] && incontrol)
			{
				if (fpscount%2==0 && !atwarp)
				{
					if (speed>0)
					{
						mainship->SetSpeed(speed-1);
					}
					if (speed<0)
					{
						mainship->SetSpeed(speed+1);
					}
				}
			}
			if(keys[maininput->GetLeft()] && incontrol)
			{
				if (!atwarp && SDL_GetTicks()>=turntime+mainship->GetTurnDelay())
				{
					mainship->Rotate(0);
					turntime=SDL_GetTicks();
				}
				else
				{
					if (SDL_GetTicks()>=turntime+mainship->GetWarpTurnDelay())
					{
						mainship->Rotate(0);
						turntime=SDL_GetTicks();
					}
				}
			}
			if(keys[maininput->GetRight()] && incontrol)
			{
				if (!atwarp && SDL_GetTicks()>=turntime+mainship->GetTurnDelay())
				{
					mainship->Rotate(1);
					turntime=SDL_GetTicks();
				}
				else {
					if (SDL_GetTicks()>=turntime+mainship->GetWarpTurnDelay())
					{
						mainship->Rotate(1);
						turntime=SDL_GetTicks();
					}
				}
			}
			if (SDL_GetTicks()>=checktime+2000)
			{
				//Check for victory and loss only once per 2 seconds
				checktime=SDL_GetTicks();
				if (hullhits>=maxhullhits) done=GameOverBox(SCREEN_WIDTH,SCREEN_HEIGHT);
				if (overheated) done=GameOverBox(SCREEN_WIDTH,SCREEN_HEIGHT);
				if (mainscen->CheckVictory())
				{
					std::string message="Congratulations!  You finished Scenario ";
					message+=mainscen->GetName();
					done=ExitToMenuBox(SCREEN_WIDTH,SCREEN_HEIGHT,message);
				}
				if (mainscen->CheckLoss())
				{
					std::string message="Game Over.  You failed to complete your objectives.";
					done=ExitToMenuBox(SCREEN_WIDTH,SCREEN_HEIGHT,message);
				}
			}
			SDL_framerateDelay(FPS);
			lastpausetime=SDL_GetTicks();
		}
		if (paused)
		{
			pausetime=SDL_GetTicks()-lastpausetime;
		}
	}
	delete FPS;
	TTF_CloseFont(font9);
	return done;
}
void Engine::CleanUpGame()
{
	running=false;
	char c[2048];
	sprintf(c,"if '%s' in sys.modules:\n\tdel sys.modules['%s']",mainmodule.c_str(),mainmodule.c_str());
	PyRun_SimpleString(c);
}
void Engine::Render()
{
	SDL_Surface *screen=SDL_GetVideoSurface();
	SDL_FillRect(screen,0,0);
	int x=0;
	int y=0;
	double dx=0.0;
	double dy=0.0;
	if(mainship)
	{
		x=mainship->GetX();
		y=mainship->GetY();
		dx=mainship->GetDX();
		dy=mainship->GetDY();
	}
	if(mainmap)
	{
		int i;
		for (i=0; i<(int)starfields.size(); i++)
		{
			starfields[i].stars->Display((int)(-dx/starfields[i].factor),(int)(-dy/starfields[i].factor));
		}
		mainmap->DisplayOnScreenObjects(x,y,SCREEN_WIDTH,SCREEN_HEIGHT);
	}
	if(mainship)
	{
		int shipx=(SCREEN_WIDTH/2)-(ship->GetImageWidth()/2);
		int shipy=(SCREEN_HEIGHT/2)-(ship->GetImageHeight()/2);
		mainship->Display(shipx,shipy);
		//mainmap->DisplayMinimap(4,10,x,y,range);
	}
}
bool Engine::ShipSelect()
{
	Log::WriteVerbose("Entering ship selection");
	//SDL_Surface *screen=SDL_GetVideoSurface();
	//SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
	mainship->SetZoom((float)0.5);
	//mainship->SetCredits(mainscen->GetStartCredits());
	mainship->SetPriceBought(0);
	FPKShip **fpkships;
	fpkships=this->LoadAllFPKShips();
	int quit=NewShipOptions(SCREEN_WIDTH, SCREEN_HEIGHT, fpkships);
	mainship=ship;
	if (quit==-1) this->Quit();
	if (quit==1) return false;
	Uint32 ticks=SDL_GetTicks();
	//Log::WriteVerbose("Loading Game...");
	//SDL_FillRect(screen,0,0);
	//centerString(font2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, "Loading Game....", white);
	//SDL_Flip(screen);
	delete mainmap;
	mainmap = new Map();
	mainmap->Init((float)0.5);
	Log::WriteVerbose("Setting map to scenario");
	mainscen->SetMap(mainmap);
	//Log::WriteVerbose("Loading map file");
	//LoadMap(map, mainscen->GetMapFn(), zoom);
	//delete gui2;
	//Log::WriteVerbose("Creating opening message");
	//std::string message=mainscen->GetOpenMessage();
	//gui2=MakeCenterOKWindow(message);
	//Log::WriteVerbose("Placing ship");
	//mainship->SetAngle(mainscen->GetStartAngle());
	//Log::WriteVerbosen("Ship:   Angle: %d",mainscen->GetStartAngle());
	//mainship->SetSpeed(mainscen->GetStartSpeed());
	//Log::WriteVerbosen(" Speed: %d",mainscen->GetStartSpeed());
	//mainship->SetWarp(false);
	//mainship->SetX(mainscen->GetStartX());
	//Log::WriteVerbosen(" X: %d",mainscen->GetStartX());
	//mainship->SetY(mainscen->GetStartY());
	//Log::WriteVerbosen(" Y: %d",mainscen->GetStartY());
	//Log::WriteVerbose(" Remaining credits: %d",mainship->GetCredits());
	mainship->SetZoom((float)0.5);
	//Log::WriteVerbose("Loading images");
	//mainship->ReloadImages();
	Log::WriteVerbose("Adjusting shoot point");
	mainship->AdjustShootPoint();
	Log::WriteVerbose("Adding main ship to map");
	mainmap->AddMainShip(mainship);
	//Log::WriteVerbose("Starting up Scenario");
	//mainscen->Startup();
	Uint32 timepassed=SDL_GetTicks()-ticks;
	Uint32 ms=timepassed%1000;
	Uint32 secs=(unsigned int)((double)timepassed/1000.0);
	Uint32 mins=(unsigned int)((double)secs/60.0);
	Log::WriteVerbose("Scenario loaded in %d minutes, %d seconds, and %d milliseconds",mins,secs,ms);
	return true;
}
FPKShip **Engine::LoadAllFPKShips()
{
	Log::WriteVerbose("Inside LoadAllFPKShips");
	char **fpklist;
	char **k;
	int i, j, temp, fpks, max;
	int total[60];
	static FPKShip *fpkships[100];
	for(i=0; i<100; i++)
	{
		fpkships[i]=0;
	}
	fpklist=PHYSFS_enumerateFiles("fpk");
	fpks=FPK_count();
	i=0;
	max=0;
	for (k = fpklist; *k != NULL; k++)
	{
		if(IsFPK(*k))
		{
			total[i]=FPK_countPlayerShips(*k);
			max+=total[i];
			i++;
		}
	}
	PHYSFS_freeList(fpklist);
	temp=0;
	for(i=0; i<fpks; i++)
	{
		for(j=temp; j<total[i]+temp; j++)
		{
			FPKShip *tempship=new FPKShip(i, j-temp);
			fpkships[j]=tempship;
		}
		temp=j;
	}
	return fpkships;
}
void Engine::SetMainModule(std::string modulename)
{
	if (!running) mainmodule=modulename;
	else Log::WriteVerbose("\nWARNING:\nAttempted to set a new module while the game is already running\n");
}
Unit *Engine::GetMainShip()
{
	return mainship;
}
void Engine::SetMainShip(Unit *ship)
{
	mainship=ship;
	if (mainmap) mainmap->AddMainShip(ship);
}
void Engine::InControl(bool control)
{
	incontrol=control;
}
Scenario *Engine::GetMainScenario()
{
	return mainscen;
}
void Engine::SetMainScenario(Scenario *scen)
{
	mainscen=scen;
}
FFTInput *Engine::GetInput()
{
	return maininput;
}
void Engine::SetInput(FFTInput *input)
{
	maininput=input;
}
Map *Engine::GetMap()
{
	return mainmap;
}
void Engine::SetMap(Map* map)
{
	mainmap=map;
}
TTF_Font *Engine::GetFont(std::string name)
{
	int i;
	for(i=0; i<(int)fonts.size(); i++)
	{
		if (!strcmp(name.c_str(),fonts[i].name.c_str())) return fonts[i].font;
	}
	return 0;
}
void Engine::AddFont(std::string name, TTF_Font *font)
{
	if(!this->GetFont(name))
	{
		FFTFont fftfont;
		fftfont.font=font;
		fftfont.name=name;
		fonts.push_back(fftfont);
	}
	else
	{
		int i;
		for(i=0; i<(int)fonts.size(); i++)
		{
			if (!strcmp(name.c_str(),fonts[i].name.c_str()))
			{
				TTF_CloseFont(fonts[i].font);
				fonts[i].font=font;
			}
		}
	}
}
Mix_Chunk *Engine::GetSound(std::string name)
{
	int i;
	for(i=0; i<(int)sounds.size(); i++)
	{
		if (!strcmp(name.c_str(),sounds[i].name.c_str())) return sounds[i].sound;
	}
	return 0;
}
void Engine::AddSound(std::string name, Mix_Chunk *sound)
{
	if(this->GetSound(name))
	{
		FFTSound fftsound;
		fftsound.sound=sound;
		fftsound.name=name;
		sounds.push_back(fftsound);
	}
	else
	{
		int i;
		for(i=0; i<(int)sounds.size(); i++)
		{
			if (!strcmp(name.c_str(),sounds[i].name.c_str()))
			{
				Mix_FreeChunk(sounds[i].sound);
				sounds[i].sound=sound;
			}
		}
	}
}
GUI *Engine::GetGUI(std::string name)
{
	int i;
	for(i=0; i<(int)guis.size(); i++)
	{
		if (!strcmp(name.c_str(),guis[i].name.c_str())) return guis[i].gui;
	}
	return 0;
}
void Engine::AddGUI(std::string name, GUI *gui)
{
	if(this->GetSound(name))
	{
		FFTGUI fftgui;
		fftgui.gui=gui;
		fftgui.name=name;
		guis.push_back(fftgui);
	}
	else
	{
		int i;
		for(i=0; i<(int)guis.size(); i++)
		{
			if (!strcmp(name.c_str(),guis[i].name.c_str()))
			{
				delete guis[i].gui;
				guis[i].gui=gui;
			}
		}
	}
}
SDL_Surface *Engine::GetSurface(std::string name)
{
	int i;
	for(i=0; i<(int)surfaces.size(); i++)
	{
		if (!strcmp(name.c_str(),surfaces[i].name.c_str())) return surfaces[i].surface;
	}
	return 0;
}
void Engine::AddSurface(std::string name, SDL_Surface *surface)
{
	if(this->GetSound(name))
	{
		FFTSurface fftsurface;
		fftsurface.surface=surface;
		fftsurface.name=name;
		surfaces.push_back(fftsurface);
	}
	else
	{
		int i;
		for(i=0; i<(int)surfaces.size(); i++)
		{
			if (!strcmp(name.c_str(),surfaces[i].name.c_str()))
			{
				delete surfaces[i].surface;
				surfaces[i].surface=surface;
			}
		}
	}
}
void Engine::AddStarfield(StarField *stars, bool above, int factor)
{
	FFTStars fftstars;
	fftstars.stars=stars;
	fftstars.above=above;
	fftstars.factor=factor;
	starfields.push_back(fftstars);
}
void Engine::ShowFPS()
{
	showfps=true;
}

