// Game.cpp: implementation of the cGame class and children.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "gamedambuilder.h"
#include "critterarmed.h"
#include "critterwall.h"
#include "force.h"
#include "listener.h"
#include "pop.h" //for playSound
#include "popview.h"
#include "spritebubble.h"
#include "critterviewer.h"
#include "graphicsopengl.h"

IMPLEMENT_SERIAL( cGameDambuilder, cGame, 0);
IMPLEMENT_SERIAL( cCritterDamFloat, cCritter, 0);
IMPLEMENT_SERIAL( cCritterDamPlayer, cCritterArmedPlayer, 0);
IMPLEMENT_SERIAL( cCritterDamWall, cCritterWall, 0);
IMPLEMENT_SERIAL( cCritterDamPlayerBullet, cCritterBullet, 0);

//#define DAMPLAYERGRAVITY
/* If we define this in, then the player will be subject to gravity.  You will only notice
this with the ListenerCar or ListenerSpaceship control.  Car won't look good, as it
will be confusing when the car is falling backwards and it thinks its in reverse. */

Real cGameDambuilder::WALLTHICKNESS = 0.4;

//#define DEBUGDAM
	/* Turn on DEBUGDAM to turn off the dam walls. */

#define STARTIN2D
	/* Turn on STARTIN2D to start in 2D, otherwise start in 3D. */
//==============================cGameDambuilder=======
cGameDambuilder::cGameDambuilder()
{
	_menuflags &= ~cGame::MENU_SHIELD;
		/* Default _menuflags from cGame has hopper off, autoplay off.
			We don't use the shield control in the standard game as nobody is
			shooting at us. */
#ifdef DAMPLAYERGRAVITY
	_menuflags |= cGame::MENU_HOPPER; 
		// The Hopper may be interesting if player has gravity.
#endif //DAMPLAYERGRAVITY
//Pick the cursor tools.
	//_arrayHCURSOR has only the _hCursorArrow inherited from cGame.
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorPin);
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorDragger);
	_arrayHCURSOR.Add(((CPopApp*)::AfxGetApp())->_hCursorReplicate);
//Initialize other fields
	_border.set( 25, 35) ; 
//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. */
	_spritetype = cGame::ST_SIMPLEPOLYGONS;
	setWrapflag(cCritter::WRAP);
	_seedcount = cGame::COUNTLARGE;
//Set the player 
	setPlayer(new cCritterDamPlayer());
//Put in some walls in the constructor.
#ifndef DEBUGDAM
	new cCritterDamWall( cVector(-4, 2),	cVector(3, -2), cGameDambuilder::WALLTHICKNESS, this);
	new cCritterDamWall( cVector(1.5, -2),	cVector(6, 0.3), cGameDambuilder::WALLTHICKNESS, this);
	new cCritterDamWall( cVector(-5, 0),	cVector(-5, 9), cGameDambuilder::WALLTHICKNESS, this);
	new cCritterDamWall( cVector(8, -2),	cVector(12, -3), cGameDambuilder::WALLTHICKNESS, this);
	new cCritterDamWall( cVector(-8, -4),	cVector(-6, -3), cGameDambuilder::WALLTHICKNESS, this);
	new cCritterDamWall( cVector(-9, -8),	cVector(-3, -3), cGameDambuilder::WALLTHICKNESS, this);
#else //DEBUGDAM is true
	_seedcount = 0;
#endif //DEBUGDAM
}

void cGameDambuilder::seedCritters()
{
 	_pbiota->purgeNonPlayerNonWallCritters(); /* Clean out all critters but leave 
		player and	walls. */
	for (int i=0; i < _seedcount; i++)
		new cCritterDamFloat(this);
}

void cGameDambuilder::initializeView(CPopView *pview)
{
	cGame::initializeView(pview); 
		/* Good idea to call the baseclass method or you
		might leave out something important that it does,
		possibly resetting something that was changed
		by a different games. */
	pview->setCursor(((CPopApp*)::AfxGetApp())->_hCursorDragger);
#ifdef STARTIN2D
	pview->setUseBackgroundBitmap(TRUE);
#else //not STARTIN2D means Start in 3D with
	pview->setUseBackgroundBitmap(FALSE);
	pview->setUseSolidBackground(FALSE);
	pview->setGraphicsClass(RUNTIME_CLASS(cGraphicsOpenGL));
	pview->pviewpointcritter()->setListener(new cListenerViewerRide()); //Ride the player.
#endif
}

void cGameDambuilder::initializeViewpoint(cCritterViewer *pviewer)
{
	cGame::initializeViewpoint(pviewer); /* No overload.  Note that you don't actually
		care about this call if you plan to ride the player, as then the viewpoint is
		set by the player. */
}

//=====================cCritterDamFloat===========

cCritterDamFloat::cCritterDamFloat(cGame *pownergame):
cCritter(pownergame)
{
	if (pgame())
		setSprite(pgame()->randomSprite(pgame()->spritetype()));
	randomize(cCritter::MF_POSITION | cCritter::MF_VELOCITY); 
	addForce(new cForceEvadeBullet());
	addForce(new cForceGravity()); //Uses default gravity strength 25.
	addForce(new cForceDrag()); //Uses default friction strength 0.5.
	setRadius(0.6);
	setDensity(2.0); 
	setMaxspeed(20.0);
}

//===================cCritterDamPlayer================
cCritterDamPlayer::cCritterDamPlayer(cGame *pownergame):
cCritterArmedPlayer(pownergame)
{
	setListener(new cListenerScooter());
 	setBulletClass(RUNTIME_CLASS(cCritterDamPlayerBullet));
	setWaitShoot(2.0*cCritterArmed::WAITSHOOT); //Don't shoot as fast as usual.
	setMaxspeed(cCritter::MAXSPEED * 5.0);
	setAbsorberflag(TRUE); //Keeps player from being buffeted about.
#ifdef DAMPLAYERGRAVITY
	setListenerAcceleration(80.0); //So Car or Spaceship can overcome gravity
	addForce(new cForceGravity()); //Uses default gravity strength 25.
	addForce(new cForceDrag()); //Uses default friction strength 0.5.
#endif //DAMPLAYERGRAVITY
}

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

//====================cCritterDamPlayerBullet==================
cCritterDamPlayerBullet::cCritterDamPlayerBullet()
{
	setRadius(2.0*cCritter::BULLETRADIUS); //Make bigger than usual.
	addForce(new cForceGravity()); //Uses default gravity strength 25.
	addForce(new cForceDrag()); //Uses default friction strength 0.5.
}

cCritterDamPlayerBullet::isTarget(cCritter *pcritter)
{
	return cCritterBullet::isTarget(pcritter) && 
		pcritter->GetRuntimeClass() != RUNTIME_CLASS(cCritterDamWall);
}
