/*
File: gameworms.cpp
Uploaded by richprillinger on Tue Nov 27 14:48:47 PST 2001
*/

/*
File: gameworms.cpp
Uploaded by richprillinger on Tue Nov 20 02:52:14 PST 2001
*/

// gameworms.cpp: implementation of the generic cGameWorms class.
//
// Cleaned up version 11/16/01 3am -Rich
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "gameworms.h"
#include "critterwall.h"				/* Lee 11-04-01 */
#include "listener.h"
#include "spriteicon.h"
#include "spritemultiicon.h"
#include "pop.h" //for playSound
#include "popview.h"
#include "force.h"
#include "spritebubble.h"

IMPLEMENT_SERIAL(cGameWorms, cGame, 0);
IMPLEMENT_SERIAL(cCritterMazeWall, cCritterWall, 0);	/* Lee 11-04-01 */
IMPLEMENT_SERIAL(cCritterWormsPlayer, cCritter, 0);		/* Lee 11-11-01 */
IMPLEMENT_SERIAL(cCritterPlayerWormsSeg, cCritter, 0);	/* Lee 11-11-01 */
IMPLEMENT_SERIAL(cCritterWormsSeg, cCritter, 0);		/* Lee 11-11-01 */
IMPLEMENT_SERIAL(cCritterWormsEnemyHead, cCritter, 0);	/* Lee 11-11-01 */
IMPLEMENT_SERIAL(cCritterWormsPlayerEgg, cCritter, 0 );
IMPLEMENT_SERIAL(cCritterWormsEnemyEgg, cCritter, 0 );
IMPLEMENT_SERIAL(cCritterWormsFood, cCritter, 0 );

//Defines
#define PLAYERSPRITELOOP
//#define NOWALLS
//#define NOEAT
#define NOEGG
//#define NOFOOD
	/* We have the option of havin the cCritterWormsPlayer either use
	an "animated" cSpriteLoop or use a directionally-sensitive cSpriteDirectional.
	Comment the #define PLAYERSPRITELOOP in for the cSpriteLoop,
	comment it out for the	cSpriteDirectional. */

//==============================cGameWorms
int cGameWorms::PLAYERHEALTH = 5; 
int cGameWorms::WORMCOUNT = 3; //1;		/* Lee added 11-04-01 */
static int randomLow = -4;				/* 11-12 Joe */
static int randomHigh = 4;				/* 11-12 Joe */
static int randomMinTime = 2;			/* min time in seconds before new animal 11-13  Joe */   
static int randomMaxTime = 6;			/* max time in seconds before new animal 11-13  Joe */
static int minFoodTime = 5;				/* min time between the creation of random food critter */
static int maxFoodTime = 10;			/* max time between the creation of random food critter */
static int worldWidth = 38.0;
static int worldHeight = 29.0;
static int playerLength = 3;

cGameWorms::cGameWorms(): //This constructor gets called only once, at first start.
	_rivalcount(3)
{
   // Setup the random amount of time until an animal is released /* 11-13 Joe  */
   // _timeTillNewAnimal = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );

//	_menuflags &= ~cGame::MENU_SHIELD; //We don't use the shield control in this game.

	//Usually we set _seedcount.
	_seedcount = 6; //The number of cCritterWormsSeg that I plan to add.

	// statics
	cCritter::MAXSPEED = 10.0;

	// cursor tools
	_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(worldWidth, worldHeight);

	//Set the backgroudn bitmap
	setBackgroundBitmap(IDB_GARDEN);

	//Set wrap with setWrapflag(cCritter::WRAP) or cCritter::BOUNCE.
	cCritterWall::THICKNESS = 0.4; /* Lee 11-04-01 */
	setWrapflag(cCritter::BOUNCE); /* Lee 11-04-01 */

	//Make a player   
   initiatePlayer(playerLength);	/* 11-5 Joe */

#ifndef NOWALLS
   initiateMap1();
#endif
}

void cGameWorms::initiateMap1()
{
#ifndef DEBUGWALL /* Lee added 11-04-01 */
	//psprite()->setFillColor(cColorStyle::CN_GREEN)
	//cCritterWall::WALLFILLCOLOR=cColorStyle::CN_WHITE;		// Rich
	add(new cCritterMazeWall( cVector(-16.5, 12),	cVector(-13.5, 12))); // 1 
	add(new cCritterMazeWall( cVector(-16.5, 12),	cVector(-16.5, 6))); // 2
	add(new cCritterMazeWall( cVector(-16.5, 3),	cVector(-13.5, 3))); // 3
	add(new cCritterMazeWall( cVector(-13.5, 3),	cVector(-13.5, 6))); // 4
	add(new cCritterMazeWall( cVector(-13.5, 6),	cVector(-10.5, 6))); // 5
	add(new cCritterMazeWall( cVector(-13.5, 9),	cVector(-10.5, 9))); // 6 
	add(new cCritterMazeWall( cVector(-10.5, 9),	cVector(-10.5, 12))); // 7
	add(new cCritterMazeWall( cVector(-10.5, 12),	cVector(-7.5, 12))); // 8
	add(new cCritterMazeWall( cVector(-7.5, 9),	cVector(-7.5, 3))); // 9
	add(new cCritterMazeWall( cVector(-7.5, 6),	cVector(-1.5, 6))); // 10
	add(new cCritterMazeWall( cVector(-4.5, 12),	cVector(-4.5, 9))); // 11 
	add(new cCritterMazeWall( cVector(-4.5, 9),	cVector(1.5, 9))); // 12
	add(new cCritterMazeWall( cVector(-1.5, 12),	cVector(4.5, 12))); // 13
	add(new cCritterMazeWall( cVector(-4.5, 3),	cVector(1.5, 3))); // 14
	add(new cCritterMazeWall( cVector(1.5, 3),	cVector(1.5, 0))); // 15
	add(new cCritterMazeWall( cVector(-1.5, 0),	cVector(-1.5, .4))); // 16 
	add(new cCritterMazeWall( cVector(-4.5, 0),	cVector(-4.5, -3))); // 17
	add(new cCritterMazeWall( cVector(-4.5, -3),	cVector(1.5, -3))); // 18
	add(new cCritterMazeWall( cVector(-7.5, 0),	cVector(-13.5, 0))); // 19
	add(new cCritterMazeWall( cVector(-10.5, 3),	cVector(-10.5, -3))); // 20
	add(new cCritterMazeWall( cVector(-16.5, 0),	cVector(-16.5, -6))); // 21 
	add(new cCritterMazeWall( cVector(-16.5, -3),	cVector(-13.5, -3))); // 22
	add(new cCritterMazeWall( cVector(-16.5, -9),	cVector(-10.5, -9))); // 23
	add(new cCritterMazeWall( cVector(-13.5, -9),	cVector(-13.5, -6))); // 24
	add(new cCritterMazeWall( cVector(-16.5, -12),	cVector(-13.5, -12))); // 25
	add(new cCritterMazeWall( cVector(-10.5, -12),	cVector(-7.5, -12))); // 26 
	add(new cCritterMazeWall( cVector(-7.5, -12),	cVector(-7.5, -9))); // 27
	add(new cCritterMazeWall( cVector(-10.5, -6),	cVector(-4.5, -6))); // 28
	add(new cCritterMazeWall( cVector(-7.5, -6),	cVector(-7.5, -3))); // 29
	add(new cCritterMazeWall( cVector(-1.5, -6),	cVector(-1.5, -9))); // 30
	add(new cCritterMazeWall( cVector(-1.5, -9),	cVector(-4.5, -9))); // 31 
	add(new cCritterMazeWall( cVector(-4.5, -9),	cVector(-4.5, -12))); // 32
	add(new cCritterMazeWall( cVector(-1.5, -12),	cVector(4.5, -12))); // 33
	add(new cCritterMazeWall( cVector(1.5, -12),	cVector(1.5, -6))); // 34
	add(new cCritterMazeWall( cVector(4.5, -9),	cVector(4.5, -8.6))); // 35
	add(new cCritterMazeWall( cVector(7.5, -12),	cVector(16.5, -12))); // 36 
	add(new cCritterMazeWall( cVector(10.5, -12),	cVector(10.5, -9))); // 37
	add(new cCritterMazeWall( cVector(7.5, -9),	cVector(7.5, -3))); // 38
	add(new cCritterMazeWall( cVector(13.5, -9),	cVector(16.5, -9))); // 39
	add(new cCritterMazeWall( cVector(13.5, -6),	cVector(16.5, -6))); // 40
	add(new cCritterMazeWall( cVector(16.5, -6),	cVector(16.5, -3))); // 41 
	add(new cCritterMazeWall( cVector(10.5, -3),	cVector(13.5, -3))); // 42
	add(new cCritterMazeWall( cVector(13.5, -3),	cVector(13.5, 0))); // 43
	add(new cCritterMazeWall( cVector(13.5, 0),	cVector(16.5, 0))); // 44
	add(new cCritterMazeWall( cVector(4.5, -3),	cVector(4.5, 0))); // 45
	add(new cCritterMazeWall( cVector(4.5, 0),	cVector(7.5, 0))); // 46 
	add(new cCritterMazeWall( cVector(7.5, 0),	cVector(7.5, 3))); // 47
	add(new cCritterMazeWall( cVector(10.5, 0),	cVector(10.5, 3))); // 48
	add(new cCritterMazeWall( cVector(10.5, 3),	cVector(16.5, 3))); // 49
	add(new cCritterMazeWall( cVector(10.5, 6),	cVector(16.5, 6))); // 50
	add(new cCritterMazeWall( cVector(13.5, 6),	cVector(13.5, 9))); // 51 
	add(new cCritterMazeWall( cVector(16.5, 9),	cVector(16.5, 12))); // 52
	add(new cCritterMazeWall( cVector(16.5, 12),	cVector(10.5, 12))); // 53
	add(new cCritterMazeWall( cVector(10.5, 9),	cVector(7.5, 9))); // 54
	add(new cCritterMazeWall( cVector(7.5, 9),	cVector(7.5, 12))); // 55
	add(new cCritterMazeWall( cVector(7.5, 6),	cVector(1.5, 6))); // 56 
	add(new cCritterMazeWall( cVector(4.5, 9),	cVector(4.5, 3)));	// 57
	add(new cCritterMazeWall( cVector(4.5, -6),	cVector(10.5, -6))); // 58
#else					/* Lee 11-04-01 */
		//_seedcount=0; /* Lee 11-04-01 */
#endif	//DEBUGWALL		/* Lee 11-04-01 */
}

void cGameWorms::seedCritters()
{
	pbiota()->purgeNonPlayerNonWallCritters(); 
  
	cCritterWormsBase * pprop_prior;	/* This is a special trick for the
										follow-the-leader thing we'll set up in 
										the next loop.  Not standard. */   

	Real randomX;        /* 11-12 Joe */
	Real randomY;        /* 11-12 Joe */

	for (int k=0; k < cGameWorms::WORMCOUNT; k++)
	{
      cCritterWormsSnake * snake = new cCritterWormsSnake( this, _seedcount - 1 );	/* 11-12 Joe  SnakeClass*/

      randomX = cRandomizer::pinstance()->randomReal( randomLow, randomHigh );		/* 11-12 Joe */
      randomY = cRandomizer::pinstance()->randomReal( randomLow, randomHigh );		/* 11-12 Joe */

		for (int i = 0; i < _seedcount - 1; i++)           /* 11-5 Joe */
		// To keep the number of segments <= _seedcount, adding a segment w/o
		// incrementing i during the first loop of the iteration.
		{
			if (i==0)
			{																/* 11-5 Joe */
				pprop_prior = new cCritterWormsEnemyHead( pplayer() );		/* 11-5 Joe */
				add( pprop_prior );											/* 11-5 Joe */
				pprop_prior->setMoveBox(cRealBox2(cVector(-19, -14.5), 
											cVector(19, 14.5)));			/* 11-12 Joe */
				pprop_prior->moveTo(cVector((k+1)*randomX, (k+1)*randomY));	/* 11-12 Joe */
				pprop_prior->setSnake( snake );								/* 11-12 Joe SnakeClass*/
				snake ->setHead( pprop_prior );								/* 11-12 Joe SnakeClass*/
			}																/* 11-5 Joe */

			cCritterWormsSeg *pprop = new cCritterWormsSeg(pprop_prior);	/* Lee 11-11-01 */
			add(pprop);
			pprop->setMoveBox( cRealBox2(cVector(-19, -14.5), cVector(19, 14.5)));	/* 11-12 Joe */
			pprop->moveTo( cVector( (k+1)*randomX, (k+1)*randomY ) );				/* 11-12 Joe */
			pprop->setSnake( snake );										/* 11-12 Joe SnakeClass*/
			//pprop->randomize(cCritter::MF_POSITION);
			pprop_prior = pprop;
		}
      snake->setTail( pprop_prior );										/* 11-12 Joe SnakeClass*/
   }
}


/* This is used to setup a player and its tail, or body segments */
void cGameWorms::initiatePlayer( int _playerseedcount )
{
	cCritterWormsPlayer * newPlayer = new cCritterWormsPlayer;
	//cCritter * pprop_prior
	cCritterWormsBase *pprop_prior;											/* 11-12 Joe SnakeClass*/
	cCritterWormsSnake * snake = new cCritterWormsSnake(this, _playerseedcount-1);	/* 11-12 Joe SnakeClass*/

	newPlayer->setSnake( snake );							/* 11-12 Joe SnakeClass*/
	snake->setHead( newPlayer );							/* 11-12 Joe SnakeClass*/
	newPlayer->setMoveBox( cRealBox2( cVector( -100, -100 ), cVector( 100, 100 ) ) );	/* 11-12 Joe */
	newPlayer->moveTo( cVector( -17, 14 ) );                                            /* 11-12 Joe */

	for (int i = 0; i < _playerseedcount - 1; i++)		/* Lee 11-11-01 */
   // To keep the number of segments <= _seedcount, adding a segment w/o
   // incrementing i during the first loop of the iteration.
	{
		if (i==0)
			pprop_prior = newPlayer;

		cCritterPlayerWormsSeg *pprop = new cCritterPlayerWormsSeg(pprop_prior);	/* Lee 11-11-01 */
		add(pprop);
		pprop->setMoveBox( cRealBox2( cVector( -100, -100 ), cVector( 100, 100 ) ) );	/* 11-12 Joe */
		pprop->moveTo( cVector( -17, 14 ) );                                            /* 11-12 Joe */
		pprop ->setSnake( snake );												/* 11-12 Joe SnakeClass*/
		//pprop->randomize(cCritter::MF_POSITION);
		pprop_prior = pprop;
	}

	setPlayer(newPlayer);
   snake->setTail( pprop_prior );												/* 11-12 Joe SnakeClass*/
}


// cGameWorms::reset does not get called at first startup, is called only
// when you start a new round or level of the game.
void cGameWorms::reset() 
{
   initiatePlayer( playerLength);                                              /* 11-5 Joe */
	cGame::reset();								//Calls pplayer()->reset() and seedCritters().
}

/* 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 cGameWorms::initializeView(CPopView *pview)
{
	cGame::initializeView(pview);				//Always call baseclass
	pview->setCursor(((CPopApp*)::AfxGetApp())->_hCursorPlay);
	pview->setUseBackgroundBitmap(TRUE);		//TRUE if you want the background, FALSE if not.
}

CString cGameWorms::statusMessage()
{
	CString cStrStatusBar = cGame::statusMessage(); //Get the standard message
	return cStrStatusBar;
}

BOOL cGameWorms::collide(cCritter *pcriti, cCritter *pcritj)
{
	/* For now we just copy cGame.  But we may sometimes want to take that
	code and edit it so as to make sure that certain kinds of pcritj get
	to call pcritj->collide(pcriti) instead of the (normal) other way
	around.*/
		//*
   BOOL collide = cGame::collide(pcriti, pcritj);              //* 11-12 Joe */
   if( collide )                                               //* 11-12 Joe */
   {
	   //  This stuff might be nukable?  -Rich

		//      if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead))) /* Lee 11-11-01 */
		//      {	// Stops worm heads from being pushed around by other segments
		//      		return FALSE;
		//      }
		//     if( pcritj->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer)) )
		//        return pcritj->collide( pcriti );
		//     if( pcritj->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead)) )
		//        return pcritj->collide( pcriti );
		//     if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer))) ///* Lee 11-11-01 */
		/*  {	// Stops worm heads from being pushed around by other segments
	      if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterPlayerWormsSeg)))
		      return FALSE;
      }*/

      if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterWormsSeg))) ///* Lee added 11-11-01 */
      {	// Stops worm heads from being pushed around by other segments
	      return FALSE;
      }
      if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterPlayerWormsSeg))) ///* Lee added 11-11-01 */
      {	// Stops worm heads from being pushed around by other segments
	      return FALSE;
      }

		//* Lee 11-11-01 */
		/*
		if (pcriti->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer))) 
		{
			cCritterWormsPlayer * player = (cCritterWormsPlayer * )pcriti;
			if (pcritj->IsKindOf(RUNTIME_CLASS(cCritterWormsSeg)))
			{
				cCritterWormsSeg * seg = (cCritterWormsSeg *)pcritj;
				seg->getSnake()->eatenTail();
				player->getSnake()->growSnake();
				//pcritj->die();
				//return FALSE;
			}
		}*/
	}
	return collide;                  /* 11-12 Joe */
	//return cGame::collide(pcriti, pcritj);
}

void cGameWorms::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 
		((CPopApp*)::AfxGetApp())->playSound("Tada",
			SND_RESOURCE|SND_ASYNC);
      // Player want to keep his length when game restarts
      playerLength = pbiota()->count(RUNTIME_CLASS(cCritterPlayerWormsSeg));
		return; 
	}

	// (2) Perhaps do this to reseed the screen if rivals are gone.
	int othercrittercount = pbiota()->count(RUNTIME_CLASS(cCritter)) -
		pbiota()->count(RUNTIME_CLASS(cCritterWall)) -					/* Lee added 11-11-01 */
		pbiota()->count(RUNTIME_CLASS(cCritterPlayerWormsSeg)) - 1;		/* Lee added 11-11-01 */

	/*** possibly add to level here, maybe increase snake intel? ***/	/* Lee added 11-11-01 */
	//Number of critters minus bullets minus player equals other critters.
	if (!othercrittercount) //Player is alone with bullets
	{
		seedCritters();
		initiatePlayer( playerLength );			/* 11-13 Joe */
		//initiateMap1();						/* 11-14 Joe */
	}

	// (3) Maybe check some other conditions.
}

void cGameWorms::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 >> ...
}

//void cGameWorms::insertAnimal( Real dt )
//{
//}

cCritterWormsPlayer::cCritterWormsPlayer()
: _eggDropped( FALSE )
{
   //_timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
   _timeUntilFood = cRandomizer::pinstance()->randomReal( minFoodTime, maxFoodTime );
   cCritterWormsBase::cCritterWormsBase();			/* 11-12 Joe SnakeClass*/

	//Set the listener
	setListener(new cListenerArrow());              /* 11-12 Joe */

	setHealth(cGameWorms::PLAYERHEALTH);
	setMaxspeed( cCritter::MAXSPEED );				/* 11-12 Joe */

	setSprite( new cSpriteIcon(IDB_PLAYERSNAKEHEAD) );
//	setRadius(1.5*cCritter::MINRADIUS);
	setRadius(1.0);
}

void cCritterWormsPlayer::reset()
{
	setHealth(cGameWorms::PLAYERHEALTH);
}

BOOL cCritterWormsPlayer::collide(cCritter *pcritter)
{
	BOOL collideflag = cCritter::collide(pcritter);
#ifdef NOEAT
   return FALSE;
#endif

	//May sometimes do more stuff here if collideflag is TRUE.
   if( collideflag )
   {
  	  if (pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsSeg)))
      {
	     cCritterWormsSeg * seg = (cCritterWormsSeg *)pcritter;
         seg->getSnake()->eatenTail();
         //getSnake()->growSnake();
         return false;
         //pcritj->die();
	     //return FALSE;
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead)) )
      {
         cCritterWormsEnemyHead * head = (cCritterWormsEnemyHead *)pcritter;
         if( getSnake()->getSize() == head->getSnake()->getSize() )
            return false;
         
         else if( getSnake()->getSize() > head->getSnake()->getSize() )
         {
            head->getSnake()->eatenHead();
            head->die();
            getSnake()->growSnake();
            return false;
         }
         else
         {
            getSnake()->getGame()->setGameover( true );
            return false;
         }
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyEgg)))
      {
         pcritter->die();
         getSnake()->growSnake();
         return false;
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayerEgg)))
         return false;
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsFood)))
      {
         pcritter->die();
         getSnake()->growSnake();
         return false;
      }
   }
	return collideflag;
}

void cCritterWormsPlayer::update(Real dt, CPopView *pview)
{
	cCritter::update(dt, pview);	//Always call this first
    if( !_eggDropped )
       getSnake()->dropEgg( dt, _eggDropped );
    seedRandomFood( dt );
}

void cCritterWormsPlayer::seedRandomFood(Real dt)
{
#ifndef NOFOOD
   if( _timeUntilFood <= 0 && getSnake()->getGame()->pbiota()->count(RUNTIME_CLASS(cCritterWormsFood)) < 1)
   {
      _timeUntilFood -= dt;
      cCritterWormsFood * newFood = new cCritterWormsFood();
      getSnake()->getGame()->add( newFood );

      // Reset the time until food counter
      _timeUntilFood = cRandomizer::pinstance()->randomReal( minFoodTime, maxFoodTime );
   }
#endif
}

//==================== cCritterWormsSeg ====================

cCritterWormsSeg::cCritterWormsSeg(cCritterWormsBase *pcritter) /* Lee added 11-11-01 */
{
	setPrevious( pcritter );							/* 11-12 Joe SnakeClass*/
	//   setMaxspeed( cCritter::MAXSPEED + 1.5 );		/* 11-12 Joe */
//	setSprite(cGame::RANDOMSPRITE(cGame::ST_BUBBLES));	/* Lee added 11-11-01 */
	setSprite(new cSpriteIcon(IDB_ENEMYSNAKESEG));		// Rich 11/19
	setRadius( 0.8 );									// Rich 11/19

	//Add some forces
	if (pcritter)
		addForce(new cForceObjectSpringRod(pcritter, 0.5, 1000));  
		// want distance between critters Lee added 11-11-01 */
}


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

	return collideflag;
}

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

//==================== cCritterPlayerWormsSeg ====================

cCritterPlayerWormsSeg::cCritterPlayerWormsSeg(cCritterWormsBase *pcritter)
{  
	setPrevious( pcritter );						/* 11-12 Joe SnakeClass*/
	//   setMaxspeed( cCritter::MAXSPEED + 2.5 );	/* 11-12 Joe */

//	setSprite(cGame::RANDOMSPRITE(cGame::ST_BUBBLES));
	setSprite(new cSpriteIcon( IDB_PLAYERSNAKESEG) );
	setRadius( 0.8 );								/* 11-6 Joe */

	//Add some forces
	if (pcritter)
		addForce(new cForceObjectSpringRod(pcritter, 0.9, 1000));
}

BOOL cCritterPlayerWormsSeg::collide(cCritter *pcritter) /* Lee added 11-11-01 */
{
	//BOOL collideflag = cCritter::collide(pcritter);
	//May sometimes do more stuff here if collideflag is TRUE.
	//return collideflag;
   return false;
}

void cCritterPlayerWormsSeg::update(Real dt, CPopView *pview) /* Lee added 11-11-01 */
{
	cCritter::update(dt, pview); //Always call this first
}

//===================cCritterMazeWall				/* Lee added 11-04-01 */
cCritterMazeWall::cCritterMazeWall(const cVector &enda, const cVector &endb,
										Real thickness):
cCritterWall(enda, endb, thickness)
{
	setFixedflag(TRUE);
}

//===================cCritterWormsEnemyHead			/* 11-5 Joe */
cCritterWormsEnemyHead::cCritterWormsEnemyHead( cCritter * pcritter )
{
	_timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
	//addForce( new cForceObjectAccelerateTowards( pcritter, 10 ) );     /* 11-12 Joe */
	setSprite( new cSpriteIcon(IDB_ENEMYSNAKEHEAD) );
	//randomize(cCritter::MF_VELOCITY);				/* Lee added 11-11-01 */
	setRadius( 1.0 );
}

BOOL cCritterWormsEnemyHead::collide( cCritter * pcritter )
{
	BOOL collideflag = cCritter::collide(pcritter);
#ifdef NOEAT
   return FALSE;
#endif
	//May sometimes do more stuff here if collideflag is TRUE.
   if( collideflag )
   {
      if (pcritter->IsKindOf(RUNTIME_CLASS(cCritterPlayerWormsSeg)))
      {
         cCritterPlayerWormsSeg * seg = (cCritterPlayerWormsSeg *)pcritter;
         seg->getSnake()->eatenTail();
		 //getSnake()->growSnake();
         //pcritj->die();
	     //return FALSE;
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayerEgg)))
      {
         pcritter->die();
         getSnake()->growSnake();
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyEgg)))
         return false;
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsFood)))
      {
         pcritter->die();
         getSnake()->growSnake();
         return false;
      }
   }
	return collideflag;
}

void cCritterWormsEnemyHead::update( Real dt, CPopView * pview )
{
   bool useless;
   cCritter::update(dt, pview);		//Always call this first
   getSnake()->dropEgg( dt, useless );
}

//====================cCritterWormsSnake     /* 11-12 Joe SnakeClass */


inline cCritterWormsSnake::cCritterWormsSnake( cGameWorms * game, int size )
      : _pHead( NULL ), _pTail( NULL ), _pGame( game ), _size(size)
{ 
   _timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
}

void cCritterWormsSnake::eatenTail()
{
   cCritterWormsBase * newTail;

   newTail = _pTail->getPrevious();
   
   if( _pTail )
      _pTail->die();
   
   _pTail = newTail;
   _size--;
}

void cCritterWormsSnake::eatenHead()
{
   deleteAll();
}

/* 11-12 Joe */
void cCritterWormsSnake::growSnake()
{
   if (_pHead->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer)))
   {
      cCritterPlayerWormsSeg * newSeg = new cCritterPlayerWormsSeg( _pTail );
      newSeg->setMoveBox( cRealBox2( cVector( 0-(worldWidth/2), 0-(worldHeight/2) )
                                    , cVector( worldWidth/2, worldHeight/2 ) ) );
      newSeg->moveTo( _pTail->position() );
      _pGame->add( newSeg );
      newSeg->setSnake( this );
      _pTail = newSeg;
      _size++;
   }
   if (_pHead->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead)))
   {
      cCritterWormsSeg * newSeg = new cCritterWormsSeg( _pTail );
      newSeg->setMoveBox( cRealBox2( cVector( 0-(worldWidth/2), 0-(worldHeight/2) )
                                    , cVector( worldWidth/2, worldHeight/2 ) ) );
      newSeg->moveTo( _pTail->position() );
      _pGame->add( newSeg );
      newSeg->setSnake( this );
      _pTail = newSeg;
      _size++;
   }
}

void cCritterWormsSnake::deleteAll()
{
   while( _size > 0 )
      eatenTail();
}

void cCritterWormsSnake::dropEgg( Real dt, bool & dropped )
{
   _timeUntilEgg -= dt;

#ifndef NOEGG
   if( _timeUntilEgg <= 0 )
   {

      if( _size <= 1 )
      {	 
		 // If the snake drops the last last body segement, the snake dies
         _pTail->die();
         _pHead->die();
      }
      else
      {
         if( _pHead->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer)) )
         {
            eatenTail();
            cCritterWormsPlayerEgg * newEgg = new cCritterWormsPlayerEgg;
            newEgg->setSprite( new cSpriteIcon( IDB_SUN ) );
            newEgg->setRadius( 1 );
            newEgg->setMoveBox( cRealBox2( _pTail->position(), _pTail->position() ) );
            newEgg->moveTo( _pTail->position() );
            newEgg->setFixedflag( true );   
            _pGame->add( newEgg );
            dropped = true;
         }
         else if( _pHead->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead)) )
         {
            eatenTail();
            cCritterWormsEnemyEgg * newEgg = new cCritterWormsEnemyEgg();
            newEgg->setSprite( new cSpriteIcon( IDB_EARTH ) );
            newEgg->setRadius( 1 );
            newEgg->setMoveBox( cRealBox2( _pTail->position(), _pTail->position() ) );
            newEgg->moveTo( _pTail->position() );
            newEgg->setFixedflag( true );
            _pGame->add( newEgg );
         }
      }
   // Drop egg must reset the random amount of time.
   _timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
   }
#endif
}

//============================cCritterWormsFood  /* 11-15 Joe */
cCritterWormsFood::cCritterWormsFood()
{
   setMoveBox( cRealBox2( cVector( 0-(worldWidth/2), 0-(worldHeight/2) )
                                    , cVector( worldWidth/2, worldHeight/2 ) ) );
   moveTo( cVector( cRandomizer::pinstance()->randomReal( 0-(worldWidth/2), worldWidth/2 )
                              , cRandomizer::pinstance()->randomReal( 0-(worldHeight/2), worldHeight/2 ) ) );
   setSprite( new cSpriteIcon( IDB_EXPLODE3 ) );
   setVelocity( cVector( 10,10 ) );
}