/**********************************************************************

	Title :			Movement module
	Filename :		movement.c
	Author :		Thomas Szirtes
	Revision :		1.0

	Notes :			

	Copyright :		(C) SEGA Europe 1998

  **********************************************************************/

/*
 *		INCLUDES
 */
#include	"ftypes.h"
#include	"future.h"
#include	"sound.h"




/*--------------------------------------------------------------------------
 
  void MOVE_Reset( )
 
  Parameters:
 	MOVESHIP	*ship		-	ship movement data - holds data for physics
 
  Returns:
 
  Notes:
 	Resets the ship movement code
 
 --------------------------------------------------------------------------*/

void MOVE_Reset( SHIP *ship	)
{
	MOVESHIP		*move;

	move	=	&ship->move;

	move->position.y		=	0.f;
	move->velocity.x		=	0.f;
	move->velocity.y		=	0.f;
	move->velocity.z		=	0.f;
	move->yaw				=	0.f;
	move->pitch				=	0.f;
	move->acceleration		=	0.f;
	move->torque_yaw		=	0.f;
	move->torque_pitch		=	0.f;
	move->roll				=	0.f;
}



/*--------------------------------------------------------------------------
 
  void MOVE_Calculate( PERIPH_DATA	*per, SHIP *ship )

  Parameters:
 	PERIPH_DATA	*per		-	peripheral data from user or computer ai
 	SHIP	*ship			-	ship object
 
  Returns:
 
   Notes:
 	Takes the peripheral commands and applies the necessary forces to the
  specified ship taking into account the physical contraints specified by
  the ship attribute data.
 
  --------------------------------------------------------------------------*/

void MOVE_Calculate(
					PERIPH_DATA		*per,			/* peripheral data */
					SHIP			*ship
					)
{
	Float		delta;
	Float		fcoef;
	MOVESHIP	*move;
	ATTRSHIP	*attr;
	float		t1,t2;

	move		=	&ship->move;
	attr		=	ship->attr;

	/* Peripheral mapping - normal to space ship */
	/*		Forward/Back		->		Pitch down/up */
	/*		Yaw Left/Right		->		Yaw Left/Right */
	/*		Fire				->		Thrust */
	/*		Open				->		Brake */
	/*		Strafe Left/Right	->		Air Brake left/Right */

	/* ----- CONVERT */
	move->torque_pitch	=	(Float)(per->pitch_up_down) * attr->max_ship_pitch;
	move->torque_yaw	=	(Float)(per->yaw_left_right) * -attr->max_ship_yaw;
	move->acceleration	=	(Float)(per->fire) * (attr->max_ship_accel/PERIPHERAL_SCALE);	

	/* ----- YAW */
	/* calculate yaw - but cap turning response speed */
	delta	=	move->torque_yaw - move->vel_yaw;		
	if	(delta>attr->response_yaw)
		move->vel_yaw	+=	attr->response_yaw;
	else if (delta<-attr->response_yaw)
		move->vel_yaw	-=	attr->response_yaw;
	else 
		move->vel_yaw	=	move->torque_yaw;	

	
	/* convert to roll */
	move->roll		=	move->vel_yaw * 30.f;
	move->yaw		+=	move->vel_yaw;

	/* ----- PITCH */
	/* calculate pitch - but cap turning response speed */
	delta	=	move->torque_pitch - move->vel_pitch;

	if	(delta>attr->response_pitch)
		move->vel_pitch	+=	attr->response_pitch;
	else if (delta<-attr->response_pitch)
		move->vel_pitch	-=	attr->response_pitch;
	else 
		move->vel_pitch	=	move->torque_pitch;
		
	move->pitch		=	move->vel_pitch * 30.f;


	/* ----- DIRECTION VECTOR */
	move->direction.x	= njSin(NJM_DEG_ANG(move->yaw));
	move->direction.y	= njSin(NJM_DEG_ANG(move->pitch));
	move->direction.z	= njCos(NJM_DEG_ANG(move->yaw));
	
	/* calculate velocity */
	move->velocity.x	+=	move->direction.x * move->acceleration;
	move->velocity.y	+=	move->direction.y * move->acceleration;
	move->velocity.z	+=	move->direction.z * move->acceleration;
	
	move->velmag		=	njScalor(&move->velocity);

	/* Calculate friction coeficient and velocity */
	fcoef				=	(attr->max_ship_accel/attr->max_ship_velocity);
	move->velocity.x	-=	fcoef * move->velocity.x;
	move->velocity.y	-=	fcoef * move->velocity.y;
	move->velocity.z	-=	fcoef * move->velocity.z;

	/* ----- PROJECTED POSITION */
	move->projected.x	=	move->position.x + move->velocity.x;
	move->projected.y	=	move->position.y + move->velocity.y;
	move->projected.z	=	move->position.z + move->velocity.z;

	if (move->projected.y>600.f && move->velocity.y>0) { move->velocity.y = 0; move->projected.y=600.f; }

	/* Just a little added in for the demo - this stops the player moving outside the island */
	t1	=	(64*GRID_SIZE)-move->projected.x;
	t2	=	(64*GRID_SIZE)-move->projected.z;

	if ( njSqrt( (t1*t1)+(t2*t2) ) > (50*GRID_SIZE) )
	{
		move->projected.x	=	move->position.x;
		move->projected.y	=	move->position.y;
		move->projected.z	=	move->position.z;
		move->velocity.x	=	0.f;
		move->velocity.y	=	0.f;
		move->velocity.z	=	0.f;

	}

}



/*--------------------------------------------------------------------------

  void MOVE_CheckCollision( SHIP *ship )
 
  Parameters:
 	ship		Ship structure
 
  Returns:
 
  Notes:
 	Checks the projected position of the ship passed - and updates
  the velocities to take into account the physics of hitting any object
 
  --------------------------------------------------------------------------*/

int MOVE_CheckCollision( SHIP *ship )
{
	int					rtn;
	MOVESHIP			*move;
	Float				s;				/* Velocity scalar */
	register Float		f;				/* temporary calculation register */
	NJS_VECTOR			v;				/* Velocity direction */
	NJS_VECTOR			coll;			/* Collision Normal */

	rtn =0;
	move		=	&ship->move;
	/* Collision for Floor */
/* COLLISION DISABLED */
/*		rtn	=	COLLISION_TestFloor	(move->projected,5.f,&coll); */
	rtn	=	COLLIDE_Floor( &move->projected, 5.f, &coll);


	if (rtn==0)
	{
		/* Collision for Buildings */
		/* pass it collision normal vector to fill out */
/* COLLISION DISABLED */
/*				rtn	=	COLLISION_TestBuilding	(move->projected,5.f,&coll); */
		if (map.map[ship->current.i][ship->current.j].inst != 0xffff)
		{
			rtn	=	COLLIDE_Building ( &move->projected, map.map[ship->current.i][ship->current.j].inst ,&coll);
		}
	}

	/* This is the equation for handling collision physics - basically */
	/* we apply a collsion normal to a velocity vector and calculate the */
	/* resultant reflection velocity vector  */
	if (ship->flags&SHIP_FLAG_USER)
	{
#ifdef SOUND_ENABLE
		if(rtn!=0)
			SOUND_ShieldOn(); 
		else 
			SOUND_ShieldOff();
#endif
	}
	
	if (rtn!= 0)
	{
		/* R  = 2N(N.V)-V; express as R = fN-V, where f=2(N.V) */
		/* coll must be normalized */
		v.x					=	move->velocity.x;
		v.y					=	move->velocity.y;
		v.z					=	move->velocity.z;
		s					=	njUnitVector(&v);					
		f					=	2.0f * njInnerProduct( &coll, &v );
		move->velocity.x	-=	s*(f*coll.x); 
		move->velocity.y	-=	s*(f*coll.y); 
		move->velocity.z	-=	s*(f*coll.z); 
	}

	return rtn;

}




/*--------------------------------------------------------------------------
 
  void MOVE_Update( SHIP *ship, Uint8 n )

  Parameters:
 	ship		Ship movement structure
 
  Returns:
 
  Notes:
 	Updates the actual position of the ship quickly
 
 --------------------------------------------------------------------------*/
extern SHIP		*shipdb		[MAX_SHIPS];

void MOVE_Update( SHIP *ship, Uint8 n )
{
	MOVESHIP		*move;
	GRIDPOS			old;
	SHIP			*sh,*tsh;

	sh				=	ship;
	move			=	&ship->move;

	old.i			=	ship->current.i;
	old.j			=	ship->current.j;
	old.h			=	ship->current.h;

	ship->current.i	=	P2GRID(	(move->position.x = move->position.x + move->velocity.x)+64.f)&0x7f;
	ship->current.j	=	P2GRID(	(move->position.z = move->position.z + move->velocity.z)+64.f)&0x7f;
	ship->current.h	=	(Sint16)( move->position.y = move->position.y + move->velocity.y );


	/* Update map too... has position changed? */

	if ((old.i != ship->current.i) || (old.j != ship->current.j))
	{
		if (map.map[old.i][old.j].ship!=NO_SHIP_ID)
		{

			/*------- remove old copy */
			sh	=	shipdb[map.map[old.i][old.j].ship];
			
			/* check if in overflow list or not */
			if (map.map[old.i][old.j].ship == n) 
			{	
				/* no = simple delete */
				map.map[old.i][old.j].ship	=	sh->next_ship;
				sh->next_ship	=	NO_SHIP_ID;
			}
			else
			{
				/* Yes.. then remove from overflow list */
				tsh	=	sh;
				while (tsh->next_ship != n && tsh->next_ship != NO_SHIP_ID)
				{
					tsh	=	shipdb[tsh->next_ship];
				}
				tsh->next_ship	=	sh->next_ship;
				sh->next_ship	=	NO_SHIP_ID;
			}
		}

		/*--------- store new copy */
		if ( map.map[ship->current.i][ship->current.j].ship == NO_SHIP_ID)
		{
			/* no = simple add */
			map.map[ship->current.i][ship->current.j].ship =	n;
		}
		else
		{
			/* yes - add to end of list */
			tsh	=	sh	=	shipdb[map.map[ship->current.i][ship->current.j].ship];
			while(tsh->next_ship != NO_SHIP_ID)
			{
				tsh	=	shipdb[tsh->next_ship];
			}
			tsh->next_ship	=	n;
		}

	}

}
 