/*
 *  SDL-Fighter is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  SDL-Fighter is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "main.h"

#ifdef DREAMCAST
#include <kos.h>
#include <SDL/SDL_dreamcast.h>

extern uint8 romdisk[];
KOS_INIT_FLAGS(INIT_DEFAULT);
KOS_INIT_ROMDISK(romdisk);
#endif

#ifndef win32
char *red[2] = {"\x1b[5;31m","\x1b[0;37m"};
char *green[2] = {"\x1b[1;32m","\x1b[0;37m"};
#else
char *red[2] = {"",""};
char *green[2] = {"",""};
#endif
float gamma_val = 1.0f;
// Enemy weapon
char eweapons[NUM_LEVELS][2] = {
	{CANNON,CANNON},
	{CANNON,MISSILE_LAUNCHER},
	{MISSILE_LAUNCHER,MISSILE_LAUNCHER},
	{MISSILE_LAUNCHER,PLASMAGUN},
	{PLASMAGUN,PLASMAGUN},
};

// Enemy shooting speed
int espeed[NUM_LEVELS] = {
	390,
	490,
	420,
	460,
	480
};

int fawless_victory = true;
int fawless_victory_msg_time = 0;
// Screen size
int SCREEN_X,SCREEN_Y;
// Event structure
SDL_Event event;
int tol_add_ship=0, tol_add_pack=0, tol_add_littles=0, num_littles=0;
int t1,
	t2,
	dt,
	dt2,
	ships = DEFAULT_SHIPS, // Number of lives
	score = 0, // Score
	BGPos = 256,
	current_level = 1,
	num_scrolls = 0,
	is_boss = false,
	game_finished = false,
	credits = false,
	credits_pos,
	help = false,
	godmode = false,
	godtime,
	quit = false,           // End?
	current_music = 0,  // Current music
	paused_music = 0,   // Paused music?
	paused_game = false,    // Paused game?
	repeat_music = false,   // Repeat music
	music_volume = 80,  // Music volume
	chunk_volume = 70; // Chunk volume

// Player ammunition
int player_ammo[3] = {DEFAULT_BULLETS, DEFAULT_MISSILES, DEFAULT_PLASMAS};
int last_enemy_kill[2] = {-1, -1};
int last_kill_time_id=-1;
// Current circle radius for 4 little ships which are rotating around the boss
int littles_radius=0;
lvl_des packs_info;
int cur_pack_info=0;
// Fps
float fps,shooting_spd=1.0f;
// enemies
struct object enemies[MAX_ENEMIES];
int num_enemies=0;
// enemy bullets
struct object ebullets[MAX_BULLETS];
int num_ebullets=0;
// packs
struct object packs[MAX_PACKS];
int num_packs=0;
// ship bullets
struct object ship_bullets[MAX_BULLETS];
int num_ship_bullets=0;
// boss
struct object boss;
// player ship
struct object ship;
// Explosions
struct explosion explosions[MAX_EXPLOSIONS];
int num_explos=0;

message messages[MAX_MESSAGES];
char home_dir[256];
int num_messages=0;

SDL_Surface *screen; // Screen
SDL_Surface *icon, // Icon
	*bgfull,
	*bgimage,
	*energy,  
	*shield,
	*benergy;
SDL_Surface *frame[NUM_BOOM_FRAMES]; // Explosion frames
SDL_Surface *obj[NUM_IMAGES]; // Images
SDL_Rect BGRect,BGSrc; 
// status of energy and shield
SDL_Rect epos, // energy pos
	esrc, // energy src
	spos, // shield pos
	ssrc, // shield src
	bpos, // boss energy pos
	bsrc; // boss energy src
// Font
BFont_Info *font;
Mix_Music *music[NUM_TRACKS]; // tracks
Mix_Chunk *chunk[NUM_CHUNKS]; // chunks

Uint8 *keys;

char *tracks[] = { "Phenomena Enigma by Mantronix", sounds_dir"mod.phenomena-enigma.mod",
	"Lotus 3 - Shamrip", sounds_dir"mod.shamrip.mod",
	"Dragonsfunk by Moby", sounds_dir"mod.dragonsfunk.mod",
	"Knulla-kuk by Moby", sounds_dir"mod.knulla-kuk.mod",
	"10 Minutes Trash", sounds_dir"mod.10minutetrash.mod",
	"Lotus 3 - Miami Ice", sounds_dir"mod.miamiice.mod",
	"Atmosphere", sounds_dir"mod.atmosphere.mod" };

char *images[NUM_IMAGES] = {
	pixmaps_dir"bullet.png",
	pixmaps_dir"missile.png",
	pixmaps_dir"enemy.png",
	pixmaps_dir"enemy2.png",
	pixmaps_dir"pack_ship.png",
	pixmaps_dir"pack_shield.png",
	pixmaps_dir"pack_energy.png",
	pixmaps_dir"pack_surprise.png",
	pixmaps_dir"boss.png",
	pixmaps_dir"boss2.png",
	pixmaps_dir"ship.png",
	pixmaps_dir"live.png",
	pixmaps_dir"enemy_missile.png",
	pixmaps_dir"plasma.png",
	pixmaps_dir"blive.png",
	pixmaps_dir"boss_child.png",
	pixmaps_dir"pack_shooting.png"};

/* NAME:	CheckDir
 * DESCRIPTION:	Checks for home dir ($HOME/.SDL-Fighter) - if home dir doesn't exists, create
 */
void CheckDir(void)
{
#ifndef win32
	struct stat st;
	char f[128];
	sprintf(home_dir, "%s", getenv("HOME"));
	sprintf(f, "%s/.SDL-Fighter", home_dir);
	if(stat (f, &st) < 0)
		mkdir(f, 16893);
#else
	sprintf(home_dir, ".");
#endif
}

void ClearScreen(void)
{
	SDL_FillRect(screen,0,0);
}

/* NAME:	Init
 * DESCRIPTION:	Inits screen and sound, loads all necessary files
 */
void Init(void)
{
	int i,j;
	srand(time(NULL));

	// Init SDL
	if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) < 0)
		ErrorExit("Unable to initialize SDL: %s",SDL_GetError());
		
	#ifdef DREAMCAST
	SDL_DC_MapKey(0,SDL_DC_START,SDLK_RETURN);
	SDL_DC_MapKey(0,SDL_DC_L,SDLK_p); //right button on the controller
	SDL_DC_MapKey(0,SDL_DC_R,SDLK_q); //left button on the controller
	SDL_DC_MapKey(0,SDL_DC_B,SDLK_b); //SDL_DC_Y is X button in real dreamcast, SDL_DC_X is Y button in real dreamcast
	SDL_DC_MapKey(0,SDL_DC_Y,SDLK_SPACE); 
	SDL_DC_MapKey(0,SDL_DC_A,SDLK_LCTRL); 
	SDL_DC_MapKey(0,SDL_DC_X,SDLK_z); 
	SDL_JoystickEventState(SDL_ENABLE);
	SDL_JoystickOpen(0);
	SDL_ShowCursor(0);
	#endif
	
	// Open screen
	if((screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, 0, (SDL_HWSURFACE|SDL_DOUBLEBUF))) == NULL)
		ErrorExit("Unable to set %dx%d video: %s",SCREEN_X, SCREEN_Y, SDL_GetError());
	// Open audio
	if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
		ErrorExit("Unable to set 22050 Hz 16-bit audio\n- Reason: %s\n", SDL_GetError());
	// Load tracks
	for(i=0;i<NUM_TRACKS;i++)
	{	
		music[i] = Mix_LoadMUS(tracks[i*2+1]);
		// check track
		if(music[i] == NULL)
			ErrorExit("Unable to load %s: %s",tracks[i*2+1],SDL_GetError());
	}

	// Load SFX
	chunk[0] = Mix_LoadWAV(sounds_dir"shot.wav");
	chunk[1] = Mix_LoadWAV(sounds_dir"shot2.wav");
	chunk[2] = Mix_LoadWAV(sounds_dir"empty.wav");
	chunk[3] = Mix_LoadWAV(sounds_dir"explode.wav");
	// Check SFX's
	for(i=0;i<NUM_CHUNKS;i++)
		if(chunk[i] == NULL) 
			ErrorExit("Unable to load WAV: %s",SDL_GetError());

	//load font
	font = LoadFont(pixmaps_dir"font.png");
	//check font
	if(font == NULL)
		ErrorExit("Unable to load font: %s",SDL_GetError());

	for(i=0;i<NUM_IMAGES;i++)
	{
		obj[i] = LoadImage(images[i]);
		CheckSurface(obj[i],"Unable to load image: %s",SDL_GetError());
	}

	LoadFrames(); // Load all explosion frames

	bgimage = IMG_Load(pixmaps_dir"bg.png"); 
	CheckSurface(bgimage,"Unable to load background: %s",SDL_GetError());

	bgfull=SDL_CreateRGBSurface(SDL_HWSURFACE,
			screen->w,
			bgimage->h * (screen->h/bgimage->h+2),
			screen->format->BitsPerPixel,
			screen->format->Rmask, //RED
			screen->format->Gmask, //GREEN
			screen->format->Bmask, //BLUE
			screen->format->Amask);//ALPHA

	for (i=0;i< screen->w/bgimage->w +1;i++)
		/* w pionie wstawienie o jedną cegiełkę więcej, niż potrzeba do samego zapełnienia 
		 * prawdę mówiąc może się w teorii zdarzyć, że wstawione zostaną dwe cegiełki więcej ;) */
		for (j=0;j< screen->h/bgimage->h +2;j++)
		{
			BGRect.x=i*bgimage->w;
			BGRect.y=j*bgimage->h;
			SDL_BlitSurface(bgimage, NULL, bgfull, &BGRect);
		}	    

	SDL_FreeSurface(bgimage);

	// Set some parameters for BG
	BGSrc.w = screen->w;
	BGSrc.h = screen->h;
	BGSrc.x = 0;
	BGSrc.y = 0;
	BGRect.x = 0;
	BGRect.y = 0;   
	BGRect.w = screen->w;
	BGRect.h = screen->h;

	// Energy image
	energy = obj[11];
	// Shield image
	shield = obj[11];
	benergy = obj[14];

	// Set position of shield column
	spos.x = 0;
	// Set position of energy column
	epos.x = screen->w - shield->w;
	// Set position of boss energy column
	bpos.y = 40;

	// Set icon to a ship
	icon = obj[10];
	SetBGAlpha(icon); // Set icon background transparent

	// Set caption
	SDL_WM_SetCaption("SDL-Fighter by Radoslaw Gniazdowski",""); // Set window caption
	SDL_WM_SetIcon(icon,NULL);
	SDL_ShowCursor(0); // Do not show cursor

	// Hook function to start when music finished (set the next track) 
	//Mix_HookMusicFinished(NextMUS);
	Mix_PlayMusic(music[current_music],1); // play music
	Mix_VolumeMusic(music_volume); // set music volume
	// Set volume for all chunks
	Mix_Volume(-1,chunk_volume);

	t1 = SDL_GetTicks();
	tol_add_pack = t1; // Time of last add pack
	LoadLvlDes(&packs_info);
	NewGame();
}

/* NAME:	FreeAll
 * DESCRIPTION:	Frees all loaded files
 */
void FreeAll(void)
{
	int i;
	if(Mix_PlayingMusic() == 1 && paused_music == 0)
		Mix_FadeOutMusic(500); // Fade out music

	SDL_Delay(600);

	printf("Deleting tracks\n");
	for(i=0;i<NUM_TRACKS;i++) // Free all tracks
		if(music[i])
			Mix_FreeMusic(music[i]);

	printf("Deleting chunks\n");
	for(i=0;i<NUM_CHUNKS;i++) // chunks
		if(chunk[i])
			Mix_FreeChunk(chunk[i]);

	printf("Deleting explosion frames\n");
	for(i=0;i<NUM_BOOM_FRAMES;i++) //explosion frames
		if(frame[i])
			SDL_FreeSurface(frame[i]);

	printf("Deleting all images\n");
	for(i=0;i<NUM_IMAGES;i++) // images
		if(obj[i])
			SDL_FreeSurface(obj[i]);

	if(bgfull)
	{
		printf("Deleting BG\n");
		SDL_FreeSurface(bgfull);
	}
	if(font)
	{
		printf("Deleting font\n");
		FreeFont(font); //free font
	}

	printf("Closing audio\n");
	Mix_CloseAudio(); // Close audio
	SDL_Quit(); // Quit SDL
}

/* NAME:	TogglePause
 * DESCRIPTION:	toggles pause
 */
void TogglePause(void)
{
	paused_game = !paused_game;

	if(paused_game)
	{
		if(Mix_Playing(-1))
			Mix_Pause(-1);
	}
	else
	{
		if(Mix_Paused(-1))
			Mix_Resume(-1);
	}
}

/* NAME:	ToggleFullScr
 * DESCRIPTION:	Toggles full screen
 */
void ToggleFullScr(void)
{
	static int full=0;
	Uint32 flags=SDL_SWSURFACE;
	full=!full;
	if(full)
		flags |= SDL_FULLSCREEN;
	screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, 0, flags);
}

/* NAME:	KeyboardDown
 * DESCRIPTION:	Checks key down events
 */
void KeyboardDown(int key)
{
	switch(key)
	{
		case SDLK_ESCAPE:
		case SDLK_q:
			quit=true;
			break;
		case SDLK_p:
			if(!help && !credits)
				TogglePause();
			break;
		case SDLK_1:
			ship.weapon = CANNON;
			break;
		case SDLK_2:
			ship.weapon = MISSILE_LAUNCHER;
			break;
		case SDLK_3:
			ship.weapon = PLASMAGUN;
			break;
		case SDLK_z:
			Mix_HaltMusic();
			current_music--;
			if(current_music < 0)
				current_music = NUM_TRACKS - 1;
			Mix_PlayMusic(music[current_music],1);
			Mix_VolumeMusic(music_volume);
			break;
		case SDLK_x:
			Mix_HaltMusic();
			Mix_PlayMusic(music[current_music],1);
			break;
		case SDLK_c:
			paused_music=!paused_music;
			if(paused_music == 1)
				Mix_PauseMusic();
			else
				Mix_ResumeMusic();
			break;
		case SDLK_v:
			Mix_HaltMusic();
			break;
		case SDLK_b:
			Mix_HaltMusic();
			current_music++;
			if(current_music == NUM_TRACKS)
				current_music = 0;
			Mix_PlayMusic(music[current_music],1);
			Mix_VolumeMusic(music_volume);
			break;
		case SDLK_r:
			repeat_music = !repeat_music;
			break;
		case SDLK_RETURN:
			if(!ships || game_finished)
				NewGame(); // start new game
			break;
		case SDLK_SPACE:
			if(ships)
			{
				ship.weapon++;
				if(ship.weapon > PLASMAGUN)
					ship.weapon = CANNON;
			}
			break;
			//#ifndef WIN32
		case SDLK_F1:
			//SDL_WM_ToggleFullScreen(screen);
			ToggleFullScr();
			break;
			//#endif
		case SDLK_F2:
			if(!credits)
			{
				help = !help;
				TogglePause();
			}
			break;
		case SDLK_F3:
			if(!help)
			{
				credits = !credits;
				credits_pos = SCREEN_Y;
				TogglePause();
			}
			break;
	}
	SDL_Delay(10); //needed for dreamcast
}

/* NAME:	CountDT
 * DESCRIPTION:	Counts DT
 */
void CountDT(void)
{
	t2 = SDL_GetTicks();
	dt = (paused_game ? 0 : t2-t1); // delta time
	dt2 = t2-t1;

	if(paused_game) 
	{
		tol_add_ship+=dt2;
		tol_add_pack+=dt2;
		tol_add_littles+=dt2;
		godtime+=dt2;
		if(fawless_victory_msg_time)
			fawless_victory_msg_time+=dt2;
	}

	t1 = t2;
}

/* NAME:	CountFPS
 * DESCRIPTION:	Counts fps
 */
float CountFPS(void)
{
	static int nframes=0;
	static float fps_time=0.0f;
	nframes++;
	if(nframes==MAX_FPS_FRAME_COUNT)
	{
		fps=((float)MAX_FPS_FRAME_COUNT) / (((float)SDL_GetTicks()) / 1000.0f - fps_time);
		fps_time=((float)SDL_GetTicks()) / 1000.0f;
		nframes=0;
	}
	return fps;
}

/* NAME:	Background
 * DESCRIPTION:	Draws scrolling backgound
 */
void BackGround(void)
{
	BGPos -= (int)(ceil(0.08*dt)); //Change position of background
	if(BGPos<0) 
	{ 
		BGPos=256;
		if(!is_boss && !game_finished && ships)
			num_scrolls++;
	}
	if(num_scrolls == MAX_SCROLLS) {
		is_boss = true;
		num_scrolls = 0;
		SetBoss();
	}
	BGSrc.y = (int)BGPos;
	Paste(bgfull, &BGSrc, screen, &BGRect);
	//ClearScreen();
}

/* NAME:	DrawObjects
 * DESCRIPTION:	Draws all objects
 */
void DrawObjects()
{
	int i;

	// Rysuj wszystkie paczki
	for(i=0; i<num_packs; i++)
		DrawOBJ(packs[i]);
	// Rysuj wszystkich wrogow
	for(i=0; i<num_enemies; i++)
		DrawOBJ(enemies[i]);
	// Rysuj pociski wroga
	for(i=0; i<num_ebullets; i++)
		DrawOBJ(ebullets[i]);
	// Rysuj pociski gracza
	for(i=0; i<num_ship_bullets; i++)
		DrawOBJ(ship_bullets[i]);
	if(is_boss)
		DrawOBJ(boss);
}

/* NAME:	CheckAndDelete
 * DESCRIPTION:	Checks all objects energies and when some object is dead = removes it from the memory
 */
void CheckAndDelete(void)
{
	int i;
	// Usun wszystkich niezywych wrogow
	// Delete all dead enemies	
	for(i=0; i<num_enemies; i++)
		if(!enemies[i].energy || enemies[i].remove)
		{
			if(!enemies[i].remove)
				AddExplosionAtObj(enemies[i]);
			if(enemies[i].type == LITTLE_ENEMY)
				num_littles--;
			DeleteEnemy(i);
			i--;
		}
	// Usun wszystkie niezywe pociski
	// Delete all dead bullets
	for(i=0; i<num_ebullets; i++)
		if(!ebullets[i].energy || ebullets[i].remove)
		{
			DeleteEnemyBullet(i);
			i--;
		}
	for(i=0; i<num_ship_bullets; i++)
		if(!ship_bullets[i].energy || ship_bullets[i].remove)
		{
			DeleteShipBullet(i);
			i--;
		}
	// Usun wszystkie niezywe paczki 
	// (paczka jest martwa wtedy gdy jest juz wzieta, lub jest juz za ekranem)
	// Delete all dead packs 
	// (pack is dead when it's picked up, or when it's behind some screen edge)
	for(i=0; i<num_packs; i++)
		if(!packs[i].energy || packs[i].remove)
		{
			DeletePack(i);
			i--;
		}
}

/* NAME:	ServeEnemies
 * DESCRIPTION:	Moves all enemies
 */
void ServeEnemies(void)
{
	int w = obj[PLASMA_BULLET_IMG]->w;
	int i;
	for(i=0;i<num_enemies;i++)
	{
		// Check collisions for this enemy
		CheckEnemyCollisions(i);
		// Change his weapon
		enemies[i].weapon = rand_ab(eweapons[current_level-1][0], eweapons[current_level-1][1]);
		// Shooting
		if(t2 - enemies[i].tols > espeed[current_level-1] && enemies[i].type == ENEMY && !is_boss && !game_finished && ships)
		{
			if(enemies[i].weapon == CANNON)
				AddEnemyBullet(enemies[i].pos1.x + enemies[i].image->w/2,enemies[i].pos1.y + enemies[i].image->h,BULLET);
			else if(enemies[i].weapon == MISSILE_LAUNCHER)
				AddEnemyBullet(enemies[i].pos1.x + enemies[i].image->w/2,enemies[i].pos1.y + enemies[i].image->h,MISSILE);
			else
				AddEnemyBullet(enemies[i].pos1.x + enemies[i].image->w/2 - w/2,enemies[i].pos1.y + enemies[i].image->h,PLASMA_BULLET);
			enemies[i].tols = t2;
		}
		else if(t2 - enemies[i].tols > LITTLE_ENEMY_SHOT_TIME_DELAY && enemies[i].type == LITTLE_ENEMY && !game_finished && ships)
		{
			AddEnemyBullet(enemies[i].pos1.x + enemies[i].image->w/2,enemies[i].pos1.y + enemies[i].image->h,BULLET);
			enemies[i].tols = t2;
		}
		// Move the enemy
		enemies[i].MoveOBJ(&enemies[i]);
	}
}

/* NAME:	ServeBullets
 * DESCRIPTION:	Moves all bullets
 */
void ServeBullets(void)
{
	int i;
	for(i=0;i<num_ebullets;i++)
		ebullets[i].MoveOBJ(&ebullets[i]);
	for(i=0;i<num_ship_bullets;i++)
		ship_bullets[i].MoveOBJ(&ship_bullets[i]);
}

/* NAME:	ServeBoss
 * DESCRIPTION:	Moves boss
 */
void ServeBoss(void)
{
	int w = obj[PLASMA_BULLET_IMG]->w;
	// Check collisions for boss
	CheckBossCollisions();
	// Change boss weapon
	boss.weapon = rand_ab(CANNON, PLASMAGUN);
	// Boss shooting
	if(t2 - boss.tols > BOSS_SHOT_TIME_DELAY && !game_finished && ships)
	{
		if(boss.weapon == CANNON)
			AddEnemyBullet(boss.pos1.x + boss.image->w/2, boss.pos1.y + boss.image->h, BULLET);
		else if(boss.weapon == MISSILE_LAUNCHER)
			AddEnemyBullet(boss.pos1.x + boss.image->w/2, boss.pos1.y + boss.image->h, MISSILE);
		else
		{
			AddEnemyBullet(boss.pos1.x + boss.image->w/2 - w/2, boss.pos1.y + boss.image->h, PLASMA_BULLET);

			AddEnemyBullet(boss.pos1.x - w/2, boss.pos1.y + boss.image->h/2, PLASMA_BULLET);
			AddEnemyBullet(boss.pos1.x + boss.image->w - w/2, boss.pos1.y + boss.image->h/2, PLASMA_BULLET);
		}
		boss.tols = t2;
	}
	boss.MoveOBJ(&boss);
}

/* NAME:	ServePacks
 * DESCRIPTION:	Moves packs
 */
void ServePacks(void)
{
	int i;
	for(i=0;i<num_packs;i++)
		packs[i].MoveOBJ(&packs[i]);
}

/* NAME:	ServeObjects
 * DESCRIPTION:	Draws objects, moves objects
 */
void ServeObjects(void)
{
	// Add enemy after every ENEMY_TIME_DELAY miliseconds
	if(t2 - tol_add_ship > ENEMY_TIME_DELAY && !is_boss && !paused_game && !game_finished)
	{
		AddEnemy(ENEMY);
		tol_add_ship = t2;
	}
	// Add pack after every packs_info.time_delay[cur_pack_info] miliseconds
	if(t2 - tol_add_pack > packs_info.time_delay[cur_pack_info] && !paused_game && !game_finished)
	{
		AddPack(packs_info.pack_type[cur_pack_info]);
		tol_add_pack = t2;
		cur_pack_info++;
		if(cur_pack_info>=MAX_LVL_DES_ELEMENTS)
			cur_pack_info=0;
	}
	// Add little enemies after every six seconds 
	// (only when number of little enemies is 0, and there is boss)
	if(t2 - tol_add_littles > LITTLE_ENEMY_TIME_DELAY && is_boss && !paused_game && !game_finished && !num_littles)
	{
		AddLittles();
		tol_add_littles = t2;
	}
	// Update time
	if(num_littles || !is_boss)
		tol_add_littles = t2;
	if(!paused_game)
	{
		ServeEnemies();
		ServeBullets();
		if(is_boss)
			ServeBoss();
		ServePacks();
		CheckScreenEdges();
		CheckShipCollisions(); // Check players ship collisions
	}
	// Draw the all objects
	DrawObjects();
	if(ship.energy && !godmode && ships)
		DrawOBJ(ship); // Draw player ship
	else if(SDL_GetTicks()%300 < 150 && godmode && ships)
		DrawOBJ(ship);
	DrawExplosions(); // Draw the all explosions
	//Check for some dead objects
	CheckAndDelete();
}

/* NAME:	KeyEvents
 * DESCRIPTION:	Checks for all keyboard events
 */
void KeyEvents()
{
	int ttw[3] = {110, 200, 185};
	// odczytanie klawiszy
	while(SDL_PollEvent(&event))
	{
		switch(event.type)
		{
			case SDL_QUIT:
				quit=true;
				break;
			case SDL_KEYDOWN:
				KeyboardDown(event.key.keysym.sym);
				break;
			default:
				break;
		}
	}
	keys = SDL_GetKeyState(NULL);
	if(!paused_game) 
	{
		// Player shooting
		if(ships && (keys[SDLK_LCTRL] || keys[SDLK_RCTRL]))
		{
			if(t2 - ship.tols > ttw[ship.weapon]/shooting_spd)
			{
				if(ship.weapon == CANNON)
				{
					if(player_ammo[CANNON] > 0)
					{
						AddShipBullet(SHIP_BULLET); // Add bullet
						player_ammo[CANNON]--;
						Mix_PlayChannel(-1,chunk[0],0); // Play shot
					}
					else
						Mix_PlayChannel(-1,chunk[2],0); // Empty
				}
				else if(ship.weapon == MISSILE_LAUNCHER)
				{
					if(player_ammo[MISSILE_LAUNCHER] > 0)
					{
						AddShipBullet(SHIP_MISSILE); // Add missile
						player_ammo[MISSILE_LAUNCHER]--;
						Mix_PlayChannel(-1,chunk[1],0);
					}
					else
						Mix_PlayChannel(-1,chunk[2],0);
				}
				else if(ship.weapon == PLASMAGUN)
				{
					if(player_ammo[PLASMAGUN] > 0)
					{
						AddShipBullet(SHIP_PLASMA_BULLET); // Add plasma bullet
						player_ammo[PLASMAGUN]--;
						Mix_PlayChannel(-1,chunk[1],0);
					}
					else
						Mix_PlayChannel(-1,chunk[2],0);
				}
				ship.tols = t2;
			}
		} //ships && (keys[SDLK_LCTRL] || keys[SDLK_RCTRL])
		// Move player ship up
		if(keys[SDLK_UP])
			ShipMoveUp();
		// Move player ship down
		if(keys[SDLK_DOWN])
			ShipMoveDown();
		// Move player ship right
		if(keys[SDLK_RIGHT])
			ShipMoveRight();
		// Move player ship  left
		if(keys[SDLK_LEFT])
			ShipMoveLeft();
	} //!paused_game 

	// Increment music volume
	if(keys[SDLK_KP_PLUS]) 
	{
		music_volume+=2;
		if(music_volume > 128)
			music_volume = 128;

		Mix_VolumeMusic(music_volume);
	}
	// Decrement music volume
	if(keys[SDLK_KP_MINUS])	
	{
		music_volume-=2;
		if(music_volume < 0)
			music_volume = 0;
		Mix_VolumeMusic(music_volume);
	}
	// Increment sfx volume
	if(keys[SDLK_u]) 
	{
		chunk_volume+=2;
		if(chunk_volume > 100)
			chunk_volume = 100;
		Mix_Volume(-1,chunk_volume);
	}
	// Decrement sfx volume
	if(keys[SDLK_j]) 
	{
		chunk_volume-=2;
		if(chunk_volume < 0)
			chunk_volume = 0;
		Mix_Volume(-1,chunk_volume);
	}
	// Increment gamma
	if(keys[SDLK_RIGHTBRACKET])
	{
		gamma_val+=0.2f;
		if(gamma_val > MAX_GAMMA)
			gamma_val = MAX_GAMMA;
		SDL_SetGamma(gamma_val, gamma_val, gamma_val);
	}
	// Decrement gamma
	if(keys[SDLK_LEFTBRACKET])
	{
		gamma_val-=0.2f;
		if(gamma_val < MIN_GAMMA)
			gamma_val = MIN_GAMMA;
		SDL_SetGamma(gamma_val, gamma_val, gamma_val);
	}
	if(keys[SDLK_EQUALS])
	{
		gamma_val = 1.0f;
		SDL_SetGamma(gamma_val, gamma_val, gamma_val);
	}
}

/* NAME:	CheckParameters
 * DESCRIPTION:	Checks parameters
 */
void CheckParameters(int argc, char **argv)
{
	int i;
	//Changed resolution for dreamcast
	SCREEN_X = 640;
	SCREEN_Y = 480;

	printf("Available parameters are:\n\tres=[1024x768|800x600|640x480]\n\n");

	for(i=1;i<argc;i++)
	{
		if(strcmp(argv[i],"res=1024x768") == 0)
		{
			SCREEN_X = 1024;
			SCREEN_Y = 768;
		}
		else if(strcmp(argv[i],"res=800x600") == 0)
		{
			SCREEN_X = 800;
			SCREEN_Y = 600;
		}
		else if(strcmp(argv[i],"res=640x480") == 0)
		{
			SCREEN_X = 640;
			SCREEN_Y = 480;
		}
	}
	printf("Resolution %dx%d\n\n", SCREEN_X, SCREEN_Y);
}

/* NAME:	Idle
*/
void Idle(void)
{
	//Count FPS (frames per second)
	CountFPS();
	//Count DT (delta time)
	CountDT();
	if(abs(last_enemy_kill[1] - last_enemy_kill[0]) <= MAX_BONUS_KILL_INTERVAL && last_kill_time_id==1)
	{
		score+=250;
		last_kill_time_id = -1;
		AddMessage("---=== BONUS QUICK KILL ===---");
	}
	// energia 0, sa jeszcze statki -> nowy statek
	if(!ship.energy && ships)
		SetShip();
	KeyEvents();
}

/* NAME:	Draw
 * DESCRIPTION:	Draws all objects on the screen
 */
void Draw(void)
{
	BackGround();
	ServeObjects();
	ShowText();
	SDL_Flip(screen); //flip screen
}

/* NAME:	main
 * DESCRIPTION:	Main function
 */
int main(int argc, char **argv)
{
	CheckDir();
	CheckParameters(argc, argv);
	Init();
	#ifdef DREAMCAST
	clearevents(); //important for the dreamcast!
	#endif
	while(!quit)
	{
		Idle();
		Draw();
	} // while(!quit)
	// Free all loaded files
	FreeAll();
	printf("\n%sGAME OVER!%s Your score: %s%d%s\n",red[0], red[1], green[0], score, green[1]);
	return 0;
}

void clearevents(void)
{
    SDL_Event dcevent;
	SDL_PollEvent(&dcevent);
}
