// ObjTools
//


#ifndef __ObjTools__
#define __ObjTools__

#include <stdlib.h>
#include <math.h>
#include <vgagl.h>

#include "FastMath.h"

//////////////////////////////////////////////////////////////////////////////
// Trajectory class - defines an object's movement
class Trajectory {
    public:
    	Trajectory( int xp=0, int yp=0 );
	Trajectory( const Trajectory& t );

	void randomDir( double speed );
    	void towards( int xp, int yp, double speed );
    	void travel( int angle, double spd ); // set direction/speed
	void setPos( double xp, double yp ) { Vx=xp; Vy=yp; }
	void setVel( double vx, double vy ) { Vxvel=vx; Vyvel=vy; }
	void addVel( double vx, double vy ) { Vxvel+=vx; Vyvel+=vy; }
	void move();
	void moveNoWrap();

	double  x() const { return Vx; }
	double  y() const { return Vy; }
	double xvel() const { return Vxvel; }
	double yvel() const { return Vyvel; }

	double speed() const { return sqrt(Vxvel*Vxvel+Vyvel*Vyvel); }	

    protected:
	double	Vxvel, Vyvel;
	double	Vx, Vy;

    };

inline Trajectory::Trajectory( int xp, int yp ) 
		: Vx(xp), Vy(yp), Vxvel(0), Vyvel(0)
	{};

inline Trajectory::Trajectory( const Trajectory& t ) 
		: Vx(t.Vx), Vy(t.Vy), Vxvel(t.Vxvel), Vyvel(t.Vyvel)
	{};

inline void Trajectory::randomDir( double speed )
	{
	travel( (rand()>>2)%360, speed );
	}

inline void Trajectory::travel( int angle, double speed )
	{
	Vxvel = FastMath::cos(angle)*speed;
	Vyvel = FastMath::sin(angle)*speed;	
	}

// set the trajectory towards point (xp,yp)
inline void Trajectory::towards( int xp, int yp, double speed )
	{
	double dx,dy,dist;
	
	dx = xp - Vx;
	dy = yp - Vy;
	dist = sqrt(dx*dx + dy*dy);
	
	Vxvel = speed*dx/dist;
	Vyvel = speed*dy/dist;
	}

// make a move towards where ever we're going, with screen wrap-around
inline void Trajectory::move()
	{
   	Vx += Vxvel;
	while (Vx < 0) Vx += (double)WIDTH;
	while (Vx > WIDTH) Vx -= (double)WIDTH;
	
	Vy += Vyvel;
	while (Vy < 0) Vy += (double)HEIGHT;
	while (Vy > HEIGHT) Vy -= (double)HEIGHT;
	}

inline void Trajectory::moveNoWrap()
	{
   	Vx += Vxvel;
	Vy += Vyvel;
	}


//////////////////////////////////////////////////////////////////////////////
// Fast Trajectory class - uses fixed point math
// Eventually all of the game's floating point math will be replaced with
// fixed point.  This class is mostly to test how this can be done.
#define FT_MULT		64
#define	FT_SHIFT	6
#define FT_HSHIFT	3
class FastTrajectory {
    public:
    	FastTrajectory( int xp=0, int yp=0 );
	FastTrajectory( const FastTrajectory& t );

	void randomDir( double speed );
    	void towards( int xp, int yp, double speed );
    	void travel( int angle, double spd ); // set direction/speed
	void setPos( int xp, int yp )
		{ 
		Vx=(int)(xp*FT_MULT);
		Vy=(int)(yp*FT_MULT);
		}
		
	void setVel( double vx, double vy ) 
		{ 
		Vxvel=(int)(vx*FT_MULT); 
		Vyvel=(int)(vy*FT_MULT); 
		}
	
	void addVel( double vx, double vy )
		{
		Vxvel+=(int)(vx*FT_MULT);
		Vyvel+=(int)(vy*FT_MULT);
		}
	
	void move();
	void moveNoWrap();

	int  x() const { return Vx>>FT_SHIFT; }
	int  y() const { return Vy>>FT_SHIFT; }
	double xvel() const { return (double)Vxvel/FT_MULT; }
	double yvel() const { return (double)Vyvel/FT_MULT; }

	//double speed() const { return sqrt(Vxvel*Vxvel+Vyvel*Vyvel); }	

    protected:
	int	Vxvel, Vyvel;
	int	Vx, Vy;
	
    };

inline FastTrajectory::FastTrajectory( int xp, int yp ) 
		: Vxvel(0), Vyvel(0)
	{
	setPos(xp,yp);
	};

inline FastTrajectory::FastTrajectory( const FastTrajectory& t ) 
		: Vx(t.Vx), Vy(t.Vy), Vxvel(t.Vxvel), Vyvel(t.Vyvel)
	{};

inline void FastTrajectory::randomDir( double speed )
	{
	travel( (rand()>>2)%360, speed );
	}

inline void FastTrajectory::travel( int angle, double speed )
	{
	Vxvel = (int)(FastMath::cos(angle)*speed*FT_MULT);
	Vyvel = (int)(FastMath::sin(angle)*speed*FT_MULT);
	}

// set the trajectory towards point (xp,yp)
inline void FastTrajectory::towards( int xp, int yp, double speed )
	{
	int dx,dy,dist;
	
	dx = xp<<FT_SHIFT - Vx;
	dy = yp<<FT_SHIFT - Vy;
	dist = (int)sqrt( ((dx*dx+dy*dy)>>FT_SHIFT)>>FT_SHIFT );
	
	Vxvel = (int)(speed*dx/dist);
	Vyvel = (int)(speed*dy/dist);
	}

// make a move towards where ever we're going, with screen wrap-around
inline void FastTrajectory::move()
	{
   	Vx += Vxvel;
	while (Vx < 0) Vx += WIDTH>>FT_SHIFT;
	while (Vx > WIDTH>>FT_SHIFT) Vx -= WIDTH>>FT_SHIFT;
	
	Vy += Vyvel;
	while (Vy < 0) Vy += HEIGHT>>FT_SHIFT;
	while (Vy > HEIGHT>>FT_SHIFT) Vy -= HEIGHT>>FT_SHIFT;
	}

inline void FastTrajectory::moveNoWrap()
	{
   	Vx += Vxvel;
	Vy += Vyvel;
	}


//////////////////////////////////////////////////////////////////////////////
// Define an object's life
class Life { 
    public:

	Life(int t) : Vtime(t), Valive(1) {};    
    	Life() : Vtime(0), Valive(0) {};

	inline int	isAlive() const 
				{ return Valive; }
	inline void	revive( int lifeSpan=0 ) 
				{ Valive=1; Vtime = lifeSpan; }
	inline virtual  void	die() 
				{ Valive=0; Vtime=0; }
	
	// give object a fixed amount of time to live..
	inline void	setTime( int time ) 
				{ 
				Vtime = time; 
				if (Vtime) Valive=1;
				}

	// if alive, timeLeft of 0 means infinite life span	
	inline int	timeLeft() const { return Vtime; }

    	inline void     tick()
    		{
    		if (Vtime)
    			{
    			Vtime--;
    			if (!Vtime) die();
    			}
		}
		
    private:
    	int 	Valive;
	int	Vtime;
    };

#endif
