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

IMPLEMENT_SERIAL(cGameHeroesOfCIS, cGame, 0);
IMPLEMENT_SERIAL(cCritterWrenchStatusIcon, cCritter, 0);
IMPLEMENT_SERIAL(cCritterHeroesPlayer, cCritterPlayer, 0);
IMPLEMENT_SERIAL(cCritterPrintQueueTray, cCritter, 0);
IMPLEMENT_SERIAL(cCritterPrintQueue, cCritter, 0);
IMPLEMENT_SERIAL(cCritterSupplyCabinet, cCritter, 0);
IMPLEMENT_SERIAL(cCritterPrinter, cCritter, 0);

//==============================cGameHeroesOfCIS

/* Other Class Constants -- Is this really where these belong? */
Real cCritterWrenchStatusIcon::WRENCH_STATUS_ICON_RADIUS = 1.0;
Real cCritterHeroesPlayer::MAX_SPEED = 15.0;
Real cCritterPrinter::PRINTER_RADIUS = 0.5;
Real cCritterPrintQueue::PRINT_QUEUE_RADIUS = 1.0;
int cCritterPrintQueue::MAX_QUEUE = 10; // There are currently only 10 sprites,
                                        // so this should probably not be larger than 10.
Real cCritterPrintQueueTray::PRINT_QUEUE_TRAY_RADIUS = 0.75;
Real cCritterPrintQueueTray::PRINT_QUEUE_TRAY_OFFSET = 1.5;

/* Game world parameters. */

Real cGameHeroesOfCIS::BLANK_EDGE_WEIGHT = 0.03; 
Real cGameHeroesOfCIS::PLAYFIELD_WEIGHT = 0.7; 
Real cGameHeroesOfCIS::PLAYFIELD_STATUSBOX_SPACER_WEIGHT = 0.03; 
	//Now some statics to define the graphical appearance of the boxes.
Real cGameHeroesOfCIS::BOX_LINEWIDTH_WEIGHT = 0.01; // thickness of the edge lines as a percent of window size.
COLORREF cGameHeroesOfCIS::PLAYFIELD_FILLCOLOR = cColorStyle::CN_LIGHTBLUE;
COLORREF cGameHeroesOfCIS::PLAYFIELD_LINECOLOR = cColorStyle::CN_BLACK;
COLORREF cGameHeroesOfCIS::STATUSBOX_FILLCOLOR = cColorStyle::CN_WHITE;
COLORREF cGameHeroesOfCIS::STATUSBOX_LINECOLOR = cColorStyle::CN_BLACK;

cGameHeroesOfCIS::cGameHeroesOfCIS() //The constructor gets called only once, at first start.
{
	_wrapflag = cCritter::BOUNCE;

	_spritetype = cGame::ST_BUBBLES; //Default sprite
	_menuflags = 0;

	//Fix your statics
	cCritter::MAXSPEED = 4.0; /* Customary to set critter speed, usually the
		bigger the world the higher the speed you want. */

	/**********************
	 * Create game world. *
	 **********************/

    //Set your world shape _border.set(width, height)
	_border.set(28.8, 19.2); //Standard is (14.4, 9.6), can override here

	//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. */
	/*
	 * We use framebox to set our game in a bit from the window border all
	 * the way around.  And then we let the _playfield to be the left part of
	 * the framebox, skip a little space, and put _statusbox in the rest of
	 * the framebox.  We need to prepare _playfield and _statusbox before calling seedBubbles,
	 * as that call will use them.
	 */
	cRealBox framebox = _border.innerBox(cGameHeroesOfCIS::BLANK_EDGE_WEIGHT *
		_border.minsize());
	_playfield = cRealBox(framebox.locorner(),
		cVector(framebox.lox()+PLAYFIELD_WEIGHT*framebox.xsize(), framebox.hiy()));
	_playfield.pcolorstyle()->setFillColor(cGameHeroesOfCIS::PLAYFIELD_FILLCOLOR);
	_playfield.pcolorstyle()->setLineWidthWeight(cGameHeroesOfCIS::BOX_LINEWIDTH_WEIGHT);
	_playfield.pcolorstyle()->setLineColor(cGameHeroesOfCIS::PLAYFIELD_LINECOLOR);
	_statusbox = cRealBox(cVector(_playfield.hix() +
		cGameHeroesOfCIS::PLAYFIELD_STATUSBOX_SPACER_WEIGHT*_border.minsize(), framebox.loy()),
		framebox.hicorner());
	_statusbox.pcolorstyle()->setFillColor(cGameHeroesOfCIS::STATUSBOX_FILLCOLOR);
	_statusbox.pcolorstyle()->setLineWidthWeight(cGameHeroesOfCIS::BOX_LINEWIDTH_WEIGHT);
	_statusbox.pcolorstyle()->setLineColor(cGameHeroesOfCIS::STATUSBOX_LINECOLOR);

//Set the backgroudn bitmap
//	setBackgroundBitmap(IDB_BACKGROUND); /*  Sets the cSpriteBackground for the background bitmap.
//		Note that you must call this after the _border has its size fully initialized. So each
//		cGame child with a different border should call this again in its constructor. */

	_arrayHCURSOR.SetSize(0); // turn off options menu

//Make a player
	setPlayer(new cCritterHeroesPlayer(this)); //"this" arg sets default player _movebox to match _border.
//Possibly make and add any permanent critters here.

	_level = 2;
}

/*
 * printerExploded checks to see if any printers have printqueues greater than MAXQUEUE
 */
BOOL cGameHeroesOfCIS::printerExploded()
{
	for (int i = 0; i < _printercount; ++i) {
		if (_pprinter[i]->isExploded())
			return TRUE;
	}

	return FALSE;
}

/* seedCritters makes and positions any temporary critters.  This gets
	automatically called when we select a game by the CPopDoc::setGameClass call.  It also gets
	called by cGame::reset() if you restart a game, or if the player advances to a new level.*/
void cGameHeroesOfCIS::seedCritters()
{
	/*
	 * Clean out any old non-player non-wall critters.
	 */
	pbiota()->purgeNonPlayerNonWallCritters(); 

	/*
	 * Create and place printers and supply cabinet.
	 */
	loadLevel(_level);
}

/* 
 * loadLevel creates and positions the printers and print queues for the given level.
 */
void cGameHeroesOfCIS::loadLevel(int level)
{

	switch (level) {
	case 0:
		// A supply cabinet in the upper right
		_psupplycabinet[0] = new cCritterSupplyCabinet(this);
		_psupplycabinet[0]->moveTo(cVector(
			playfield().hix() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius(),
			playfield().hiy() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius()));

		_printercount = 1;

		// A printer in the lower left
		_pprinter[0] = new cCritterPrinter(this);
		_pprinter[0]->moveTo(cVector(
			playfield().lox() + _pprinter[0]->radius() + 2 * pplayer()->radius(),
			playfield().loy() + _pprinter[0]->radius() + 2 * pplayer()->radius()));
		_pprinter[0]->pprintqueue()->moveTo(cVector(
			statusbox().lox() + statusbox().xsize()/2,
			statusbox().loy() + statusbox().ysize()/2));
		break;

	case 1:
		// A supply cabinet in the upper right
		_psupplycabinet[0] = new cCritterSupplyCabinet(this);
		_psupplycabinet[0]->moveTo(cVector(
			playfield().hix() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius(),
			playfield().hiy() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius()));

		_printercount = 2;

		// A printer in the lower left
		_pprinter[0] = new cCritterPrinter(this);
		_pprinter[0]->moveTo(cVector(
			playfield().lox() + _pprinter[0]->radius() + 2 * pplayer()->radius(),
			playfield().loy() + _pprinter[0]->radius() + 2 * pplayer()->radius()));
		_pprinter[0]->pprintqueue()->moveTo(cVector(
			statusbox().lox() + statusbox().xsize()/2,
			statusbox().loy() + statusbox().ysize()/2));

		// A printer in the upper left
		_pprinter[1] = new cCritterPrinter(this);
		_pprinter[1]->moveTo(cVector(
			playfield().lox() + _pprinter[1]->radius() + 2 * pplayer()->radius(),
			playfield().hiy() - _pprinter[1]->radius() - 2 * pplayer()->radius()));
		_pprinter[1]->pprintqueue()->moveTo(cVector(
			statusbox().lox() + statusbox().xsize()/2,
			statusbox().loy() + statusbox().ysize()/2 + 3 * _pprinter[1]->pprintqueue()->radius()));
		break;

	case 2:
		// A supply cabinet in the upper right
		_psupplycabinet[0] = new cCritterSupplyCabinet(this);
		_psupplycabinet[0]->moveTo(cVector(
			playfield().hix() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius(),
			playfield().hiy() - _psupplycabinet[0]->radius() - 2 * pplayer()->radius()));

		_printercount = 5;

		// A printer in the lower left
		_pprinter[0] = new cCritterPrinter(this);
		_pprinter[0]->moveTo(cVector(
			playfield().lox() + _pprinter[0]->radius() + 2 * pplayer()->radius(),
			playfield().loy() + _pprinter[0]->radius() + 2 * pplayer()->radius()));
		_pprinter[0]->assignPrinterID(PRINTER_ODIE);

		// A printer in the upper left
		_pprinter[1] = new cCritterPrinter(this);
		_pprinter[1]->moveTo(cVector(
			playfield().lox() + _pprinter[1]->radius() + 2 * pplayer()->radius(),
			playfield().hiy() - _pprinter[1]->radius() - 2 * pplayer()->radius()));
		_pprinter[1]->assignPrinterID(PRINTER_CUJO);

		// A printer in the lower right
		_pprinter[2] = new cCritterPrinter(this);
		_pprinter[2]->moveTo(cVector(
			playfield().hix() - _pprinter[2]->radius() - 2 * pplayer()->radius(),
			playfield().loy() + _pprinter[2]->radius() + 2 * pplayer()->radius()));
		_pprinter[2]->assignPrinterID(PRINTER_LASSIE);

		// A printer in the mid left
		_pprinter[3] = new cCritterPrinter(this);
		_pprinter[3]->moveTo(cVector(
			playfield().lox() + _pprinter[3]->radius() + 2 * pplayer()->radius(),
			playfield().hiy() - playfield().ysize()/2));
		_pprinter[3]->assignPrinterID(PRINTER_ASTRO);

		// A printer in the mid bottom
		_pprinter[4] = new cCritterPrinter(this);
		_pprinter[4]->moveTo(cVector(
			playfield().hix() - playfield().xsize()/2,
			playfield().loy() + _pprinter[4]->radius() + 2 * pplayer()->radius()));
		_pprinter[4]->assignPrinterID(PRINTER_CLIFFORD);


		break;

	default:
		break;
	}
}

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

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

void cGameHeroesOfCIS::initializeViewpoint(cCritterViewer *pviewer)
{
	/* The two args to setViewpoint are (directiontoviewer, lookatpoint).
	   Note that directiontoviewer points FROM the origin TOWARDS the viewer. */

	if (pviewer->is3D()) {

		//Direction to viewer is down a bit, and back off less than that.
		pviewer->setViewpoint(cVector3(0.0, -1.0, 2.0), _border.center());	
	}
	else {   //2D case.
		pviewer->setViewpoint(cVector::ZAXIS, _border.center());
	}
}

/*
 * Determines the message that will be printed out at the bottom of the window.
 */
CString cGameHeroesOfCIS::statusMessage()
{
	CString cStrStatusBar;
	int nUpdatesPerSecond;
	CString cStrUpdatespersecond;
	CString cStrWrench;
	CString cStrCount;
	CString cStrScore;
	CString cStrCollisionCount; //Usually leave empty

	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)";
		if (((CPopApp*)::AfxGetApp())->_timer.runningNearMinSpeed())
			cStrUpdatespersecond += " (Slower than Real Time)";
	}
	else
			cStrUpdatespersecond.Format("Animation is paused.");
	cStrScore.Format("Score: %d.", score() );
	cStrWrench.Format("Wrench: %d.", wrench());
//	cStrCollisionCount.Format("Collide-Checks: %d.", pcollider()->GetSize());
	int crittercount = _pbiota->count(RUNTIME_CLASS(cCritter));
#ifndef DONTCOUNTALLCRITTERS
	cStrCount.Format("Total Critters: %d.", crittercount);
#else //DONTCOUNTALLCRITTERS
	int bulletcount = _pbiota->count(RUNTIME_CLASS(cCritterBullet));
	crittercount -= bulletcount;
	if (visibleplayer()) /*Subtract off 1 for player as well. */
		crittercount -= 1;
	cStrCount.Format("Other Critters: %d.", crittercount);
#endif //DONTCOUNTALLCRITTERS
	cStrStatusBar = cStrScore + "  " + cStrWrench + "  " + cStrCount + "  " + cStrUpdatespersecond + 
		"  " + cStrCollisionCount; 
	return cStrStatusBar;
}

void cGameHeroesOfCIS::adjustGameParameters()
{
// (1) End the game if a printer explodes
	if (printerExploded() && !_gameover) //Printer has exploded and game's not over.
	{
		_gameover = TRUE;

		pplayer()->addScore(_scorecorrection); // So user can reach _maxscore 
		playSound("Pop");
		return;
	}
// (2) Perhaps do this to reseed the screen if rivals and props are gone.
	int othercrittercount = pbiota()->count(RUNTIME_CLASS(cCritter)) -
		pbiota()->count(RUNTIME_CLASS(cCritterBullet)) - 1;
		//Number of critters minus bullets minus player equals other critters.

// (3) Maybe check some other conditions.
	/* You might for instance have something like this:
	if (_level == 1 && score() > 100)
	{
		_level = 2;
		//Possibly delete some critters added in the constructor.
		seedCritters();
	}
	*/

}

void cGameHeroesOfCIS::drawBackground(cGraphics *pgraphics, int drawflags)
{
    //Draw the fillings of the boxes first, before critters.
	cRealBox2 playfieldfloor(_playfield);
	cRealBox2 statusboxfloor(_statusbox);

	playfieldfloor.pcolorstyle()->setEdged(FALSE);
	playfieldfloor.pcolorstyle()->setFilled(TRUE);
	playfieldfloor.draw(pgraphics, drawflags);

	statusboxfloor.pcolorstyle()->setEdged(FALSE);
	statusboxfloor.pcolorstyle()->setFilled(TRUE);
	statusboxfloor.draw(pgraphics, drawflags);
}

void cGameHeroesOfCIS::drawForeground(cGraphics *pgraphics, int drawflags)
{
//	cGame::drawForeground(pgraphics, drawflags);
	//Don't need the outer border box so don't call the base class drawForeground.
/* Draw the edges of the two boxes, letting them pop into 3D if pgraphics can show it. */
	_statusbox.pcolorstyle()->setEdged(TRUE);
	_statusbox.pcolorstyle()->setFilled(FALSE);
	_playfield.pcolorstyle()->setEdged(TRUE);
	_playfield.pcolorstyle()->setFilled(FALSE);
	_statusbox.draw(pgraphics, drawflags);
	_playfield.draw(pgraphics, drawflags);

}

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

//---------------- Player status methods------------

int cGameHeroesOfCIS::wrench()
{
	ASSERT(pplayer());
	return ((cCritterHeroesPlayer*)pplayer())->wrench();
}


//==================== cCritterWrenchStatusIcon ====================

cCritterWrenchStatusIcon::cCritterWrenchStatusIcon(cGame *pownergame):
cCritter(pownergame)
{
	// Make supply cabinets immobile and invincible.
	setFixedflag(TRUE);
	setShield(TRUE);

	cRealBox statusbox = ((cGameHeroesOfCIS*)pownergame)->statusbox();

	moveTo(cVector(statusbox.lox() + statusbox.xsize()/2,
		           statusbox.loy() + 2 * WRENCH_STATUS_ICON_RADIUS));

	setWrenchStatus(FALSE);
}

void cCritterWrenchStatusIcon::setWrenchStatus(BOOL status)
{
	if (status)
		setSprite(new cSpriteIcon(IDB_SPRING));
	else
		setSprite(new cSpriteIcon(IDB_BLANK));

	setRadius(WRENCH_STATUS_ICON_RADIUS);
}

//====================cCritterHeroesPlayer
cCritterHeroesPlayer::cCritterHeroesPlayer(cGame *pownergame):
cCritterPlayer(pownergame)
{
	_wrench = 0;
	_pwrenchicon = new cCritterWrenchStatusIcon(pownergame);

	//Set the listener
	setListener(new cListenerArrow());

	setMaxspeed(MAX_SPEED);

	setArmed(FALSE); // Don't allow player to shoot

	/* Constrain player movement to playfield. */
    setMoveBox(((cGameHeroesOfCIS*)pownergame)->playfield());

	/* Force player to point upwards. */
	setAttitudeToMotionLock(FALSE);
	setAttitudeTangent(cVector::YAXIS);
}

void cCritterHeroesPlayer::reset()
{
	cCritterPlayer::reset();

	_wrench = 0;
}

BOOL cCritterHeroesPlayer::collide(cCritter *pcritter)
{
	BOOL collideflag = cCritter::collide(pcritter);

	/* Handle collisions with supply cabinets. */
	if (collideflag && pcritter->IsKindOf(RUNTIME_CLASS(cCritterSupplyCabinet))) {
		_wrench = 1;
		//_pwrenchicon->setWrenchStatus(TRUE);
	}

	/* Handle collisions with printers. */
	if (collideflag && pcritter->IsKindOf(RUNTIME_CLASS(cCritterPrinter))) {
		cCritterPrinter *printer = (cCritterPrinter*)pcritter;
		if(printer->isBroken() && _wrench > 0)
		{
			printer->fixMe();
			_wrench = 0;
	     //_pwrenchicon->setWrenchStatus(FALSE);
			++_score;
		}
	}
	
	return collideflag;
}

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

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

//==================== cCritterPrintQueueTray ====================

cCritterPrintQueueTray::cCritterPrintQueueTray(cGame *pownergame):
cCritter(pownergame)
{
	// Make print queue tray immobile and invincible.
	setFixedflag(TRUE);
	setShield(TRUE);
}

/*
 * initializePrintQueueTray sets the tray's icon based on the printer
 * it is associated with, and places it a fixed distance below its
 * parent print queue.
 */
void cCritterPrintQueueTray::initializePrintQueueTray(printerName pID,
													  cVector queueposition)
{
	setTrayIcon(pID);
	moveTo(queueposition - cVector(0.0, PRINT_QUEUE_TRAY_OFFSET));
}

/*
 * setTrayIcon sets tray sprite based on printer.
 */
void cCritterPrintQueueTray::setTrayIcon(printerName pID)
{
	switch(pID) {
	case PRINTER_ODIE:
		setSprite(new cSpriteIcon(IDB_TRAY_ODIE));
		break;

	case PRINTER_CUJO:
		setSprite(new cSpriteIcon(IDB_TRAY_CUJO));
		break;

	case PRINTER_LASSIE:
		setSprite(new cSpriteIcon(IDB_TRAY_LASSIE));
		break;

	case PRINTER_ASTRO:
		setSprite(new cSpriteIcon(IDB_TRAY_ASTRO));
		break;

	case PRINTER_CLIFFORD:
		setSprite(new cSpriteIcon(IDB_TRAY_CLIFFORD));
		break;

	case PRINTER_DINO:
		setSprite(new cSpriteIcon(IDB_UFO));
		break;

	default:
		setSprite(new cSpriteIcon(IDB_FACE));
		break;
	}

	setRadius(PRINT_QUEUE_TRAY_RADIUS);
}

//==================== cCritterPrintQueue ====================

cCritterPrintQueue::cCritterPrintQueue(cGame *pownergame):
cCritter(pownergame)
{
	// Make print queues immobile and invincible.
	setFixedflag(TRUE);
	setShield(TRUE);

	// Set print-queue-specific variables.
	_pprintqueuetray = new cCritterPrintQueueTray(pownergame);
	_queue = 0;
	_statusbox = ((cGameHeroesOfCIS*)pownergame)->statusbox();
}

/*
 * initializePrintQueue positions the print queue based on the
 * printer it is associated with, and initializes the tray
 * icon as well.
 */
void cCritterPrintQueue::initializePrintQueue(printerName pID)
{
	positionPrintQueue(pID);
	_pprintqueuetray->initializePrintQueueTray(pID, position());
}

/*
 * positionPrintQueue positions the print queue based on printer.
 */
void cCritterPrintQueue::positionPrintQueue(printerName pID)
{
	Real lox = _statusbox.lox();
	Real loy = _statusbox.loy();
	Real xsize = _statusbox.xsize();
	Real ysize = _statusbox.ysize();

	switch(pID) {
	case PRINTER_ODIE:
		moveTo(cVector(
			lox + (1/4.0) * xsize,
			loy + (5/6.0) * ysize));
		break;

	case PRINTER_CUJO:
		moveTo(cVector(
			lox + (2/4.0) * xsize,
			loy + (5/6.0) * ysize));
		break;

	case PRINTER_LASSIE:
		moveTo(cVector(
			lox + (3/4.0) * xsize,
			loy + (5/6.0) * ysize));
		break;

	case PRINTER_ASTRO:
		moveTo(cVector(
			lox + (1/4.0) * xsize,
			loy + (3/6.0) * ysize));
		break;

	case PRINTER_CLIFFORD:
		moveTo(cVector(
			lox + (2/4.0) * xsize,
			loy + (3/6.0) * ysize));
		break;

	case PRINTER_DINO:
		moveTo(cVector(
			lox + (3/4.0) * xsize,
			loy + (3/6.0) * ysize));
		break;

	default:
		break;
	}
}

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

	switch (queue()) {
	case 0:
		setSprite(new cSpriteIcon(IDB_QUEUE_0));
		break;
	case 1:
		setSprite(new cSpriteIcon(IDB_QUEUE_1));
		break;
	case 2:
		setSprite(new cSpriteIcon(IDB_QUEUE_2));
		break;
	case 3:
		setSprite(new cSpriteIcon(IDB_QUEUE_3)); 
		break;
	case 4:
		setSprite(new cSpriteIcon(IDB_QUEUE_4)); 
		break;
	case 5:
		setSprite(new cSpriteIcon(IDB_QUEUE_5)); 
		break;
	case 6:
		setSprite(new cSpriteIcon(IDB_QUEUE_6)); 
		break;
	case 7:
		setSprite(new cSpriteIcon(IDB_QUEUE_7)); 
		break;
	case 8:
		setSprite(new cSpriteIcon(IDB_QUEUE_8)); 
		break;
	case 9:
		setSprite(new cSpriteIcon(IDB_QUEUE_9)); 
		break;
	case 10:
		setSprite(new cSpriteIcon(IDB_QUEUE_10)); 
		break;
	default:
		break;
	}
	
	setRadius(PRINT_QUEUE_RADIUS);
}

//==================== cCritterSupplyCabinet ====================

cCritterSupplyCabinet::cCritterSupplyCabinet(cGame *pownergame):
cCritter(pownergame)
{
	// Set critter-specific variables
	setSprite(pgame()->randomSprite(cGame::ST_SIMPLEPOLYGONS)); 
	setRadius(0.5);

	// Make supply cabinets immobile and invincible.
	setFixedflag(TRUE);
	setShield(TRUE);
}

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

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

//==================== cCritterPrinter ====================

cCritterPrinter::cCritterPrinter(cGame *pownergame):
cCritter(pownergame)
{
	//Make printers immobile and invincible.
	setFixedflag(TRUE);
	setShield(TRUE);

	// Set printer-specific variables
	_printerID = PRINTER_UNNAMED; 
	_pprintqueue = new cCritterPrintQueue(pownergame);
	_broken = FALSE;
	_exploded = FALSE;
}

void cCritterPrinter::assignPrinterID(printerName pID)
{
	_printerID = pID;
	_pprintqueue->initializePrintQueue(pID);
	setFixedSprite();
}

void cCritterPrinter::breakMe()
{
	if (!isBroken())
	{
		playSound("Explosion");
		_broken = TRUE;
		setBrokenSprite();
		setAge(0.0);
	}
}

void cCritterPrinter::fixMe()
{
	if (isBroken())
	{
		_broken = FALSE;
		setFixedSprite();
		setAge(0.0);
	}
}

void cCritterPrinter::explodeMe()
{
	if (!isExploded())
	{
		_exploded = TRUE;
		setSprite(new cSpriteIcon(IDB_EXPLODE3));
		setRadius(PRINTER_RADIUS);
	}

}
void cCritterPrinter::setBrokenSprite(){

	switch(printerID()) {
	case PRINTER_ODIE:
		setSprite(new cSpriteIcon(IDB_ODIE_BROKEN));
		break;

	case PRINTER_CUJO:
		setSprite(new cSpriteIcon(IDB_CUJO_BROKEN));
		break;

	case PRINTER_LASSIE:
		setSprite(new cSpriteIcon(IDB_LASSIE_BROKEN));
		break;

	case PRINTER_ASTRO:
		setSprite(new cSpriteIcon(IDB_ASTRO_BROKEN));
		break;

	case PRINTER_CLIFFORD:
		setSprite(new cSpriteIcon(IDB_CLIFFORD_BROKEN));
		break;

	case PRINTER_DINO:
		setSprite(new cSpriteIcon(IDB_GNARLY));
		break;

	default:
		setSprite(new cSpriteIcon(IDB_FACE));
		break;
	}

	setRadius(PRINTER_RADIUS);
}

void cCritterPrinter::setFixedSprite(){

	switch(printerID()) {
	case PRINTER_ODIE:
		setSprite(new cSpriteIcon(IDB_ODIE_OK));
		break;

	case PRINTER_CUJO:
		setSprite(new cSpriteIcon(IDB_CUJO_OK));
		break;

	case PRINTER_LASSIE:
		setSprite(new cSpriteIcon(IDB_LASSIE_OK));
		break;

	case PRINTER_ASTRO:
		setSprite(new cSpriteIcon(IDB_ASTRO_OK));
		break;

	case PRINTER_CLIFFORD:
		setSprite(new cSpriteIcon(IDB_CLIFFORD_OK));
		break;

	case PRINTER_DINO:
		setSprite(new cSpriteIcon(IDB_EARTH));
		break;

	default:
		setSprite(new cSpriteIcon(IDB_SUN));
		break;
	}

	setRadius(PRINTER_RADIUS);
}

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

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

	if (isBroken() && age() >= 1.0) {
		setAge(0.0);
		pprintqueue()->incQueue(1);
		if (pprintqueue()->queueOverflow()) {
			explodeMe();
		}
	}
	if (!isBroken() && age() >= 3.0) {
		setAge(0.0);
		pprintqueue()->decQueue(1);

		if (cRandomizer::pinstance()->randomReal(0, 1) > 0.75)
			breakMe();
	}
}
