// CritterWall.h: interface for the cCritterWall and cCritterBullet classes.
//
//////////////////////////////////////////////////////////////////////

#ifndef CRITTERWALL_H
#define CRITTERWALL_H

#include "critter.h"

class cCritterWall : public cCritter
{
DECLARE_SERIAL(cCritterWall);
public:
	static Real THICKNESS;
	static Real CORNERJIGGLE;/* To keep someone from impossibly bouncing up and down on a corner,
		 we jiggle the bounces off corners by a small random amount.*/
	static COLORREF WALLFILLCOLOR; //It's set in static.cpp to CN_LIGHTGRAY
protected:
//Serialized fields
	cVector _enda, _endb;
	Real _radiustangent, _radiusnormal; //Half the rectangle's edge in the respective directions.
	COLORREF _defaultfillcolor;
//Helper Methods
	cVector globalToLocalVector(const cVector &globalvec);
	cVector localToGlobalVector(const cVector &localvec);
	cVector globalToLocalPosition(const cVector &globalpos);
	cVector localToGlobalPosition(const cVector &localpos);
	int outcode(const cVector &globalpos); 
	int outcodeLocal(const cVector &localpos); 
	Real distanceToLocal(const cVector &localpos); 
	Real distanceToLocal(const cVector &localpos, int outcode); 
public:
	cCritterWall(cGame *pownergame = NULL);
	cCritterWall(const cVector &enda, const cVector &endb,
		Real thickness = cCritterWall::THICKNESS, cGame *pownergame=NULL);
		/* For some reason it doesn't work well to feed in the cGame *pownergame argument
		to a wall, the result seems to be to make the wall get drawn twice.  So we create
		our walls without a cGame* argument and then call the cGame::add(pcritterwall)
		on the newly made wall. */
	virtual void copy(cCritter *pcritter);
//Mutators
	void setEndsAndThickness(const cVector &enda, const cVector &endb, Real thickness);
	void setEnds(const cVector &enda, const cVector &endb);
	void setThickness(Real thickness);
	void setCorners(const cVector &leftbottom, const cVector &righttop); /* This makes a 
		vertical or a horizontal wall using the arguments as diagonally opposite corners of the 
		wall area. The wall willbe thought of as oriented so that the ends are at either end of
		the longer axis and the thickness is the shorter axis. It doesn't matter which pair of 
		corners you feed in, the method just uses the corners to find which rectangle you're 
		talking about. */
	void mutate(int mutationflags, Real mutationstrength); /* This is exactly the same as the
		base class cCritter::mutate except that we comment out the line, which would mutate the 
		sprite. We don't want to mutate a wall's sprite. */
	void setFillColor(COLORREF fillcolor);
//Serialize methods
	virtual void Serialize(CArchive &ar);
//Overloads
	int dragTo(const cVector &newposition, Real dt); /* Overload this so as not to change
		velocity as I normally want my walls to be stable and not drift after being dragged. */
	virtual BOOL collide(cCritter *pcritter);
	virtual int collidesWith(cCritter *pcritterother); /* Overload to rule out possibliity of 
		all/wall collision,	even if they aren't fixed. */
	virtual Real distanceTo(const cVector &vpoint);
	virtual int clamp(const cRealBox &border);
	virtual void setWrapflag(int wrapflag){}//Don't allow _wrapflag to change from cCritter::WRAP.
//Special method
	virtual BOOL blocks(const cVector& start, const cVector& end); /* Returns 
		TRUE if the wall blocks a line drawn from start to end. */
};

#endif //CRITTERWALL_H

