/*****************************************************************************
Name            :   actor.cpp
Title           :   Actor
C Author        :   Stel Michael
Created         :   9 Sept 1993

Copyright       :   1992 by VideoLogic Limited. All rights reserved.
			No part of this software, either material or conceptual
			may be copied or distributed, transmitted, transcribed,
			stored in a retrieval system or translated into any
			human or computer language in any form by any means,
			electronic, mechanical, manual or other-wise, or
			disclosed to third parties without the express written
			permission of VideoLogic Limited, HomePark Estate,
			King's Langley, Hertfordshire, WD4 8LZ, U.K.
												 
Platform 		: Microsoft Visual C++ V2		  
*****************************************************************************/

#define Cplusplus 

#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include "sgl.h"
#include "craft.h"                                    
#include "math.h" 
#include "sclist.h"
#include "actor.h"
#include "player.h"
#include "autoobj.h"

#define _LOW_LEVEL	30.0f
#define _GROUND_LEVEL	-20.0f

extern  float jx;
extern  float jy;
extern	int	lp;
extern	int	rp;  
extern	int sp;    

extern int	tinterval;


LoneObject::LoneObject(int trm,int grp,float startpos[3],float startori[3],	float startvel) : BasicObject(trm,grp) 
{	                
	pos[0]=startpos[0];
	pos[1]=startpos[1];
	pos[2]=startpos[2];

	ori[0]=startori[0];		
	ori[1]=startori[1];
	ori[2]=startori[2];

	vel=startvel;
}


void LoneObject::Process()
{      
    if (status==HITIT)
		status=DEAD;
   
	sgl_modify_transform(tran,TRUE);
	sgl_translate(pos[0],pos[1],pos[2]);	
} 
                

void ControlledObject::Process()
{   
    if (status==HITIT)
    	status=DEAD;

	if (UnderControl) 
	{             
		SetInputs(jx,jy,lp,rp,sp);
    }
                
	sgl_modify_transform(tran,TRUE);	
	sgl_translate(pos[0],pos[1],pos[2]);
}


ControlledObject::ControlledObject(int trm,int grp,int trm2,int gcunt2,float startpos[3],float startori[3],float startvel,int Control):LoneObject(trm,grp,startpos,startori,startvel)
{                                                      
	UnderControl=Control;
	group2=gcunt2; 
	tran2=trm2;
}


ControlledCraft::ControlledCraft(int trm,int grp,int trm2,int gcunt2,float startpos[3],float startori[3],float startvel,int Control):ControlledObject(trm,grp,trm2,grp2,startpos,startori,startvel,Control)
{
}


AutomatedCraft::AutomatedCraft(int trm,int grp,float startpos[3],float startori[3],float startvel,Player *Target,int Cam):LoneObject(trm,grp,startpos,startori,startvel)
{ 
	CurrentTarget=Target;
	aCam = Cam;
}


void AutomatedCraft::Process()
{
	float Dz,Dx;

    if (status==HITIT)
    	status=DEAD;

    AdjustDirection();

	if (ori[2]>MAXROLL_ANG)
		ori[2]=MAXROLL_ANG;
	
	if (ori[2]<-MAXROLL_ANG)
		ori[2]=-MAXROLL_ANG;

	if (ori[0]>MAXELEV_ANG) 
		ori[0]=MAXELEV_ANG;
	if (ori[0]<-MAXELEV_ANG)
		ori[0]=-MAXELEV_ANG;

	/*	adjust y angle giving craft's forward direction */
	
	ori[1]-=(ori[2]/4.0f);

	/*	adjust velocity of craft and position craft at it's new position */
	
	Dz = (float) cos(ori[1]);	    
	Dx = (float) sin(ori[1]);
	pos[2] += (vel*Dz);
	pos[0] += (vel*Dx);
	pos[1] -= (vel*((float) sin(-ori[0])));

	sgl_modify_transform(tran,TRUE);
	sgl_translate(pos[0],pos[1],pos[2]);

	if (!aCam)
	{
		sgl_rotate(sgl_y_axis,ori[1]);  
		sgl_rotate(sgl_x_axis,-ori[0]);
		sgl_rotate(sgl_z_axis,ori[2]);
	}
}


void AutomatedCraft::AdjustDirection()
{   
    float TargetDir[3],targetDis;  
    float z1,x1,z2,x2,a,b,d;  
    float magxz;
    float ang_diff;
	float Dx,Dz,dp;
	float damper,ori_change;
	float randNum;
    float disUnder; 
    float *TargetPos;
	
	int i;
 
	TargetPos=CurrentTarget->GetPos();
    
	for  (i=0;i<3;i++)
		TargetDir[i] = TargetPos[i]-pos[i];
                                                                   
	targetDis = (float) sqrt(TargetDir[0]*TargetDir[0]+TargetDir[1]*TargetDir[1]+TargetDir[2]*TargetDir[2]);

    randNum=((float) (rand()%10))/20.0f;

	if (targetDis>500.0f)
	{
		vel+=(SPEED_INC+randNum);
		if (vel>MAXVEL)
				vel=MAXVEL;
	}
	else
	{
		
		vel-=(SPEED_LOSS+randNum);
		if (vel<0.0f)
				vel=0.0f;
	}

	/* calculate angle in xz plane between target's direction and 
	   craft's position */
                             
    z1 = (float) cos(ori[1])+pos[2];
    x1 = (float) sin(ori[1])+pos[0];
    
    z2 = pos[2];
    x2 = pos[0];
    
    a = TargetPos[2];
    b = TargetPos[0];
    
    d = ((x2-x1)*a) - ((z2-z1)*b)+z2*x1-z1*x2;                         
    
    magxz =(float) sqrt(TargetDir[0]*TargetDir[0]+TargetDir[2]*TargetDir[2]);
    
    if (magxz<=0.01f)
    	ang_diff=0.0f;

    else
    { 
    	Dx = TargetDir[0]/magxz;
    	Dz = TargetDir[2]/magxz;
        dp= Dx* (float) sin(ori[1])+Dz* (float) cos(ori[1]);
		ang_diff = (float) acos(dp);  
    }
    
    if (ori[2]>=DAMP_ANG)
		damper=-DAMPING_RATE;

	else if (ori[2]<=(-DAMP_ANG))
		damper=DAMPING_RATE;

	else
		damper=0.0f;
    
	randNum=((float) (rand()%10))/5.0f;
    
	if (d>0.0f)     
	{
		ori_change=(( (float) -fabs(ang_diff)/120.0f)*(3.0f+randNum))+damper;
		ori[2]+=ori_change;     
	}
	else                                
	{
		ori_change=(( (float) fabs(ang_diff)/120.0f)*(2.0f+randNum))+damper;
		ori[2]+=ori_change;      
	}

	if (ori[0]>=DAMP_ANG)
		damper=-DAMPING_RATE;

	else if (ori[0]<=-DAMP_ANG)
		damper=DAMPING_RATE;

	else
		damper=0.0f;

    randNum=((float) (rand()%10))/5.0f;
    
    magxz =(float)  sqrt(TargetDir[0]*TargetDir[0]+TargetDir[2]*TargetDir[2]);
    
    ang_diff= (float) acos(magxz/targetDis);

    if (pos[1]<(_GROUND_LEVEL+_LOW_LEVEL)) 
    {                   
    	disUnder=(pos[1]-(_GROUND_LEVEL+_LOW_LEVEL));
		ori_change=((-disUnder/120.0f)*(2.0f+randNum))+damper;
		ori[0]+=ori_change;      
    }
    else  
    {
    	if (TargetDir[1]>0.0f) 
		{	
			ori_change=(( (float) fabs(ang_diff)/60.0f)*(3.0f+randNum))+damper;
			ori[0]+=ori_change;     
		}
		else                                
		{
			ori_change=(( (float) -fabs(ang_diff)/60.0f)*(2.0f+randNum))+damper;
			ori[0]+=ori_change;      
		}
    }
}


void	ControlledCraft::Process()
{                             
	float Dx,Dz,damper,ori_change;

	if (UnderControl) 
	{             
		SetInputs(jx,jy,lp,rp,sp);  
		
		if (ori[0]>=DAMP_ANG)
			damper=-DAMPING_RATE;

		else if (ori[0]<=-DAMP_ANG)
			damper=DAMPING_RATE;
		
		else   
			damper=0.0f;

		ori_change=(-yInp/12.5f)+damper;

		ori[0]+=ori_change;

		if (ori[0]>MAXELEV_ANG) 
			ori[0]=MAXELEV_ANG;

		if (ori[0]<-MAXELEV_ANG)
			ori[0]=-MAXELEV_ANG;
	
		/* adjust roll for craft */
	
		if (ori[2]>=DAMP_ANG)
			damper=-DAMPING_RATE;

		else if (ori[2]<=(-DAMP_ANG))
			damper=DAMPING_RATE;

		else
			damper=0.0f;

		ori_change=(-xInp/12.5f)+damper;
		ori[2]+=ori_change;

		if (ori[2]>MAXROLL_ANG)
			ori[2]=MAXROLL_ANG;
	
		if (ori[2]<-MAXROLL_ANG)
			ori[2]=-MAXROLL_ANG;
	
		/* adjust y angle giving craft's forward direction */
	
		ori[1]-=(ori[2]/4.0f);

		if (lBut)
		{
			vel+=SPEED_INC;
			if (vel>MAXVEL)
				vel=MAXVEL;
		}
		else
		{
			vel-=SPEED_LOSS;
			if (vel<MINVEL)
				vel=MINVEL;
		}

		Dz = (float) cos(ori[1]);	    
		Dx = (float) sin(ori[1]);
		pos[2] += (vel*Dz);
		pos[0] += (vel*Dx);
		pos[1] -= (vel*((float) sin(-ori[0])+ALTLOSS));

		/* make sure craft stays in bounding game box */
	
		if (pos[1]<MINHEIGHT)
			pos[1]=MINHEIGHT; 
   	
		if (pos[0]>ARENASIZE)
			pos[0]=ARENASIZE;

		else if (pos[0]<-ARENASIZE)
			pos[0]=-ARENASIZE;

		if (pos[2]>ARENASIZE)
			pos[2]=ARENASIZE;

		else if (pos[2]<-ARENASIZE)
			pos[2]=-ARENASIZE;
    }
    
	/* move craft in display list */

	sgl_modify_transform(tran,TRUE);
	sgl_translate(pos[0],pos[1],pos[2]);
	sgl_rotate(sgl_y_axis,ori[1]);  
	
	sgl_modify_transform(tran2,TRUE);
	sgl_rotate(sgl_x_axis, -ori[0]);
	sgl_rotate(sgl_z_axis, ori[2]);	            
}

 
