// Gameballworld.cpp: implementation of the GameBallworld class and associated classes.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "gameballworld.h"
#include "force.h"
#include "listener.h"
#include "pop.h" //for playSound
#include "spritepolygon.h" 
#include "critterviewer.h"
#include "graphicsopengl.h"
#include "graphicsmfc.h"

IMPLEMENT_SERIAL( cGameBallworld, cGame, 0);
IMPLEMENT_SERIAL( cCritterBallProp, cCritter, 0);
IMPLEMENT_SERIAL( cCritterBallworldPlayer, cCritterArmedPlayer, 0);
IMPLEMENT_SERIAL( cCritterTreasure, cCritter, 0);
IMPLEMENT_SERIAL( cCritterBallWall, cCritterWall, 0);

#define HANDSETVIEWERPOS
	/* HANDSETVIEWERPOS turns on the option of hand setting the viewer pos in 
the InitializeViewer call.  It's more standard to comment this out, but I had some
lingering problems with the default approach for a long thin world, so now I'm preferring
the HANDSETVIEWERPOS optoin. The other way WORKS, but I don't TRUST it anymore for this
paritcualr world as I have so often seen it arbitrarily put my view BEHIND the world 
(negative z), though this coudl have been due to some cCritterViewer trackplayer code
thats' been recently revised.  So you can probably comment out HANDSETVIEWERPOS.*/

//==============================cGameBallworld=======
Real cGameBallworld::TREASURERADIUS = 1.0;
Real cGameBallworld::WALLTHICKNESS = 1.0;
Real cGameBallworld::LEVELTIMER = 99.0;

cGameBallworld::cGameBallworld()
{

//Fix the menu selections you'll allow.
	_menuflags &= ~cGame::MENU_BOUNCEWRAP; 
		/* Default _menuflags from cGame has autoplay off, hopper off. 
		Turn off wrap because it's bad with gravity, we want balls bouncing on bottom.*/
//	_menuflags &= ~cGame::MENU_3D; 
		/* Turn off 3D option because it's bad with the long thin background bitmap
		called IDB_STREET.  Other than that, though, 3D is ok for this game. */
	_menuflags &= ~cGame::MENU_TRACKPLAYER;
		/* Don't allow user to turn off the track player option. */ 
	_menuflags &= ~cGame::MENU_RIDEPLAYER;
		/* Don't ride the player */
	_menuflags |= cGame::MENU_HOPPER; //Turn on hopper listener option.
	_menuflags &= ~cGame::MENU_CHANGELISTENER; 
		/* It looks bad to use any listener other than hopper. */
	_spritetype = cGame::ST_BUBBLES;
	_border.set(150.0, 20.0, 0.0); //Use a long, thin world.
	//setBackgroundBitmap(IDB_STREET); 
		/*  Sets the cSpriteBackground for the desired 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. */
	setWrapflag(cCritter::BOUNCE);
	_seedcount = 7; 
	setPlayer(new cCritterBallworldPlayer(this));
	//_arrayHCURSOR has only the _hCursorArrow inherited from cGame.
	//_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorPlay); //No need for the shoot cursor

	// Initial level is 0.
	_cur_level = -1;

	_numLevels = 3;
	_levels = new _level[_numLevels];

	// this is high importance.
	gameStarted = false;

	_last_level = 1;

	_levels[0].init(11, 13, 9, 100, 50, IDB_LEVEL1);

	_levels[0].addEnemy(-54, 0.0, 2.0, 5.0, true, 2.0, IDB_CLOUD);
	_levels[0].addEnemy(-57, -5, 3.0, 3.0, false, 2.0, IDB_ITR);
	_levels[0].addEnemy(-50, -6, 2.5, 2.5, false, 2.0, IDB_ITR);
	_levels[0].addEnemy(-10, 0.0, 2.0, 2.0, true, 2.0, IDB_CLOUD);
	_levels[0].addEnemy(-33.5, 5, 5.7, 2.0, false, 0, IDB_FOOTBALL);
	_levels[0].addEnemy(27, 0.0, 4.0, 4.0, true, 2.0, IDB_CLOUD);
	_levels[0].addEnemy(19, -1, 4, 4, false, 2.0, IDB_ITR);
	_levels[0].addEnemy(-25, 4, 3.0, 2.0, false, 2.0, IDB_ITR);
	_levels[0].addEnemy(35, -9, 0, 0, false, 0, IDB_FOOTBALL);
	_levels[0].addEnemy(40, -9, 0, 0, false, 0, IDB_FOOTBALL);
	_levels[0].addEnemy(42, 0, 5, 5, true, 2.0, IDB_CLOUD);


	_levels[0].addWall(-60, -10, -54, -7);
	_levels[0].addWall(-54, -10, -47, -8);

	_levels[0].addWall(-49, 0, -40, 1);

	_levels[0].addWall(-35, 4, -32, 5);
	_levels[0].addWall(-58, 2, -55, 3.5);
	_levels[0].addWall(-22, -4, -19, -3);
	_levels[0].addWall(-30, -1, -27, 0);
	_levels[0].addWall(-17, 0, -14, 1);

	_levels[0].addWall(-5, -5, 0, -4);
	_levels[0].addWall(1, -3, 6, -2);

	_levels[0].addWall(10, 1, 25, 3);
	_levels[0].addWall(10, -5, 25, -3);
	_levels[0].addWall(29, -1, 39, 0);

	_levels[0].addGoodie(-47, 2, 0, 1);
	_levels[0].addGoodie(-45, 2, 1, 0);
	_levels[0].addGoodie(-43, 2, 0, 1);
	_levels[0].addGoodie(-41, 2, 1, 0);

	_levels[0].addGoodie(-28.5, 1, 1, 0);
	_levels[0].addGoodie(-20.5, -2, 1, 0);
	_levels[0].addGoodie(-56.5, 6, 1, 0);

	_levels[0].addGoodie(-15.5, 2, 1, 0);

	_levels[0].addGoodie(-28.5, 1, 1, 0);


	_levels[1].init(2, 0, 0, 200, 40, IDB_LEVEL2);
	_levels[1].addEnemy(-5,0, 0, 0, false, 0, IDB_FOOTBALL);
	_levels[1].addEnemy(-11, 0, 0, 0, false, 0, IDB_FOOTBALL);

	_levels[2].init(2, 4, 0, 300, 30, IDB_LEVEL3);
	_levels[2].addEnemy(-5,0, 0, 0, false, -5, IDB_ITR);
	_levels[2].addEnemy(-11, 0, 0, 0, false, -5, IDB_ITR);
	_levels[2].addEnemy(-1, 0.0, 2.0, 2.0, true, 2.0, IDB_CLOUD);

	_levels[2].addWall(-4, 1, 0, 0);
	_levels[2].addWall(4, -7, 1, -4);
	_levels[2].addWall(-20, -7, -18, -5);
	_levels[2].addWall(20, -7.5, 22, -3);


	//Put in some walls in the constructor.
#ifndef DEBUGDAM
	

#else //DEBUGDAM is true
	_seedcount = 0;
#endif //DEBUGDAM
}

void cGameBallworld::initializeView(CPopView *pview)
{
	cGame::initializeView(pview);
	pview->setUseBackgroundBitmap(TRUE);
//	pview->setGraphicsClass(RUNTIME_CLASS(cGraphicsOpenGL)); //Comment this in for a 3D start
	pview->pviewpointcritter()->setTrackplayer(TRUE); //Always look at the player.
	pview->pviewpointcritter()->setFoveaProportion(0.45); /* A critterviewer has a _foveaproortion
		that ranges from 0.0 to 1.0.  We make it smaller than the default value of 0.85 so
		that the trackplayer image will scroll before player gets all the way to edge. 
		Reduce still more if you want to scroll even sooner.*/
}

void cGameBallworld::initializeViewpoint(cCritterViewer *pviewer)
{
	if (pviewer->is3D())
	{
#ifdef HANDSETVIEWERPOS
		pviewer->setViewpoint(cVector3(0.0, -8.0, 40.0), 
			cVector(border().lox(), border().midy()),
			FALSE);  
			/* The setViewpoint args are (directiontoviewer, lookatpoint, trytoseewholeworld),
			the default third argument is TRUE, which means to back off enough to
			see the whole world.  But in a long thin world, we don't want to do that.  */
#else //HANDSETVIEWERPOS
		pviewer->setViewpoint(cVector3(0.0, -0.2, 1.0), 
			cVector(border().lox(), border().midy()));  /* the default third TRUE argument
			will move the viewpoint far from the world and try to see it all. */
		pviewer->zoom(7.0); /* The bigger the world and the further away you are, 
			the more zoom you need. */
		/* I don't like this way as it makes the player trackign a little flaky to be in a
		high zoom. */
#endif //HANDSETVIEWERPOS
	}
	else //2D case
	{
		pviewer->setViewpoint(cVector::ZAXIS, //pplayer()->position());
			cVector(border().lox(), border().midy()));
		pviewer->zoom(4.0);
	}
}

void cGameBallworld::seedCritters()
{
	pbiota()->purgeCritters(RUNTIME_CLASS(cCritterBullet));
	pbiota()->purgeCritters(RUNTIME_CLASS(cCritterBallProp));
	//for (int i=0; i<_seedcount; i++)
	//	new cCritterBallProp(this);

	gotoNextLevel(pplayer());

	pplayer()->moveTo(border().locorner());
}

void cGameBallworld::adjustGameParameters()
{
// (1) End the game if the player is dead
	if (!health()  && !_gameover) //Player's been killed and game's not over.
	{
		//_gameover = TRUE;
		if ((--((cCritterBallworldPlayer*)pplayer())->livesLeft) == 0)
		{
			CString timeMsg;
			timeMsg.Format("You were knocked unconscious and ITRed.");
			AfxMessageBox(timeMsg, MB_OK | MB_ICONINFORMATION);
			exit(0);
		}
		else
		{
			CString timeMsg;
			timeMsg.Format("Never going to make it to the Libra Complex this way. Try again!\nYou have %d lives left.", ((cCritterBallworldPlayer*)pplayer())->livesLeft);
			pplayer()->setHealth(10);
			AfxMessageBox(timeMsg, MB_OK | MB_ICONINFORMATION);
		}
		pplayer()->addScore(_scorecorrection); // So user can reach _maxscore 
		playSound("Tada");
		return; 
	}
// (2) Also don't let the ballcount diminish.
			//(need to recheck propcount in case we just called seedCritters).
	int ballcount = pbiota()->count(RUNTIME_CLASS(cCritterBallProp));
	int ballstoadd = _seedcount - ballcount;
 	//for (int i=0; i < ballstoadd; i++)
	//	new cCritterBallProp(this);
// (3) Maybe check some other conditions.

	if ((int)(cGameBallworld::LEVELTIMER - age()) <= 0 && !_gameover)
	{
		//_gameover = TRUE;
		CString timeMsg;
		timeMsg.Format("Ooops!  You ran out of time.  ITR Games are going to start without you, loser.");
		AfxMessageBox(timeMsg, MB_OK | MB_ICONINFORMATION);
		exit(0);
		return;
	}

	// if not moving in either direction
	if (pplayer()->velocity().x() == 0.0 &&
		pplayer()->velocity().y() == 0.0)
	{
		//pplayer()->setFacing(!pplayer()->facing());
		if (pplayer()->facing())
			pplayer()->setSprite(new cSpriteIcon(IDB_NSTANDL));
		else
			pplayer()->setSprite(new cSpriteIcon(IDB_NSTAND));
		pplayer()->setRadius(1.5);
	}

	if (pplayer()->velocity().y() < 0.0)
	{
		//if (pplayer()->facing())
		//	pplayer()->setSprite(new cSpriteIcon(IDB_NSTANDL));
		//else
		//	pplayer()->setSprite(new cSpriteIcon(IDB_NSTAND));
		pplayer()->setRadius(1.5);
	}

	// End level
	if (pplayer()->position().x() > border().hix() - 2.5)
		gotoNextLevel(pplayer());

/*
	if ( (int)(age() - ( (cCritterBallworldPlayer*) pplayer())->lasthit()) < 5)
	{
		( (cCritterBallworldPlayer*) pplayer())->setInvincible(
			( (cCritterBallworldPlayer*) pplayer())->invincible() - 1
			);
	}
	else
	{
		( (cCritterBallworldPlayer*) pplayer())->setInvincible(0);
	}
	*/
 }

CString cGameBallworld::statusMessage()
{
	CString cStrStatusBar;
	int nUpdatesPerSecond;
	CString cStrUpdatespersecond;
	CString cStrCount;
	CString cStrScore;
	CString cStrHealth;
	CString cStrTimer;
	CString cStrLevel;
	CString cStrLives;

	if (!gamepaused())
	{
		nUpdatesPerSecond = int(((CPopApp*)::AfxGetApp())->_timer.updatesPerSecond());
		if (!nUpdatesPerSecond)
			cStrUpdatespersecond.Format("Less than one update per second.");
		else	
			cStrUpdatespersecond.Format("Updates per second: %d.", nUpdatesPerSecond);
		if (((CPopApp*)::AfxGetApp())->_timer.runningNearMinSpeed())
			cStrUpdatespersecond += " (Slower than Real Time)";
	}
	else
			cStrUpdatespersecond.Format("Animation is paused.");
	cStrLives.Format("Lives: %d.", ((cCritterBallworldPlayer*)pplayer())->livesLeft);
	cStrScore.Format("Score: %d.", score());
	cStrHealth.Format("Health: %d.", health());
	cStrTimer.Format("Timer: %d.", (int)(cGameBallworld::LEVELTIMER - age()));
	cStrLevel.Format("Level: %d.", _cur_level+1, _last_level+1);
	int crittercount = _pbiota->count(RUNTIME_CLASS(cCritter));
	int bulletcount = _pbiota->count(RUNTIME_CLASS(cCritterBullet));
	cStrCount.Format("Ball Critters: %d.", crittercount-bulletcount-2); //Subtract two for player and treasure
	cStrStatusBar = cStrLevel + " " + cStrLives + " " + cStrHealth + " " + cStrTimer + " " + cStrScore + " "+ cStrCount + "  " + cStrUpdatespersecond; 
	return cStrStatusBar;
}

void cGameBallworld::Serialize(CArchive& ar) /* This is a bit of work, as I have to match
	_ppuck , _phockeyrobot , _pmygoal , _probotgoal to the pointers in the cBiota array. */
{
	int treasureindex;
	cGame::Serialize(ar);
	if (ar.IsStoring()) // Save 
 	{
		ar << _index(_ptreasure);
	}
	else //Load
	{
		ar >> treasureindex;
			// I have to cast from cCritter*
		_ptreasure = (cCritterTreasure*)(_pbiota->GetAt(treasureindex));
	}
}

void cGameBallworld::gotoNextLevel(cCritter* player)
{
	// resetting health
	if (player->health() < 10)
	{
		player->setHealth(10);
	}

	// Save the last level and increment the counter.
	_last_level = _cur_level;
	++_cur_level;

	setBackgroundBitmap(_levels[_cur_level]._bgbmp);

	// If the game has been in progress for at least one level,
	// give a score bonus.  (This is so that score bonus is calculated
	// at the last level, before we restart to level 0).
	if (gameStarted)
		player->addScore(_levels[_last_level]._scoreBonus);

	// Reset the level counter at the last level.
	if (_cur_level >= _numLevels)
	{
		playSound("Tada");
		CString winMsg;
		winMsg.Format("You win!  Your total score is %d", score());
		AfxMessageBox(winMsg, MB_OK | MB_ICONINFORMATION);
		exit(0);
		_cur_level = 0;
	}

	// Set the timer.
	cGameBallworld::LEVELTIMER = _levels[_cur_level]._timeLimit;

	// If the game has been in progress for at least one level,
	// remove the old critters.
	if (gameStarted)
	{
		cGameBallworld::LEVELTIMER += .2 * (_levels[_last_level]._timeLimit - age());
		pplayer()->setAge(0);

		for (int i = 0; i < _levels[_last_level]._numWalls; ++i)
		{
			_theseWalls[i]->setCorners( cVector2(0,0), cVector2(0,0) );
		//	((cCritter*) _theseWalls[i])->die();
		}

		for (int i = 0; i < _levels[_last_level]._numEnemies; ++i)
		{
			if (_theseEnemyIDs[i])
			{
				_theseEnemies[i]->die();
			}
		}

		for (int i = 0; i < _levels[_last_level]._numGoodies; ++i)
		{
			if (_theseGoodyIDs[i])
			{
				_theseGoodies[i]->die();
			}
		}

		delete [] _theseEnemyIDs;
		delete [] _theseGoodyIDs;

		delete [] _theseEnemies;
		delete [] _theseWalls;
		delete [] _theseGoodies;
	}

	gameStarted = true;
	player->moveTo(this->border().locorner());

	_theseEnemyIDs  = new bool             [_levels[_cur_level]._numEnemies];
	_theseGoodyIDs  = new bool             [_levels[_cur_level]._numGoodies];
	_theseEnemies   = new cCritterBallProp*[_levels[_cur_level]._numEnemies];
	_theseWalls     = new cCritterBallWall*[_levels[_cur_level]._numWalls];
	_theseGoodies   = new cCritterTreasure*[_levels[_cur_level]._numGoodies];
	


	// create all the lovely enemies.
	for (int i = 0; i < _levels[_cur_level]._numEnemies; ++i)
	{
		cCritterBallProp* enemy;
		if (!(_levels[_cur_level]._enemies+i)->isFlying)
			enemy = new cCritterBallProp(this, 
										(_levels[_cur_level]._enemies+i)->getVector().x() - 
											(_levels[_cur_level]._enemies+i)->lrange,
										(_levels[_cur_level]._enemies+i)->getVector().x() + 
											(_levels[_cur_level]._enemies+i)->rrange,
										(_levels[_cur_level]._enemies+i)->isFlying,
										(_levels[_cur_level]._enemies+i)->initVel,
										(_levels[_cur_level]._enemies+i)->pic, i);
		else
			enemy = new cCritterBallProp(this, 
										(_levels[_cur_level]._enemies+i)->getVector().y() - 
											(_levels[_cur_level]._enemies+i)->lrange,
										(_levels[_cur_level]._enemies+i)->getVector().y() + 
											(_levels[_cur_level]._enemies+i)->rrange,
										(_levels[_cur_level]._enemies+i)->isFlying,
										(_levels[_cur_level]._enemies+i)->initVel,
										(_levels[_cur_level]._enemies+i)->pic, i);
		
		enemy->moveTo( (_levels[_cur_level]._enemies + i)->getVector() );
		_theseEnemies[i]  = enemy;
		_theseEnemyIDs[i] = true;
	}

	// create all the lovely walls.
	for (int i = 0; i < _levels[_cur_level]._numWalls; ++i)
	{
		cCritterBallWall* wall;

		wall = new cCritterBallWall( (_levels[_cur_level]._walls+i)->getUpperVector() , (_levels[_cur_level]._walls+i)->getLowerVector(), 0, this);
		_theseWalls[i] = wall;


	}


	//new cCritterTreasure( this, -12, 0, 1, 0);
	//new cCritterTreasure( this, -10, 0, 0, 1);

	// create all the goodies.
	for (int i = 0; i < _levels[_cur_level]._numGoodies; ++i)
	{
		cCritterTreasure* goody = new cCritterTreasure(  this, 
							   (_levels[_cur_level]._goodies+i)->_x, 
							   (_levels[_cur_level]._goodies+i)->_y, 
							   (_levels[_cur_level]._goodies+i)->_health,
							   (_levels[_cur_level]._goodies+i)->_score,
							   i
							);

		
		_theseGoodies[i]  = goody;
		_theseGoodyIDs[i] = true;
	}

		


}

//====================Critters for the Ballworld Game ==========================
//==================================================================


//==================cCritterBallworldPlayer=============

cCritterBallworldPlayer::cCritterBallworldPlayer(cGame *pownergame):
cCritterArmedPlayer(pownergame)
{
	livesLeft = 2;
	setFacing(false);
	setSprite(new cSpriteIcon(IDB_NSTAND));
	setHealth(10);
	moveTo(_movebox.locorner());
	setWrapflag(cCritter::CLAMP); //Use CLAMP so you stop dead at edges.
	setArmed(TRUE);  //Let's use bullets.
	setMaxspeed(40.0); //Need good speed to overcome gravity.
	setListener(new cListenerHopper(8.0, 0.25, 0.5)); /* The three arguments to the
		cListenerHopper constructor specify the walkspeed, the hopuptime, and the hopagainwait.
		Walkspeed is how fast the left/right (and PgUp/PgDn if in 3D where the ground is xz plane)
			arrow keys move the critter,
		Hopuptime is how many seconds you can accelerate up with the UP arrow, and
		Hopupwait is how many seconds you have to wait after the end of one hop
			before starting a new hop. */
	setListenerAcceleration(160.0); //So Hopper can overcome gravity
	addForce(new cForceGravity(50.0)); /* Uses  gravity. Default strength is 25.0.
		Gravity	will affect player using cListenerHopper. */
//	addForce(new cForceDrag(0.5)); //Better without friction.
//	setDensity(8.0 * density()); //To make it fall faster, but we don't need this.
	setRadius(1.5); //Default cCritter::PLAYERRADIUS is 0.4. 
	setAttitudeToMotionLock(FALSE);  //It looks nicer if you don't turn the player with motion.
	setAttitudeTangent(cVector::XAXIS); /* Without motion lock, we need setAttitudeTangent 
		to make sure he's pointing up at the start. */
}

BOOL cCritterBallworldPlayer::collide(cCritter *pcritter)
{	
	BOOL collided = cCritter::collide(pcritter);
	if (!collided)
		return FALSE;
/* If you're here, you collided.  We'll treat all the guys the same -- the collision
 with a Treasure is different, but we let the Treasure contol that collision. */
	if ((pgame()->age() - lasthit()) > (Real)1.0)
	{
		damage(1);
		setLasthit(pgame()->age());
	}
	pcritter->die();
	return TRUE;
}



//==================cCritterBallProp=============

cCritterBallProp::cCritterBallProp(cGame *pownergame):
cCritterArmedRobot(pownergame),
dead(false)
{
	if (pgame())
		setSprite(pgame()->randomSprite(pgame()->spritetype()));
	addForce(new cForceGravity(25.0, cVector( 0.0, -1, 0.0))); /* Make the
		gravity tilt towards the left to move them along. */
	addForce(new cForceDrag()); //Uses default friction strength 0.5.
	setDensity(2.0); 
	// Enemies won't bounce.
	setBounciness(0.0);
	setMaxspeed(20.0);
   	randomize(cCritter::MF_VELOCITY | cSprite::MF_RADIUS);
	setMinTwitchThresholdSpeed(4.0); //Means sprite doesn't switch direction unless it's moving fast
	Real playerx = 0.0;
	if (pownergame)
		playerx = pownergame->pplayer()->position().x();
	randomizePosition(cRealBox(cVector(playerx + 3.0,_movebox.loy()),
		_movebox.hicorner())); 
		/* I put them to the right of the player  */
}

void cCritterBallProp::die()
{
	pplayer()->addScore(value());
	( (cGameBallworld*) pgame())->_theseEnemyIDs[id] = false;
	dead = true;
	cCritter::die();
}

void cCritterBallProp::update(CPopView *pactiveview, Real dt)
{
	cCritterArmedRobot::update(pactiveview, dt); //Always call this first
	if (_outcode & BOX_LOX) /* use bitwise AND to check if a flag is set. */
		delete_me(); //tell the game to remove yourself

	if (isFlying)
	{
		if (position().y() < left_range)
		{
			setVelocity(cVector(velocity().x(), -(velocity().y())));
			moveTo(cVector(position().x(), left_range));
		}
		else if (position().y() > right_range)
		{
			setVelocity(cVector(velocity().x(), -(velocity().y())));
			moveTo(cVector(position().x(), right_range));
		}
	}
	else
	{
		if (position().x() < left_range)
		{
			setVelocity(cVector(-(velocity().x()), velocity().y()));
			moveTo(cVector(left_range, position().y()));
		}
		else if (position().x() > right_range)
		{
			setVelocity(cVector(-(velocity().x()), velocity().y()));
			moveTo(cVector(right_range, position().y()));
		}
	}
}

// functions we've added
cCritterBallProp::cCritterBallProp(cGame *pownergame, Real _left_range, Real _right_range, bool _isFlying, Real init_velocity, int _pic, int id):
cCritterArmedRobot(pownergame),
dead(false),
left_range(_left_range),
right_range(_right_range),
isFlying(_isFlying),
pic(_pic),
id(id)
{
	if (pgame())
	{
		setSprite(new cSpriteIcon(pic));
		setRadius(1.5);
		this->badtype = pic;
	}
	if (!isFlying)
		addForce(new cForceGravity(25.0, cVector( 0.0, -1, 0.0)));
	setDensity(2.0); 
	// Enemies won't bounce.
	setBounciness(0.0);
	setMaxspeed(20.0);
	setMinTwitchThresholdSpeed(4.0); //Means sprite doesn't switch direction unless it's moving fast
	
	// Set horizontal/vertical velocity depending on critter motion
	if (!isFlying)
		setVelocity(cVector(-init_velocity, 0.0));
	else
		setVelocity(cVector(0.0, -init_velocity));

	/* Gun stuff */
	// Only flying critters and non-moving critters shoot.
	if (isFlying || init_velocity == 0)
	{
		setBulletClass(RUNTIME_CLASS(cCritterBulletSilver));
		setWaitShoot(3);
		// Flying critters shoot at the player
		if (isFlying)
			setTarget(pplayer());
		else
			setAimVector(cVector(-1.0, 0.0)); // If not flying shoot forward
		makeServiceRequest("move_to_front");
	}
	else
	{
		// Moving dudes dont get to shoot.
		setArmed(false);
	}
}


//===================cCritterDamWall
cCritterBallWall::cCritterBallWall(const cVector &enda, const cVector &endb,
	 Real thickness, cGame *pownergame):
cCritterWall(enda, endb, thickness, pownergame)
{
	//Don't presently do anything else.  Could change color with a line like
	//psprite()->setFillColor(cColorStyle::CN_LIGHTYELLOW);
}

//==================cCritterTreasure=============

cCritterTreasure::cCritterTreasure(cGame *pownergame, Real xPosition, Real yPosition, int _health, int _score, int _id):
cCritter(pownergame), health(_health), score(_score), id(_id)
{
	_collidepriority = cCollider::CP_PLAYER + 1; /* Let this guy call collide on the
		player, as his method is overloaded in a special way. */
	/* Set sprite to health or score depending on which is set. */
	if (health >= score)
	{ 
		setSprite(new cSpriteIcon(IDB_HEALTH));
	}
	else
	{
		setSprite(new cSpriteIcon(IDB_TREASURE));
	}

	setRadius(0.7);
	setFixedflag(TRUE);
	moveTo(cVector(xPosition, yPosition));
}

int cCritterTreasure::collidesWith(cCritter *pothercritter)
{
	if (pothercritter->IsKindOf(RUNTIME_CLASS(cCritterBallworldPlayer)))
		return cCollider::COLLIDEASCALLER;
	else
		return cCollider::DONTCOLLIDE;
}

BOOL cCritterTreasure::collide(cCritter *pcritter)
{
	BOOL collided = cCritter::collide(pcritter);
	if (!collided)
		return FALSE;

	pplayer()->addScore(score);
	pplayer()->addHealth(health);
	/* Kill the treasure */
	this->die();
	return TRUE;
}

void cCritterTreasure::die()
{
	( (cGameBallworld*) pgame())->_theseGoodyIDs[id] = false;
	cCritter::die();
}
