/*
File: gameworms.cpp
Uploaded by joecheng on Fri Dec 14 14:44:05 PST 2001
*/

/*
File: gameworms.cpp
Uploaded by joecheng on Thu Nov 29 14:47:31 PST 2001
*/

// gameworms.cpp: implementation of the generic cGameWorms class.
//
// Cleaned up version 11/16/01 -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 = 3; 
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 frog 11-13  Joe */   
static int randomMaxTime = 6;			/* max time in seconds before new frog 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;
const int playerStartLength = 3;
int playerLives = 3;
int level = 1;
Real wallThickness = 0.8;
cVector2 playerStart( -17, 14 );

cGameWorms::cGameWorms(): //This constructor gets called only once, at first start.
	_rivalcount(3), _playerLength( playerStartLength )
{
   //Setup the random amount of time until an animal is released /* 11-13 Joe  */
   _timeUntilFood = 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 */

   initializeLocations();

#ifndef NOWALLS
   if (level % 2)
	   initiateMap1();
   else
	   initiateMap2();
   level++;
#endif

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

void cGameWorms::step( Real dt, CPopView *pactiveview )
{  
#ifndef NOFOOD
   if( pbiota()->count(RUNTIME_CLASS(cCritterWormsFood)) < 1 )
      _timeUntilFood -= dt;

   if( _timeUntilFood <= 0 )
   {
      cCritterWormsFood * newFood = new cCritterWormsFood();
      add( newFood );

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

void cGameWorms::initiateMap1()
{
	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
	add(new cCritterMazeWall( cVector(19, 14.5),	cVector(19, -14.5))); // 59 /* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(-19, 14.5),	cVector(-19, -14.5))); // 60/* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(19, 14.5),	cVector(-19, 14.5))); // 61 /* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(19, -14.5),	cVector(-19, -14.5))); // 62/* Lee 12-01-01 */
}

void cGameWorms::initiateMap2()
{
        // a second map for worm game 12/4/01 -Rich
	add(new cCritterMazeWall(cVector(-16.5,-12), cVector(-3,-12)));
	add(new cCritterMazeWall(cVector(3,-12), cVector(16,-12)));
	add(new cCritterMazeWall(cVector(0,-14), cVector(0,-9)));
	add(new cCritterMazeWall(cVector(-3,-9), cVector(3,-9)));
	add(new cCritterMazeWall(cVector(-6,-6), cVector(-2,-6)));
	add(new cCritterMazeWall(cVector(2,-6), cVector(6,-6)));
	add(new cCritterMazeWall(cVector(-7,-3), cVector(-7,3)));
	add(new cCritterMazeWall(cVector(6,-3), cVector(6,0)));
	add(new cCritterMazeWall(cVector(-6,-12), cVector(-6,-9)));
	add(new cCritterMazeWall(cVector(6,-12), cVector(6,-9)));
	add(new cCritterMazeWall(cVector(-9,-9), cVector(-12.5,-9)));
	add(new cCritterMazeWall(cVector(-9,-9), cVector(-9,-6)));
	add(new cCritterMazeWall(cVector(9,-9), cVector(13,-9)));
	add(new cCritterMazeWall(cVector(9,-9), cVector(9,-6)));
	add(new cCritterMazeWall(cVector(-16.5,-9), cVector(-16.5,-6)));
	add(new cCritterMazeWall(cVector(-16.5,-6), cVector(-13.0,-6)));
	add(new cCritterMazeWall(cVector(-7,-3), cVector(-13.0,-3)));
	add(new cCritterMazeWall(cVector(-10,0), cVector(-16.5,0)));
	add(new cCritterMazeWall(cVector(-16.5,0), cVector(-16.5,3)));
	add(new cCritterMazeWall(cVector(-19,-3), cVector(-16.0,-3)));
	add(new cCritterMazeWall(cVector(-16.5,6), cVector(-13.5,6)));
	add(new cCritterMazeWall(cVector(-13.5,9), cVector(-13.5,3)));
	add(new cCritterMazeWall(cVector(-16.5,9), cVector(-16.5,12)));
	add(new cCritterMazeWall(cVector(-16.5,12), cVector(-13.5,12)));
	add(new cCritterMazeWall(cVector(-10,0), cVector(-10,3)));
	add(new cCritterMazeWall(cVector(-10,6), cVector(-10,9)));
	add(new cCritterMazeWall(cVector(-4,6), cVector(0,6)));
	add(new cCritterMazeWall(cVector(-10,6), cVector(-7,6)));
	add(new cCritterMazeWall(cVector(-10,12), cVector(-3,12)));
	add(new cCritterMazeWall(cVector(-7,12), cVector(-7,9)));
	add(new cCritterMazeWall(cVector(0,14), cVector(0,12)));
	add(new cCritterMazeWall(cVector(3,9), cVector(-4,9)));
	add(new cCritterMazeWall(cVector(19,6), cVector(15.5,6)));
	add(new cCritterMazeWall(cVector(2.7,12), cVector(3.1,12)));
	add(new cCritterMazeWall(cVector(6,12), cVector(6,6)));
	add(new cCritterMazeWall(cVector(3,6), cVector(9,6)));
	add(new cCritterMazeWall(cVector(6,3), cVector(-4,3)));
	add(new cCritterMazeWall(cVector(-4,-3), cVector(-4,0)));
	add(new cCritterMazeWall(cVector(-4,-3), cVector(3,-3)));
	add(new cCritterMazeWall(cVector(-1.5,0), cVector(3,0)));
	add(new cCritterMazeWall(cVector(9,3), cVector(9,-3)));
	add(new cCritterMazeWall(cVector(9,3), cVector(13,3)));
	add(new cCritterMazeWall(cVector(9,12), cVector(12,12)));
	add(new cCritterMazeWall(cVector(9,12), cVector(9,9)));
	add(new cCritterMazeWall(cVector(16,14), cVector(16,9)));
	add(new cCritterMazeWall(cVector(16,9), cVector(12,9)));
	add(new cCritterMazeWall(cVector(12,9), cVector(12,6)));
	add(new cCritterMazeWall(cVector(16,0), cVector(12.5,0)));
	add(new cCritterMazeWall(cVector(16,3), cVector(16,-3)));
	add(new cCritterMazeWall(cVector(12.5,-6), cVector(16,-6)));
	add(new cCritterMazeWall(cVector(16,-6), cVector(16,-9)));
	add(new cCritterMazeWall(cVector(9,-3), cVector(13,-3)));
	add(new cCritterMazeWall( cVector(19, 14.5),	cVector(19, -14.5))); // 59 /* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(-19, 14.5),	cVector(-19, -14.5))); // 60/* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(19, 14.5),	cVector(-19, 14.5))); // 61 /* Lee 12-01-01 */
	add(new cCritterMazeWall( cVector(19, -14.5),	cVector(-19, -14.5))); // 62/* Lee 12-01-01 */
}

void cGameWorms::initializeLocations()
{
   startLocations[0] = cVector( 14, 11 );
   startLocations[1] = cVector( -14,-11 );
   startLocations[2] = cVector( 14, -11 );
   startLocations[3] = cVector( 5.5, 3 );
   startLocations[4] = cVector( 5, -4 );
   startLocations[5] = cVector( -9, 3 );
   startLocations[6] = cVector( 5, -10 );
   startLocations[7] = cVector( -6, 0 );
   startLocations[8] = cVector( 15, -1 );
   startLocations[9] = cVector( 0, 1 );
   startLocations[10] = cVector( -2, 10 );
   startLocations[11] = cVector( 3, -10);
   startLocations[12] = cVector( 2, 10 );
   startLocations[13] = cVector( -2, -11 );
   startLocations[14] = cVector( 10, -8 );
   startLocations[15] = cVector( -10, -8 );
   startLocations[16] = cVector( 10, 8 );
   startLocations[17] = cVector( -9, 8 );
   startLocations[18] = cVector( 9, 5 );
   startLocations[19] = cVector( -6, -3 );
   // startLocations[20] = cVector( -14, -1 );

}

void cGameWorms::seedCritters()
{
//	pbiota()->purgeNonPlayerNonWallCritters(); 
	pbiota()->purgeNonPlayerCritters();
#ifndef NOWALLS
   if (level % 2)
		initiateMap1();
   else
	    initiateMap2();
	   
   level++;
#endif
  int locationNumber = cRandomizer::pinstance()->randomReal( 0, possibleLocations );

	for (int k=0; k < cGameWorms::WORMCOUNT; k++)
   {
      locationNumber = cRandomizer::pinstance()->randomReal( 0, possibleLocations );
	   initiateEnemySnake( _seedcount - 1, startLocations[locationNumber] );
   }
}


/* This is used to setup a player and its tail, or body segments */
void cGameWorms::initiatePlayer( int _playerseedcount )
{
	cCritterWormsPlayer * newPlayer = new cCritterWormsPlayer;
	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*/
   //snake->addSegment( newPlayer );
	newPlayer->setMoveBox( cRealBox2( cVector( -100, -100 ), cVector( 100, 100 ) ) );	/* 11-12 Joe */
	newPlayer->moveTo( playerStart );                                            /* 11-12 Joe */
	setPlayer(newPlayer);
   initiatePlayerSegs( _playerseedcount, snake );
}

void cGameWorms::initiatePlayerSegs( int seedcount, cCritterWormsSnake * snake )
{
	cCritterWormsBase *pprop_prior;											/* 11-12 Joe SnakeClass*/

	for (int i = 0; i < seedcount - 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 = (cCritterWormsPlayer *)pplayer();

		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( playerStart );                                            /* 11-12 Joe */
		pprop->setSnake( snake );												/* 11-12 Joe SnakeClass*/
      snake->addSegment( pprop );
		pprop_prior = pprop;
	}

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

void cGameWorms::initiateEnemySnake( int length, cVector2 location )
//void cGameWorms::seedCritters()
{
   //int locationNumber = cRandomizer::pinstance()->randomReal( 0, possibleLocations );
	cCritterWormsBase * pprop_prior;	/* This is a special trick for the
										follow-the-leader thing we'll set up in 
										the next loop.  Not standard. */   

   cCritterWormsSnake * snake = new cCritterWormsSnake( this );//, _seedcount - 1 );	/* 11-12 Joe  SnakeClass*/

   //locationNumber = cRandomizer::pinstance()->randomReal( 0, possibleLocations );

	for (int i = 0; i < length ; 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( location );	/* 11-12 Joe */
			//pprop_prior->moveTo( startLocations[locationNumber] );	/* 11-12 Joe */
			pprop_prior->setSnake( snake );								/* 11-12 Joe SnakeClass*/
			snake ->setHead( pprop_prior );								/* 11-12 Joe SnakeClass*/
         //snake->addSegment( pprop_prior );
		}																/* 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( location );	                           /* 11-12 Joe */
		//pprop->moveTo( startLocations[locationNumber] );				/* 11-12 Joe */
		pprop->setSnake( snake );										/* 11-12 Joe SnakeClass*/
      snake->addSegment( pprop );
		//pprop->randomize(cCritter::MF_POSITION);
		pprop_prior = pprop;
   }
}

// 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( playerStartLength );
      cGame::reset();
}

/* 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.
	cGame::reset();				/* 12-6 Cheap fix Lee */				//Calls pplayer()->reset() and seedCritters().
   initiatePlayer( playerStartLength);                                              /* 11-5 Joe */
}

CString cGameWorms::statusMessage()
  {
  	CString cStrStatusBar;
	int nUpdatesPerSecond;
	CString cStrUpdatespersecond;
	CString cStrPlayerSize;
	CString cStrCount;
	CString cStrScore;
	CString cStrPlayerHealth;

	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.runningNearMaxSpeed())
			cStrUpdatespersecond += " (Near Max)";
	}
	else
			cStrUpdatespersecond.Format("Animation is paused.");
	cStrScore.Format("Score: %d.", score());
	cStrPlayerSize.Format("Player Length: %d.", playerSize());
	cStrPlayerHealth.Format("Lives Left: %d.", health());
	int crittercount = _pbiota->count(RUNTIME_CLASS(cCritter));
	//int bulletcount = _pbiota->count(RUNTIME_CLASS(cCritterBullet));
   int wallCount = pbiota()->count(RUNTIME_CLASS(cCritterMazeWall));
	crittercount -= wallCount;
	if (visibleplayer()) /*Subtract off 1 for player as well. */
		crittercount -= 1;
	cStrCount.Format("Critters: %d.", crittercount);
	cStrStatusBar = cStrScore + "  " + cStrPlayerSize + "  " + cStrPlayerHealth + "  " + cStrCount + "  " + cStrUpdatespersecond; 
	return cStrStatusBar;
  }

BOOL cGameWorms::collide(cCritter *pcriti, cCritter *pcritj)
{
	/* The collide methods are used in this order
         1. Walls
         2. Player Head
         3. Enemy Head
         4. All others except the player and enemy eggs. 
   //*/
   BOOL collide;

   BOOL isiwall = pcriti->IsKindOf(RUNTIME_CLASS(cCritterWall));
 	BOOL isjwall = pcritj->IsKindOf(RUNTIME_CLASS(cCritterWall));
 	if (isiwall && isjwall) // Assume two walls don't collide for now. 
 		return FALSE; //May want to rethink this if we derive a paddle from wall.
 	if (isiwall)
 		return pcriti->collide(pcritj);
 	if (isjwall)
 		return pcritj->collide(pcriti);

   // For all collisions involving the Player's Head, call the Player's head's collide method
   if( pcritj->IsKindOf( RUNTIME_CLASS( cCritterWormsPlayer ) ) )
      collide = pcritj->collide( pcriti );
   else if( pcriti->IsKindOf( RUNTIME_CLASS( cCritterWormsPlayer ) ) )
      collide = pcriti->collide( pcritj );

   // For all collision that involve the Enemy's Head and NOT the Player's head call the 
   // Enemy's Head's collide method
   else if( pcritj->IsKindOf( RUNTIME_CLASS( cCritterWormsEnemyHead ) ) )
      collide = pcritj->collide( pcriti );
   else if( pcriti->IsKindOf( RUNTIME_CLASS( cCritterWormsEnemyHead ) ) )
      collide = pcriti->collide( pcritj );

   // All important egg collisions are dealt with in the heads already
   // Let the other classes collide method deal with the collision is the collision involves
   // an egg.
   else if( pcriti->IsKindOf( RUNTIME_CLASS( cCritterWormsPlayerEgg ) ) )
      collide = pcritj->collide( pcriti );
   else if( pcriti->IsKindOf( RUNTIME_CLASS( cCritterWormsEnemyEgg ) ) )
      collide = pcritj->collide( pcriti );

   // Finally call the "normal" collide 
   else
      BOOL collide = cGame::collide(pcriti, pcritj);              //* 11-12 Joe */
	
	return collide;                  /* 11-12 Joe */
}

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 his default Length back
      _playerLength = playerStartLength;
		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 */
      pbiota()->count(RUNTIME_CLASS(cCritterWormsFood)) - 
      pbiota()->count(RUNTIME_CLASS(cCritterWormsPlayerEgg)) -
      pbiota()->count(RUNTIME_CLASS(cCritterWormsEnemyEgg));

	/*** 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 )// && pplayer()->health() ) //Player is alone with bullets
	{
      if( pbiota()->count(RUNTIME_CLASS(cCritterWormsPlayerEgg)) > 0 )
         pplayer()->setHealth( health() + 1 );
      // Player gets to keep its lenght when the levels change
      _playerLength = playerSize() + 1;
      //_playerLength = pbiota()->count(RUNTIME_CLASS(cCritterPlayerWormsSeg));
		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 >> ...
}

cCritterWormsPlayer::cCritterWormsPlayer()
: _eggDropped( FALSE ), _calledByPlayer( false )
{
   setAbsorberflag( TRUE );
   setHealth( playerLives );
   //_timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
   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()
{
   if( _calledByPlayer )
   {
      getSnake()->deleteTail();

      moveTo( playerStart );
      getSnake()->getGame()->initiatePlayerSegs( playerStartLength, getSnake() );
            
      _calledByPlayer = false;
   }
}

void cCritterWormsPlayer::damagePlayer()
{
   damage(1);
   if ( health() <= 0)
   {
      getSnake()->getGame()->setGameover( true );
	   return;
   }
   else
   {
      _calledByPlayer = true;
      AfxMessageBox( "Get Ready to Be Reincarnated!!" );
      reset();
	   return;
   }
}

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 (cCritter::distanceTo( pcritter ) < (radius() + pcritter->radius()) / 1.2 )        /* 11-24 Joe */
   {
  	  if (pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsSeg)))
      {
	     cCritterWormsSeg * seg = (cCritterWormsSeg *)pcritter;
         seg->getSnake()->eatenTail();
         if( seg->getSnake()->getSize() < 1 )
            seg->getSnake()->eatenHead();
         //getSnake()->growSnake();
		 getSnake()->getGame()->pplayer()->addScore( 50 ); /* 12-6 Lee */
         return false;
         //pcritj->die();
	     //return FALSE;

      }
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyHead)) )
      {
         cCritterWormsEnemyHead * head = (cCritterWormsEnemyHead *)pcritter;

         if( getSnake()->getSize() > head->getSnake()->getSize() )
         {
            head->getSnake()->eatenHead();
            head->die();
            getSnake()->growSnake();
			   getSnake()->getGame()->pplayer()->addScore( 100 ); /* 12-6 Lee */
            return false;
         }
         else
            damagePlayer();
      }
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyEgg)))
      {
         pcritter->die();
         getSnake()->growSnake();
		 getSnake()->getGame()->pplayer()->addScore( 50 ); /* 12-6 Lee */
         return false;
      }
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayerEgg)))
         return false;
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsFood)))
      {
         pcritter->die();
         getSnake()->growSnake();
		 getSnake()->getGame()->pplayer()->addScore( 50 ); /* 12-6 Lee */
         return false;
      }
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterPlayerWormsSeg)))
         return false;
   }
   return cCritter::collide( pcritter );
}

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)
{
}

void cCritterWormsPlayer::die()
{
   cCritter::die();
}

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

cCritterWormsSeg::cCritterWormsSeg(cCritterWormsBase *pcritter) /* Lee added 11-11-01 */
{
	setPrevious( pcritter );							/* 11-12 Joe SnakeClass*/
	setSprite( new cSpriteIcon( IDB_ENEMYSNAKESEG ) );	/* Lee added 11-11-01 */
	setRadius( 1.0 );									/* 11-6 Joe */

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

BOOL cCritterWormsSeg::collide(cCritter *pcritter)
{
   return false;
}

void cCritterWormsSeg::update(Real dt, CPopView *pview)
{
	cCritter::update(dt, pview); //Always call this first
	/* new code - Lee - 12-4-01 */
	if (getSnake()->getGame()->pbiota()->count(RUNTIME_CLASS(cCritterPlayerWormsSeg)) > getSnake()->getSize() )
	{
		setSprite( new cSpriteIcon( IDB_SHORTENEMYSNAKESEG ) );
			setRadius( 1.0 );									/* 11-6 Joe */
	}
	else
	{
		setSprite( new cSpriteIcon( IDB_ENEMYSNAKESEG ) );
			setRadius( 1.0 );									/* 11-6 Joe */
	}
/*         cCritterWormsEnemyHead * head = (cCritterWormsEnemyHead *)pcritter;
         if( getSnake()->getSize() == head->getSnake()->getSize() )
		 {
			 head->setSprite( new cSpriteIcon( IDB_ENEMYSNAKESEG ) );
		 }         
         else if( getSnake()->getSize() > head->getSnake()->getSize() )
         {
			 head->setSprite( new cSpriteIcon( IDB_SHORTENEMYSNAKESEG ) );
         } */
}

void cCritterWormsSeg::die()
{
   cCritter::die();
//   getSnake()->getGame()->pplayer()->addScore( 50 ); /* otherwise egg drops give player score */
}

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

cCritterPlayerWormsSeg::cCritterPlayerWormsSeg(cCritterWormsBase *pcritter)
{  
	setPrevious( pcritter );						/* 11-12 Joe SnakeClass*/

	setSprite( new cSpriteIcon( IDB_PLAYERSNAKESEG ) );
	setRadius( 1.0 );								/* 11-6 Joe */

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

BOOL cCritterPlayerWormsSeg::collide(cCritter *pcritter) /* Lee added 11-11-01 */
{
   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);
   setThickness( wallThickness );

   psprite()->setFillColor(cColorStyle::CN_DARKGREEN);          // Rich
   psprite()->setLineColor(cColorStyle::CN_NOTASDARKGREEN);     // Rich
   psprite()->setLineWidthWeight(0.04);                         // Rich
}

BOOL cCritterMazeWall::collide( cCritter * pcritter )
{
   // Need to change the collision detection scheme, make the collision occur when the
   // critter actually visually touches the walls

   /* Code directly from cCritterWall  */
	cVector localpos = globalToLocalPosition(pcritter->position());
	int newoutcode = outcodeLocal(localpos);
	Real distance = distanceToLocal(localpos, newoutcode);
	int oldoutcode = outcode(pcritter->oldposition());
	cVector localvelocity;
	cVector cornerpoint;
	cVector fromcorner;

	BOOL crossed = (oldoutcode == BOX_DOWN && !(newoutcode & BOX_DOWN)) ||
		(oldoutcode == BOX_UP && !(newoutcode & BOX_UP)); /* First check for moving across
			in direction of normal */
	crossed |=  (oldoutcode == BOX_LEFT && !(newoutcode & BOX_LEFT)) ||
		(oldoutcode == BOX_RIGHT && !(newoutcode & BOX_RIGHT)); /* Then Check for moving
			across in direction of tangent (can happen either if someone wants to 
			cut across a corner, or, less often, across whole tangent length (usually this direction 
			is long, but someone could change this by choosing close endpoints and a big
			thickness). */

			/* If crossed is TRUE then we moved across the wall, even though we may no longer
			be touching it. Note that we are checking for cutting across corners as well to make it 
			harder to sneak 	out of a box of walls.  We do this instead use a simpler check like 
			like BOOL crossed = (oldoutcode == BOX_DOWN && newoutcode == BOX_UP) ||
				oldoutcode == BOX_UP && newoutcode == BOX_DOWN)), 	etc.  A different approach
			would be to look  at the UP DOWN parts of the wallbox corners' outcodes relative
			to the line connecting position and oldposition; if some are UP and some are 
			DOWN then the line crosses. */

	if (distance >= pcritter->radius() / 2 && !crossed) //No collision
		return FALSE; /*See if there's a collision at all. We say there's a collision if 
			crossed or if the cCritterWall::distance is less than radius.  Remember 
			that cCritterWall::distance measures the distance to the OUTSIDE PERIMETER of
			the box, not the distance to the box's center. cCritterWall::distance is 0 for 
			any point inside the wall's box. */
   /* End here code from, cCritterWall */

   		/* Now pick an newoutcode to determine which region outside of the wall that you want
			to bounce into. */
	if (newoutcode == BOX_INSIDE || newoutcode != oldoutcode) 
				//If inside, or you passed through the wall.
		newoutcode = oldoutcode;
	if (newoutcode == BOX_INSIDE)
				//You're inside, or you passed through, and oldoutcode was inside.  Back up.
	{
		cVector backupposition = pcritter->position();
		int backupcount = 0; //Avoid faint possibility of being in the while loop forever.
		while (newoutcode == BOX_INSIDE && backupcount<10)
		{
			backupposition -= _radiusnormal * pcritter->tangent();
			newoutcode = outcode(backupposition);
			backupcount++;
		}
	}
	if (newoutcode == BOX_INSIDE)
			//If somehow STILL not a good newoutcode, just use direction of attitudeNormal().
		newoutcode = BOX_UP;

	localvelocity = globalToLocalVector(pcritter->velocity()); 

	switch(newoutcode)
	{
		case BOX_LEFT:
			localpos.set(-_radiustangent - pcritter->radius(), localpos.y());
			localvelocity.set(-fabs(localvelocity.x()), localvelocity.y());
			break;
		case BOX_RIGHT:
			localpos.set(_radiustangent + pcritter->radius(), localpos.y());
			localvelocity.set(fabs(localvelocity.x()), localvelocity.y());
			break;
		case BOX_DOWN:
			localpos.set(localpos.x(), -_radiusnormal - pcritter->radius());
			localvelocity.set(localvelocity.x(), -fabs(localvelocity.y()));
			break;
		case BOX_UP:
			localpos.set(localpos.x(), _radiusnormal + pcritter->radius());
			localvelocity.set(localvelocity.x(), fabs(localvelocity.y()));
			break;
		case BOX_DOWN_LEFT:
		case BOX_DOWN_RIGHT:
		case BOX_UP_LEFT:
		case BOX_UP_RIGHT: /* For the corner outcodes we bounce off the corner point. */
			switch(newoutcode)
			{
				case BOX_DOWN_LEFT:
					cornerpoint.set(-_radiustangent, -_radiusnormal);
					break;
				case BOX_DOWN_RIGHT:
					cornerpoint.set(_radiustangent, -_radiusnormal);
					break;
				case BOX_UP_LEFT:
					cornerpoint.set(-_radiustangent, _radiusnormal);
					break;
				case BOX_UP_RIGHT:
					cornerpoint.set(_radiustangent, _radiusnormal);
					break;
			}
			fromcorner = (localpos - cornerpoint).normalize();
			localpos = cornerpoint + pcritter->radius()*fromcorner;
			localvelocity = -localvelocity;
				/* To keep someone from unrealistically bouncing up and down on a corner, we
					jiggle the bounce. */
			localvelocity.turn(cRandomizer::pinstance()->randomReal(-cCritterWall::CORNERJIGGLE,
				-cCritterWall::CORNERJIGGLE));
			break;
	}
	pcritter->moveTo(localToGlobalPosition(localpos));
	pcritter->setVelocity(localToGlobalVector(localvelocity));
	
   //BOOL collided = cCritterWall::collide( pcritter );

   if( pcritter->IsKindOf( RUNTIME_CLASS( cCritterWormsPlayer ) ) || 
        pcritter->IsKindOf( RUNTIME_CLASS( cCritterWormsEnemyHead ) ) )
   {
      // Set the critter colliding into the wall to turn either right or left
//      if( collided )
         if( cRandomizer::pinstance()->randomBOOL() )
            pcritter->yaw( - 80 );
         else
            pcritter->yaw( 80 );
      /* 11-24 Joe */
      // Code to only allow movements in either 0, 90, 180, 270 degrees
      cVector direction = tangent();
      Real x = pcritter->tangent().x();
      Real y = pcritter->tangent().y();
      // The tangent vector points upwards
      if( y > 0 )
      {
         if( x < 0 )
         {
            if( (0.0 - x) <= y )
               pcritter->setTangent( cVector2( 0.0, 1.0 ) );
            else
               pcritter->setTangent( cVector2( -1.0, 0.0 ) );
         }
         else 
         {
            if( x <= y ) 
               // the critter moves up
               pcritter->setTangent( cVector2( 0.0, 1.0 ) );
            else if( x > y )
               pcritter->setTangent( cVector2( 1.0, 0.0 ) );
         }
      }
      // The tangent vector points downwards
      if( y < 0 )
      {
         if( x < 0 )
         {
            if( ( 0 - x ) <= ( 0 - y ) )
               pcritter->setTangent( cVector2( 0.0, -1.0 ) );
            else
               pcritter->setTangent( cVector2( 1.0, 0.0 ) );
         }
         else
         {
            if( x <= ( 0.0 - y ) )
               // the critter moves up
               pcritter->setTangent( cVector2( 0.0, -1.0 ) );
            else if( x > y )
               pcritter->setTangent( cVector2( -1.0, 0.0 ) );
         }   //
      }
      /* end 11-24 Joe */
   //return true;
   }

   return TRUE;
   
//   return collided;
}

//===================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 );
   //setTangent( cVector2( 0.3, 0.7 ) );
   //setSpeed( 5.0 );
   //setTarget( getSnake()->getGame()->pplayer() );
}

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

   if (cCritter::distanceTo( pcritter ) < (radius() + pcritter->radius()) / 1.15 )     /* 11-24-01 Joe */
	//May sometimes do more stuff here if collideflag is TRUE.
   //if( collideflag )
   {
      if (pcritter->IsKindOf(RUNTIME_CLASS(cCritterPlayerWormsSeg)))
      {
         cCritterPlayerWormsSeg * seg = (cCritterPlayerWormsSeg *)pcritter;
         cCritterWormsPlayer * player = (cCritterWormsPlayer *)seg->getSnake()->getHead();
         //player->damagePlayer();
         seg->getSnake()->eatenTail();
         if( player->getSnake()->getSize() < 1 )
            player->damagePlayer();
		 //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;
      }
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsSeg)))
         return false;
   }
	return false;
   //return cCritter::collide( pcritter );
}

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

void cCritterWormsEnemyHead::die()
{
   cCritter::die();
 //  getSnake()->getGame()->pplayer()->addScore( 100 ); /* complete code */
}

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

inline cCritterWormsSnake::cCritterWormsSnake( cGameWorms * game )
      : _pHead( NULL ), _pTail( NULL ), _pGame( game ), _size( 0 )
{ 
   _timeUntilEgg = cRandomizer::pinstance()->randomReal( randomMinTime, randomMaxTime );
}
void cCritterWormsSnake::eatenTail()
{
   cCritterWormsBase * newTail;

   // if the tail does not exist then the snake dies.
   if( !_pTail )
   {
      eatenHead();
      return;
   }

   newTail = _pTail->getPrevious();
   if( _pTail )
      _pTail->die();
   
   _pTail = newTail;
   _size--;
/*
   // If this causes the snake to have no body then the snake dies.
   if( _size < 1 )
   {
      eatenHead();
   }*/
}

// When calling this function, you must either immdeiately add segments or kill the snake
void cCritterWormsSnake::deleteTail()
{
   while ( _size >= 1 )
   {
      cCritterWormsBase * newTail;

      // if the tail does not exist then the snake dies.
      if( !_pTail )
      {
         eatenHead();
         return;
      }

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

void cCritterWormsSnake::eatenHead()
{
   deleteTail();
   if( _pHead )
      _pHead->die();
}

/* 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::dropEgg( Real dt, bool & dropped )
{
   _timeUntilEgg -= dt;

#ifndef NOEGG
   if( _timeUntilEgg <= 0 && _size > 1 )
   {

      if( _size < 1 )
      {	 
         return;
		 // If the snake drops the last last body segement, the snake dies
         _pTail->die();
         _pHead->die();
      }
      else
      {
         if( _pHead->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayer)) )
         {
            eatenTail();
            if( getSize() < 1 )
               eatenHead();
            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();            
            if( getSize() < 1 )
               eatenHead();
            cCritterWormsEnemyEgg * newEgg = new cCritterWormsEnemyEgg( getGame() );
            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 );
//			newEgg->setUseFixedLifetime(TRUE);
//			newEgg->setFixedLifetime(5);
         }
      }
      // 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_FROGGI ) );
   setRadius( 1 );
   setVelocity( cVector( 10,10 ) );
}

BOOL cCritterWormsFood::collide( cCritter * pcritter )
{
   if (cCritter::distanceTo( pcritter ) < radius() + pcritter->radius() )
   {
      if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsEnemyEgg)))
         pcritter->die();
      else if( pcritter->IsKindOf(RUNTIME_CLASS(cCritterWormsPlayerEgg)))
         pcritter->die();
      
   }
   return false;
}

void cCritterWormsBase::drawHighlight( cGraphics * pgraphics, Real highlightratio )
{
   cCritter::drawHighlight( pgraphics, highlightratio );
   Real focusradius = (highlightratio * radius()) / 7000; //Rich
   cSpriteCircle focuscircle;
   focuscircle.setFilled(FALSE);
   focuscircle.setLineColor(cColorStyle::CN_LIGHTGRAY);
   focuscircle.setRadius(focusradius);                      // Rich
   focuscircle.setPrismDz(0.0);
}

void cCritterWormsEnemyEgg::die()
{
   if( _timeTillHatch <= 0 )
   //if( age() >= 2.0 )
   _pGame->initiateEnemySnake( 2, position() );
   cCritter::die();
}

void cCritterWormsEnemyEgg::update( Real dt, CPopView * pview )
{
   cCritter::update( dt, pview );
   _timeTillHatch -= dt;
   if( _timeTillHatch <= 0 )
      die();
}