// gameballworld.h  A side-scroller game.
//
//////////////////////////////////////////////////////////////////////

#ifndef GAMEBALLWORLD_H
#define GAMEBALLWORLD_H

#include "game.h"
#include "critterarmed.h"
#include "critterwall.h"

//==============Critters for the cGameBallworld: Player, Ball, Treasure ================

class cCritterBallworldPlayer : public cCritterArmedPlayer 
{
DECLARE_SERIAL(cCritterBallworldPlayer)
private:
	Real _lasthit;  // Age when last hit.
public:
	cCritterBallworldPlayer(cGame *pownergame = NULL);
	BOOL collide(cCritter *pcritter);
	
	void setLasthit(Real time){_lasthit = time;}
	Real lasthit(){return _lasthit;}
};

class cCritterBallProp : public cCritter //A ball with friction & gravity
{
DECLARE_SERIAL(cCritterBallProp)
private:
	bool dead;
	
	Real left_range;
	Real right_range;
	bool isFlying;


public:
	cCritterBallProp(cGame *pownergame = NULL);
	void update(CPopView *pactiveview, Real dt); // do a delete_me if you hit the left end
	void die(); //Overload to give score to the player when it jumps on it.

	// functions we've added
	bool isDead() { return dead; }
	cCritterBallProp(cGame *pownergame, Real _left_range, Real _right_range, bool _isFlying, Real init_velocity);
};

class cCritterTreasure : public cCritter
{ //A hollow circle.  objects disappear when they get fully inside it.
DECLARE_SERIAL(cCritterTreasure)
public:
	cCritterTreasure(cGame *pownergame = NULL);
	virtual BOOL collide(cCritter *pcritter); //Checks if pcritter inside.
	int cCritterTreasure::collidesWith(cCritter *pothercritter); /* Only collide
		with cCritterBallworldPlayer. */
};


//======================cGameBallworld==========================

class cGameBallworld : public cGame
{
DECLARE_SERIAL(cGameBallworld);
public:
	static Real WALLTHICKNESS;
	static Real TREASURERADIUS;
	static Real LEVELTIMER;
private:
	cCritterTreasure* _ptreasure;
	cCritterBallProp** _theseEnemies;
	int _cur_level;
	int _numLevels;

	struct _enemy
	{
		_enemy()
		{
			_enemy(0, 0, 0, 0, false, 0);
		}

		_enemy(Real x, Real y, Real lrange, Real rrange, bool isFlying, Real initVel)
			: x(x),
			  y(y),
			  lrange(lrange),
			  rrange(rrange),
			  isFlying(isFlying),
			  initVel(initVel)
		{ }

		Real x;
		Real y;

		Real lrange;
		Real rrange;
		bool isFlying;
		Real initVel;

		cVector2 getVector()
		{
			return cVector2(x, y);
		}
	};

	struct _wall
	{
		_wall()
		{
			_wall(0, 0, 0, 0);
		}

		_wall(Real ux, Real uy, Real lx, Real ly)
			: ux(ux),
			  uy(uy),
			  lx(lx),
			  ly(ly)
		{ }

		Real ux;
		Real uy;
		Real lx;
		Real ly;

		cVector2 getUpperVector()
		{
			return cVector2(ux, uy);
		}

		cVector2 getLowerVector()
		{
			return cVector2(lx, ly);
		}
	};

	struct _level
	{
		int _lastEnemy;
		int _lastWall;

		int _numEnemies;
		int _numWalls;
		_enemy* _enemies;
		_wall*  _walls;

		_level()
			: _lastEnemy(0),
			  _lastWall(0)
		{
			init(0, 0);
		}

		void init(int numEnemies, int numWalls)
		{
			_numEnemies = numEnemies;
			_numWalls   = numWalls;

			if (numEnemies > 0)
				_enemies = new _enemy[numEnemies];
			else
				_enemies = NULL;

			if (numWalls > 0)
				_walls   = new _wall [numWalls];
			else
				_walls   = NULL;
		}

		_level(int numEnemies, int numWalls) 
			: _lastEnemy(0),
			  _lastWall(0)
		{
			init(numEnemies, numWalls);
		}

		~_level()
		{
			delete [] _enemies;
			delete [] _walls;
		}

		void addEnemy(Real x, Real y, Real lrange, Real rrange, bool isFlying, Real iVel)
		{
			if (_lastEnemy >= _numEnemies)
				return;

			_enemies[_lastEnemy++] = _enemy(x, y, lrange, rrange, isFlying, iVel);
		}

		void addWall(Real ux, Real uy, Real lx, Real ly)
		{
			_walls  [_lastWall++ ] = _wall(ux, uy, lx, ly);
		}
	};

	_level* _levels;

public:
	cGameBallworld();
	virtual int worldShape(){return cGame::SHAPE_XSCROLLER;} 
		/* Need this to signal the cCritterViewer to not wobble up and down when
		 _trackplayer is on. Overrides the default worldShape of cGame::SHAPE_RECT.*/
	virtual void seedCritters();

	virtual void gotoNextLevel();

	virtual void initializeView(CPopView *pview);
	virtual void initializeViewpoint(cCritterViewer *pviewer); /* Move over to be above the
		lower left corner where the player is.  In 3D, use a low viewpoint low looking up. */
	virtual void adjustGameParameters();
	virtual CString statusMessage();
	virtual void Serialize(CArchive& ar);
};

//======Add walls to wonderful Ballworld======
class cCritterBallWall : public cCritterWall
{
DECLARE_SERIAL(cCritterBallWall);
public:
	cCritterBallWall(cGame *pownergame = NULL):cCritterWall(pownergame){}
		//Don't actually use this one.
	cCritterBallWall(const cVector &enda, const cVector &endb, 
		Real thickness = cGameBallworld::WALLTHICKNESS, cGame *pownergame= NULL);
};

#endif //GAMEBALLWORLD_H