/*
* Copyright 2023, Ali Arya
* Anyone Can Code: Algorithmic Thinking
* Example 6.5c
*/

#include "Main.h"

#define SCREEN_W 640
#define SCREEN_H 480

class GameObject
{
public:
	int x;
	int y;
	SDLX_Bitmap* shape;
	bool visible;

	void Init(char* fname, int xx, int yy)
	{
		shape = SDLX_LoadBitmap(fname);
		x = xx;
		y = yy;
		visible = true;
	}
	void Move()
	{
		x += rand() % 5 - 2;
		y += rand() % 5 - 2;
	}
	void Draw()
	{
		if(visible)
			SDLX_DrawBitmap(shape, x, y);
	}
	bool Collision(GameObject* obj)
	{
		int distanceX = abs(x - obj->x);
		int distanceY = abs(y - obj->y);
		if (distanceX < 10 && distanceY < 10)
			return true;
		else
			return false;
	}
};
class Enemy
{
public:
	int x;
	int y;
	SDLX_Bitmap* shape;
	bool visible;
	int vx;
	int vy;
	int age;

	Enemy()
	{
		shape = SDLX_LoadBitmap("Enemy.bmp");
		x = 200;
		y = 200;
		visible = true;
		vx = rand() % 5 - 2;
		vy = rand() % 5 - 2;
		age = 0;
	}
	Enemy(char* fname, int xx, int yy)
	{
		shape = SDLX_LoadBitmap(fname);
		x = xx;
		y = yy;
		visible = true;
		vx = rand() % 5 - 2;
		vy = rand() % 5 - 2;
		age = 0;
	}
	Enemy(SDLX_Bitmap* bmp, int xx, int yy)
	{
		shape = bmp;
		x = xx;
		y = yy;
		visible = true;
		vx = rand() % 5 - 2;
		vy = rand() % 5 - 2;
		age = 0;
	}
	Enemy(Enemy* e) //clone
	{
		shape = e->shape;
		x = e->x;
		y = e->y;
		visible = e->visible;
		vx = rand() % 5 - 2;
		vy = rand() % 5 - 2;
		age = 0;
	}
	Enemy* Move()
	{
		Enemy* e = NULL;
		//move
		x += vx;
		y += vy;
		//bounce
		if (x < 0 || x > SCREEN_W)
			vx *= -1;
		if (y < 0 || y > SCREEN_H)
			vy *= -1;
		//clone
		if (age != -1)
		{
			age++;
			if (age == 50)
			{
				e = new Enemy(this);
				age = -1; //don't clone again
			}
		}
		return e;
	}
	void Draw()
	{
		if (visible)
			SDLX_DrawBitmap(shape, x, y);
	}
	bool Collision(GameObject* obj)
	{
		int distanceX = abs(x - obj->x);
		int distanceY = abs(y - obj->y);
		if (distanceX < 10 && distanceY < 10)
			return true;
		else
			return false;
	}
};
class EnemyListItem
{
public:
	Enemy* e;
	EnemyListItem* next;
	EnemyListItem()
	{
		e = NULL;
		next = NULL;
	}
	EnemyListItem(SDLX_Bitmap* shape, int x, int y)
	{
		e = new Enemy(shape, x, y);
		next = NULL;
	}
};
class EnemyList
{
public:
	EnemyListItem* first;	//first on the linked list
	EnemyListItem* last;		//last on the linked list
	SDLX_Bitmap* shape;	//common shape for all enemies

	EnemyList()
	{
		shape = SDLX_LoadBitmap("Enemy.bmp");
		first = last = new EnemyListItem(shape, 200, 200);
	}
	void Delete()
	{
		//remove an item from the list and delete it
	}
	void Move()
	{
		EnemyListItem* temp = first;
		while (temp != NULL)
		{
			Enemy* e = temp->e->Move();
			if (e != NULL)
			{
				EnemyListItem* li = new EnemyListItem();
				li->e = e;
				last->next = li;
				last = li;
			}
			temp = temp->next;
		}
	}
	void Draw()
	{
		EnemyListItem* temp = first;
		while (temp != NULL)
		{
			temp->e->Draw();
			temp = temp->next;
		}
	}
	bool Collision(GameObject* obj)
	{
		bool result = false;
		EnemyListItem* temp = first;
		while (temp != NULL)
		{
			result = temp->e->Collision(obj);
			if (result)
				break;
			temp = temp->next;
		}
		return result;
	}
};
int main(int argc, char* argv[])
{
	/////////////////////////////////////////////////////////////////
	// INIT part of the game
	// things that are done only once at the start (initialization)
	/////////////////////////////////////////////////////////////////

	//set the seed of random generator to current time, so random numbers will be different each run
	srand(time(NULL));

	//init SDL library and graphics window
	SDLX_Init("Simple 2D Game", SCREEN_W, SCREEN_H, true);

	//game map (background)
	SDLX_Bitmap* map = SDLX_LoadBitmap("map.bmp", false, NULL); //do not use any mask for transparent color

	//game objects
	GameObject player;
	player.Init((char*)"Player.bmp", 0, 0);
	GameObject prize;
	prize.Init((char*)"Prize.bmp", 200, 200);

	//enemies
	EnemyList enemies;

	bool quit = false;
	bool win = false;

	bool right = false;
	bool left = false;
	bool up = false;
	bool down = false;

	/////////////////////////////////////////////////////////////////
	//--------Main game Loop---------- -
	// things that are done repeatedly
	/////////////////////////////////////////////////////////////////
	while (!quit)
	{
		/////////////////////////////////////////////
		// UPDATE
		/////////////////////////////////////////////

		//check if we hit the prize
		if(player.Collision(&prize))
		{
			quit = true;
			win = true;
			prize.visible = false;
		}
		//check if we hit the enemy
		if (enemies.Collision(&player))
		{
			player.visible = false;
			quit = true;
			win = false;
		}

		//check if there is any movement
		//player controlled by keyboard
		SDLX_Event e;
		//keyboard events
		if (SDLX_PollEvent(&e))
		{
			if (e.type == SDL_KEYDOWN)
			{
				if (e.keycode == SDLK_ESCAPE)
					quit = true;
				//update player  
				if (e.keycode == SDLK_RIGHT)
					right = true;
				if (e.keycode == SDLK_LEFT)
					left = true;
				if (e.keycode == SDLK_UP)
					up = true;
				if (e.keycode == SDLK_DOWN)
					down = true;
			}
			if (e.type == SDL_KEYUP)
			{
				if (e.keycode == SDLK_RIGHT)
					right = false;
				if (e.keycode == SDLK_LEFT)
					left = false;
				if (e.keycode == SDLK_UP)
					up = false;
				if (e.keycode == SDLK_DOWN)
					down = false;
			}
		}

		//update player
		if (right)
			player.x += 3;
		if (left)
			player.x -= 3;
		if (up)
			player.y -= 3;
		if (down)
			player.y += 3;

		//update enemy
		enemies.Move();

		/////////////////////////////////////////////
		// DRAW
		/////////////////////////////////////////////
		//note the order (last one will be drawn on top)
		SDLX_DrawBitmap(map, 0, 0);
		prize.Draw();
		enemies.Draw();
		player.Draw();

		//Update the screen
		SDLX_Render();


		//now wait for loop timing
		SDLX_Delay(1);
	}

	SDLX_Delay(3000);

	return 0;
}