// ObjTools
//


#ifndef __ObjTools__
#define __ObjTools__

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

#include "FastMath.h"


//////////////////////////////////////////////////////////////////////////////
// Trajectory class - uses fixed point math
// Defines position and movement of an object
class Trajectory {
    public:
    	Trajectory( FixedPoint Fxp=0, FixedPoint Fyp=0 );
	Trajectory( const Trajectory& t );

	void randomDir( FixedPoint Fspeed );
    	void towards( FixedPoint Fxp, FixedPoint Fyp, FixedPoint Fspeed );
    	void travel( Angle angle, FixedPoint Fspd ); // set direction/speed
		
	void setFpos( FixedPoint Fxp, FixedPoint Fyp )
		{ 
		VFx = Fxp;
		VFy = Fyp;
		}
		
	void setFvel( FixedPoint Fvx, FixedPoint Fvy ) 
		{
		VFxvel = Fvx;
		VFyvel = Fvy;
		}

	void addVel( FixedPoint Fvx, FixedPoint Fvy )
		{
		VFxvel += Fvx;
		VFyvel += Fvy;
		}

	void move();
	void moveNoWrap();


	int  x() const { return FP2INT(VFx); }
	int  y() const { return FP2INT(VFy); }
	double xvel() const { return FP2FLOAT(VFxvel); }
	double yvel() const { return FP2FLOAT(VFyvel); }


	// public for speed
	FixedPoint	VFx, VFy;
	FixedPoint	VFxvel, VFyvel;

	// wrap around co-ordinates
	static void setFwrap( FixedPoint Fx, FixedPoint Fy)
		{
		VFmaxx = Fx;
		VFmaxy = Fy;
		}	
    private:
    	static FixedPoint VFmaxx;
    	static FixedPoint VFmaxy;
    	
    };

inline Trajectory::Trajectory( FixedPoint Fxp, FixedPoint Fyp ) 
		: VFxvel(0), VFyvel(0)
	{
	setFpos( Fxp, Fyp );
	};

inline Trajectory::Trajectory( const Trajectory& t ) 
		: VFx(t.VFx), VFy(t.VFy), VFxvel(t.VFxvel), VFyvel(t.VFyvel)
	{};

inline void Trajectory::randomDir( FixedPoint Fspeed )
	{
	travel( (rand()>>2), Fspeed );
	}

inline void Trajectory::travel( Angle angle, FixedPoint Fspeed )
	{
	VFxvel = FPMULT(FastMath::Fcos(angle),Fspeed);
	VFyvel = FPMULT(FastMath::Fsin(angle),Fspeed);
	}

// set the trajectory towards point (Fxp,Fyp)
inline void Trajectory::towards( FixedPoint Fxp, FixedPoint Fyp, 
				 FixedPoint Fspeed )
	{
	FixedPoint Fdx,Fdy;
	int dist;
	
	Fdx = Fxp - VFx;
	Fdy = Fyp - VFy;
	dist = (int)sqrt( FP2INT(FPMULT(Fdx,Fdx)+FPMULT(Fdy,Fdy)) );

	VFxvel = FPMULT(Fspeed,Fdx)/dist;
	VFyvel = FPMULT(Fspeed,Fdy)/dist;
	}

// make a move towards where ever we're going, with screen wrap-around
inline void Trajectory::move()
	{
   	VFx += VFxvel;
	if (VFx < 0) VFx += VFmaxx;
	else if (VFx >= VFmaxx) VFx -= VFmaxx;

	VFy += VFyvel;
	if (VFy < 0) VFy += VFmaxy;
	else if (VFy >= VFmaxy) VFy -= VFmaxy;
	}

inline void Trajectory::moveNoWrap()
	{
   	VFx += VFxvel;
	VFy += VFyvel;
	}


//////////////////////////////////////////////////////////////////////////////
// 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
