// gamemyproject.cpp: implementation of the generic cGameMyProject class.
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "gamemyproject.h"
#include "critterarmed.h"
#include "listener.h"
#include "spriteicon.h"
#include "pop.h" //for playSound
#include "popview.h"
#include "force.h"
#include "spritebubble.h"
#include "graphicsopengl.h"
#include "graphicsmfc.h"
#include "critterviewer.h"
#include "spritemultiicon.h"

IMPLEMENT_SERIAL(cGameMyProject, cGame, 0);
IMPLEMENT_SERIAL(cCritterMyProjectPlayer, cCritterArmedPlayer, 0);
IMPLEMENT_SERIAL(cCritterMyProjectRival, cCritterArmedRobot, 0);
IMPLEMENT_SERIAL(cCritterMyProjectProp, cCritter, 0);
IMPLEMENT_SERIAL(cCritterMyProjectPlayerBullet, cCritterBullet, 0);
IMPLEMENT_SERIAL(cCritterMyProjectRivalBullet, cCritterBullet, 0);


//#define DEBUGMYPROJECT  //Comment DEBUGMYPROJECT in to start with only one critter besides player.
//==============================cGameMyProject
int cGameMyProject::PLAYERHEALTH = 25;  //Start with a very high health for demo purposes,
		//Do you don't die so fast.  Usually use a lower value for a real game.
int cGameMyProject::DEFAULTSEEDCOUNT = 5;
int cGameMyProject::DEFAULTRIVALCOUNT = 5;

cGameMyProject::cGameMyProject() //The constructor gets called only once, at first start.
{	
	_rivalcount = cGameMyProject::DEFAULTRIVALCOUNT; //The number of cCritterRival that I plan to add.
	_seedcount = cGameMyProject::DEFAULTSEEDCOUNT; //The number of cCritterMyProjectProp that I plan to add.
	_wrapflag = cCritter::BOUNCE;
#ifdef DEBUGMYPROJECT
	_rivalcount = 0;
	_seedcount = 1;
#endif //DEBUGMYPROJECT
	_spritetype = cGame::ST_BUBBLES; //Default sprite for cCritterMyProjectProp critters
	_menuflags &= ~cGame::MENU_RIDEPLAYER; /* Since I use so many bitmaps in this one,
		if I ride the player in 3D it runs bad with all the close up bitmaps. */
//Fix your statics
	cCritter::MAXSPEED = 4.0; /* Customary to set critter speed, usually the
		bigger the world the higher the speed you want. */
//Set the cursor tools.
	/*_arrayHCURSOR has only the _hCursorArrow inherited from cGame. 
		 Add a Shooting cursor and a Dragging cursor for fun. */
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorPlay); 
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorDragger); 
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorPin);
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorReplicate); 
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorZap); 
//Set your world shape _border.set(width, height)
	_border.set(60.0, 40.0);//Standard is (14.4, 9.6), can override here
//Set the backgroudn bitmap
	setBackgroundBitmap(IDB_BACKGROUND); /*  Sets the cSpriteBackground for the background bitmap.
		Note that you must call this after the _border has its size fully initialized. So each
		cGame child with a different border should call this again in its constructor. */
//Set wrap with setWrapflag(cCritter::WRAP) or cCritter::BOUNCE.
//Make a player
	setPlayer(new cCritterMyProjectPlayer(this)); //"this" arg sets default player _movebox to match _border.
//Possibly make and add any permanent critters here.
}

/* seedCritters makes and positions any temporary critters.  This gets
	automatically called when we select a game by the CPopDoc::setGameClass call.  It also gets
	called by cGame::reset() if you restart a game.*/
void cGameMyProject::seedCritters()
{
	pbiota()->purgeNonPlayerNonWallCritters(); 
		/* Clean out any old non-player non-wall critters. Although we don't have 
			walls yet, you might want to put some in. */
	/* Note that I can have some switch behavior in here depending on _level. */
	
 	for (int i=0; i < _seedcount; i++)
		 new cCritterMyProjectProp(this); 
	for (i=0; i<_rivalcount; i++)
		new cCritterMyProjectRival(this);
}

/* cGameMyProject::reset does not get called at first startup, is called only when you start a
	 new round or level of the game.*/
void cGameMyProject::reset() 
{
	_rivalcount = cGameMyProject::DEFAULTRIVALCOUNT;
	_seedcount = cGameMyProject::DEFAULTSEEDCOUNT;
	cGame::reset(); //Calls pplayer()->reset() and seedCritters().
	//Soemtimes reset other parameters here.
}

/* This gets called at startup and when you begin a new game.  This is the
place to set the background or the kind of cursor you want to use. */
void cGameMyProject::initializeView(CPopView *pview)
{
	cGame::initializeView(pview); //Always call the baseclass method.
	pview->setUseBackgroundBitmap(TRUE); //Default is FALSE
	pview->pviewpointcritter()->setTrackplayer(TRUE); //Always look at the player.
}

void cGameMyProject::initializeViewpoint(cCritterViewer *pviewer)
{
		/* The two args to setViewpoint are (directiontoviewer, lookatpoint).
			Note that directiontoviewer points FROM the origin TOWARDS the viewer. */
	if (pviewer->is3D())
	{
		pviewer->setViewpoint(cVector3(0.0, -1.0, 2.0), _border.center());
			//Direction to viewer is down a bit, and back off less than that.
		pviewer->zoom(4.0);
	}
	else //2D case.
	{
		pviewer->setViewpoint(cVector::ZAXIS, _border.center());
		pviewer->zoom(2.0);
	}
}

CString cGameMyProject::statusMessage()
{
	CString cStrStatusBar = cGame::statusMessage(); //Get the standard message
		//Add to it or change it.
	return cStrStatusBar;
}

void cGameMyProject::adjustGameParameters()
{
// (1) End the game if the player is dead
	if (!health()  && !_gameover) //Player's been killed and game's not over.
	{
		_gameover = TRUE;
		pplayer()->addScore(_scorecorrection); // So user can reach _maxscore 
		playSound("Tada");
		return; 
	}
// (2) Perhaps do this to reseed the screen if rivals and props are gone.
	int othercrittercount = pbiota()->count(RUNTIME_CLASS(cCritter)) -
		pbiota()->count(RUNTIME_CLASS(cCritterBullet)) - 1;
		//Number of critters minus bullets minus player equals other critters.
	if (!othercrittercount) //Player is alone with bullets
		seedCritters();
// (3) Maybe check some other conditions.
	/* You might for instance have something like this:
	if (_level == 1 && score() > 100)
	{
		_level = 2;
		//Possibly delete some critters added in the constructor.
		seedCritters();
	}
	*/
}

void cGameMyProject::Serialize(CArchive& ar)
{
	cGame::Serialize(ar);
	if (ar.IsStoring()) // Save any extra variables
		ar << _rivalcount ; //Line of form ar << ...
	else //Load any extra variables 
		ar >> _rivalcount; //Line of form ar >> ...
}

//====================cCritterMyProjectPlayer
cCritterMyProjectPlayer::cCritterMyProjectPlayer(cGame *pownergame):
cCritterArmedPlayer(pownergame)
{
		//Set the listener
	setListener(new cListenerScooter());
		//Set the bullet
 	setBulletClass(RUNTIME_CLASS(cCritterMyProjectPlayerBullet));
	//setWaitShoot(2.0*cCritterArmed::WAITSHOOT); //Don't shoot as fast as usual.
		//Set other variables, perhaps including sprite.
	setHealth(cGameMyProject::PLAYERHEALTH);
		/* Maybe add some forces like gravity; the player will ignore them, but the
			bullets it shoots will use them. */
	setMaxspeed(1.3*cCritterBulletSilverMissile::MAXSPEED); //So you can catch them.
}

void cCritterMyProjectPlayer::reset()
{
	cCritterArmedPlayer::reset();
		//Perhaps use setHealth to restore the health to a high value.
	setHealth(cGameMyProject::PLAYERHEALTH);
}

BOOL cCritterMyProjectPlayer::collide(cCritter *pcritter)
{
	BOOL collideflag = cCritter::collide(pcritter);
		/* May sometimes do more stuff here if collideflag is TRUE.  In the code
		below, for instance, we have the player "eat" cCritterMyProjectProp critters, that is,
		increasing the cCritterMyProjectPlayerown health and killing the cCritterMyProjectProp
		when they touch. If you don't want this behavior take these lines out. */
	if (collideflag && pcritter->IsKindOf(RUNTIME_CLASS(cCritterMyProjectProp)))
	{
		setHealth(health() + 1);
		playSound("Ding");
		pcritter->die();
	}
	return collideflag;
}

void cCritterMyProjectPlayer::update(CPopView *pactiveview, Real dt)
{
	cCritterArmedPlayer::update(pactiveview, dt);//Always call this first
}

int cCritterMyProjectPlayer::damage(int hitstrength)
{
	int damagereward = cCritterArmedPlayer::damage(hitstrength); //Default bevavior.
	//Maybe change the sprite or something as well.
	return damagereward;
}

cCritterBullet* cCritterMyProjectPlayer::shoot()
{
	return cCritterArmedPlayer::shoot();
}

//====================cCritterMyProjectPlayerBullet==================
cCritterMyProjectPlayerBullet::cCritterMyProjectPlayerBullet()
{
		/* The default constructor will do enough, but you 
		can override the default triangle sprite and size here. */
	//setSprite(pgame()->randomSprite(cGame::ST_POLYPOLYGONS)); 
	setRadius(2.0*cCritter::BULLETRADIUS); //Make bigger than usual.
}

void cCritterMyProjectPlayerBullet::update(CPopView *pactiveview, Real dt)
{
	cCritterBullet::update(pactiveview, dt); //Always call base update first
}

//==================== cCritterMyProjectProp ====================

cCritterMyProjectProp::cCritterMyProjectProp(cGame *pownergame):
cCritter(pownergame)
{
		//Set the health and value.  Make a sprite and use setSprite to install it.
		//For instance you might use a random sprite.
	if (pgame())
		setSprite(pgame()->randomSprite(pgame()->spritetype())); 
	else
		setSprite(pgame()->randomSprite(cGame::ST_BUBBLES)); 
		//Randomize psotion velocity if you like.
	randomize(cCritter::MF_POSITION | MF_VELOCITY);
		//Set a particular radius if you like.
	setRadius(0.5);
		//Add some forces
	BOOL clockwise = _personality & 1; /* Use a random bit to decide whether
		to circle clockwise or counterclockwise. */
	addForce(new cForceVortex(0.3, clockwise?-PI/2.0:PI/2.0, cVector::ZEROVECTOR));
		//circle around the center of the world.
	if (pgame())
		addForce( new cForceObjectSeek(pgame()->pplayer(), -0.1)); 
		//Weakly Avoid the player.
}

int cCritterMyProjectProp::damage(int hitstrength)
{
	int damagereward = cCritter::damage(hitstrength); //Default bevavior.
	//Maybe change the sprite or something as well.
	return damagereward;
}

BOOL cCritterMyProjectProp::collide(cCritter *pcritter)
{
	BOOL collideflag = cCritter::collide(pcritter);
		//May sometimes do more stuff here if collideflag is TRUE.
	return collideflag;
}

void cCritterMyProjectProp::update(CPopView *pactiveview, Real dt)
{
	cCritter::update(pactiveview, dt); //Always call this first
}

//==================== cCritterMyProjectRival ====================

cCritterMyProjectRival::cCritterMyProjectRival(cGame *pownergame):
cCritterArmedRobot(pownergame)
{
	setWrapflag(cCritter::WRAP);
		//Set the health and value. 
		// Make a sprite and use setSprite to install it.
	if (pgame())
	{
		setSprite(pgame()->randomSprite(cGame::ST_BITMAPS)); 
		//Choose randomly among available bitmaps
	//	setSprite(new cSpriteIcon(IDB_FACE)); //Or you could use a specific bitmap.
		//Always set target for cCritterArmedRobot
		setTarget(pplayer()); //Makes it automatically aim at pplayer.
	}
		//Set the bullet
 	setBulletClass(RUNTIME_CLASS(cCritterMyProjectRivalBullet));
		//Set wait time between shots
	setWaitShoot(10.0); //Seconds between shots fired.
	//setGunlength(0.0);//Erase the "ugly" gun line from these if you like
		// COMMENT NEXT LINE OUT TO TURN SHOOTING ON.
	//setArmed(FALSE); //TURN OFF THE SHOOTING.
	randomize(cSprite::MF_RADIUS);// Randomize size if you like.
	randomize(cCritter::MF_POSITION | MF_VELOCITY);
		//Add some forces
	addForce(new cForceClassEvade(7.0, 1.5, 
		RUNTIME_CLASS(cCritterMyProjectPlayerBullet)));
	if (pgame()) //Then we know we added this to a game so pplayer() is valid
 		addForce(new cForceObjectSeek(pplayer(), 0.3));
 }

int cCritterMyProjectRival::damage(int hitstrength)
{
	int damagereward = cCritter::damage(hitstrength); //Default bevavior.
	//Maybe change the sprite or something as well.
	return damagereward;
}	

BOOL cCritterMyProjectRival::collide(cCritter *pcritter)
{
	BOOL collideflag = cCritter::collide(pcritter);
		//May sometimes do more stuff here if collideflag is TRUE.
	return collideflag;
}

void cCritterMyProjectRival::update(CPopView *pactiveview, Real dt)
{
	cCritterArmedRobot::update(pactiveview, dt);//Always call this first
}

//====================cCritterMyProjectRivalBullet==================
cCritterMyProjectRivalBullet::cCritterMyProjectRivalBullet()
{
//	setSprite(new cSpriteBubblePie()); //Maybe use bubbles for fun.
//	randomize(cPolygon::MF_COLOR); //randomize color of sprite.
//	_dieatedges = FALSE; //Include this in case you want the bullet to wrap around
	setRadius(2.0*cCritter::BULLETRADIUS);
}

void cCritterMyProjectRivalBullet::initialize(cCritterArmed *pshooter)
{
	cCritterBullet::initialize(pshooter);
	addForce( new cForceObjectSeek(ptarget(), 10.0)); 
//	setRadius(0.5 * pshooter->radius()); //Make bullet size depend on shooter, don't have to do this.
//	setWrapflag(cCritter::WRAP);
}

