#include <math.h>
#include "Graphics.h"
 
Graphics graphics;
bool key_states[256];

//estrutura de informacoes do tiro
typedef struct tiro{
	float pos_x;
	float pos_y;
	bool ativo;
}Tiro;

//estrutura de informacoes da nave
typedef struct nave{
	Image imagemNormal;
	Image imagemTurbo;
	float pos_x;
	float pos_y;
	float velocidade;
	bool turbo;
	Tiro tiros[20]; //vetor de tiros associado a nave
	int tiro_cont;
	bool atirar;
} Nave;

Nave player;

//estrutura de informacoes das estrelas
typedef struct estrela{
	float pos_x;
	float pos_y;
	float velocidade;
} Estrela; 

//vetor com 300 estrelas
Estrela estrelas[300];
//fator de velocidade de movimentacao das estrelas
int fatorVelocidadeEstrelas = 1;

//funcao de loop principal do jogo
void MainLoop()
{	
	int x;
	//desenha o vetor de estrelas na tela
	for (x = 0; x < 300; x++)
	{
		//movimenta a estrela no eixo x
		estrelas[x].pos_x = estrelas[x].pos_x - ((fatorVelocidadeEstrelas * estrelas[x].velocidade) * graphics.GetElapsedTime());

		//se a estrela saiu da tela, posiciona ela no inicio da tela novamente
		if (estrelas[x].pos_x < -10)
			estrelas[x].pos_x = graphics.GetScreenWidth() + 10;

		//define a cor da estrela de acordo com a sua velocidade 
		//(estrelas mais proximas sao mais brilhantes e rapidas, ja estrelas distantes sao mais lentas e menos brilhantes)
		graphics.SetColor(estrelas[x].velocidade, estrelas[x].velocidade, estrelas[x].velocidade);

		//desenha um retangulo na tela para representar a estrela
		graphics.FillRectangle2D(estrelas[x].pos_x, estrelas[x].pos_y, estrelas[x].pos_x + 3, estrelas[x].pos_y + 3);
	}

    if (key_states[KEY_LEFT] == true) //se a seta da esquerda for pressionada
	{
		//movimenta a nave para tras se ela nao estiver fora da tela
		if (player.pos_x + (player.imagemNormal.width / 3) > 0)
			player.pos_x = player.pos_x - (player.velocidade * graphics.GetElapsedTime());
	}
	if (key_states[KEY_RIGHT] == true) //se a seta da direita for pressionada
	{
		//movimenta a nave para frente se ela nao estiver fora da tela
		if (player.pos_x + player.imagemNormal.width < graphics.GetScreenWidth())
			player.pos_x = player.pos_x + (player.velocidade * graphics.GetElapsedTime());
	}
	if (key_states[KEY_UP] == true) //se a seta para cima for pressionada
	{
		//movimenta a nave para cima se ela nao estiver fora da tela
		if (player.pos_y + (player.imagemNormal.height / 1.5) < graphics.GetScreenHeight())
			player.pos_y = player.pos_y + (player.velocidade * graphics.GetElapsedTime());
	}
	if (key_states[KEY_DOWN] == true) //se a seta para baixo for pressionada
	{
		//movimenta a nave para baixo se ela nao estiver fora da tela
		if (player.pos_y + (player.imagemNormal.height / 3) > 0)
			player.pos_y = player.pos_y - (player.velocidade * graphics.GetElapsedTime());
	}

	//desenha o vetor de tiros
	for (x = 0; x < 20; x++)
	{
		//desenha somente se o tiro estiver ativo
		if (player.tiros[x].ativo == true)
		{
			//se o tiro ainda estiver visivel na tela, movimenta ele no eixo x
			if (player.tiros[x].pos_x < graphics.GetScreenWidth())
				player.tiros[x].pos_x = player.tiros[x].pos_x + (700 * graphics.GetElapsedTime());
			else // se o tiro sair da tela, desativa ele
				player.tiros[x].ativo = false;
	
			//desenha um retangulo representando o tiro na cor vermelha
			graphics.SetColor(255, 0, 0);
			graphics.FillRectangle2D(player.tiros[x].pos_x, player.tiros[x].pos_y, player.tiros[x].pos_x + 6, player.tiros[x].pos_y + 3);
		}
	}
		
	if (player.turbo == true) //desenha a nave com o turbo ativo na posicao pos_x e pos_y da tela
		graphics.DrawImage2D(player.pos_x, player.pos_y, 128, 128, player.imagemTurbo);
	else  //desenha a nave na posicao pos_x e pos_y da tela
		graphics.DrawImage2D(player.pos_x, player.pos_y, 128, 128, player.imagemNormal);

}

//Funcao para verificar o pressionamento de teclas do teclado
void KeyboardInput(int key, int state, int x, int y)
{ 
    if (state == KEY_STATE_DOWN)
        key_states[key] = true;
    else if (state == KEY_STATE_UP)
        key_states[key] = false;

	//se a tecla shift da direita ou da esqueda forem pressionadas
	if (((key == KEY_LEFTSHIFT)||(key == KEY_RIGHTSHIFT))&&(state == KEY_STATE_DOWN))
	{
		//aumenta o fator de velocidade das estrelas e ativa o turbo da nave
		fatorVelocidadeEstrelas = 4;
		player.turbo = true;
	}
	//se a tecla shift da direita ou da esqueda forem liberadas
	else if (((key == KEY_LEFTSHIFT)||(key == KEY_RIGHTSHIFT))&&(state == KEY_STATE_UP))
	{
		//restaura o fator de velocidade das estrelas e desativa o turbo da nave
		fatorVelocidadeEstrelas = 1;
		player.turbo = false;
	}

	//se a tecla espaco foi pressionada
	if ((key == ' ')&&(state == KEY_STATE_DOWN))
	{
		//se o jogador pode atirar
		if (player.atirar == true)
		{			
			//ativa o tiro e inicializa a sua posicao inicial de acordo com a posicao da nave
			player.tiros[player.tiro_cont].ativo = true;
			player.tiros[player.tiro_cont].pos_x = player.pos_x + player.imagemNormal.width;
			player.tiros[player.tiro_cont].pos_y = player.pos_y + (player.imagemNormal.height/2);

			player.tiro_cont = player.tiro_cont + 1;
			//desabilita o tiro do jogador (somente habilita novamente quando ele soltar a tecla espaco)
			player.atirar = false;

			if (player.tiro_cont >= 20)			
				player.tiro_cont = 0;
		}	
	}
	//se a tecla espaco foi liberada, permite o jogador possa atirar novamente
	if ((key == ' ')&&(state == KEY_STATE_UP))
		player.atirar = true;
}

//Funcao para gerar aleatoriamente a pocisao e velocidade das estrelas
void GeraEstrelas()
{
	int x;
	for (x = 0; x < 300; x++)
	{
		estrelas[x].pos_x = rand() % graphics.GetScreenWidth(); //posicao x aleatoria
		estrelas[x].pos_y = rand() % graphics.GetScreenHeight(); //posicao y aleatoria
		estrelas[x].velocidade = 1 + rand() % 200; //valocidade aleatoria
	}
}
 
int main(void)
{
	//cria janela para o jogo
	graphics.CreateMainWindow(800, 600, "Oficina de Engenharia da Computação");
    //define a cor de fundo da tela: preto (RGB - 0,0,0)
	graphics.SetBackgroundColor(0, 0, 0);
 
	//carrega a imagem da nave que esta na pasta Images
	player.imagemNormal.LoadPNGImage("Images/hero-ship.png"); 
	//carrega a imagem da nave com o turbo ativo
	player.imagemTurbo.LoadPNGImage("Images/hero-ship-boosted.png"); 
	
	//define a posicao inicial e a velocidade da nave
	player.pos_x = 100;
	player.pos_y = 250;
	player.velocidade = 200;
	player.turbo = false;
	player.tiro_cont = 0;
	player.atirar = true;
	
	//cria aleatoriamente as estrelas
	GeraEstrelas();
 
	//define as funcoes de pressionamento de teclas e loop do aplicativo
    graphics.SetKeyboardInput(KeyboardInput);
    graphics.SetMainLoop(MainLoop);

	//inicia o loop do aplicativo
    graphics.StartMainLoop();
    return 0;
}