/*************************************************************************
  Crytek Source File.
  Copyright (C), Crytek Studios, 2001-2004.
 -------------------------------------------------------------------------
  $Id$
  $DateTime$
  
 -------------------------------------------------------------------------
  History:
  - 29:9:2004: Created by Filippo De Luca

*************************************************************************/
#include "StdAfx.h"
#include "G4Player.h"
#include "G4PlayerView.h"
#include "Game.h"
#include "Game04.h"
#include "GameUtils.h"
#include "GameActions.h"

#include "Weapon.h"
#include "WeaponSystem.h"

#include "FilmDirector.h"

#include <IViewSystem.h>
#include <IItemSystem.h>
#include <IPhysics.h>
#include <ICryAnimation.h>
#include "IAISystem.h"
#include "IAgent.h"
#include <IVehicleSystem.h>
#include <ISerialize.h>
#include "AutoCombat.h"
#include <IRenderAuxGeom.h>

#include <IGameTokens.h>

#include "PlayerMovementController.h"
//#include "SafePlayerMovementController.h"
//#include "AIPlayerMovementController.h"

#include "HUD/HUD.h"

#include "PlayerMovement.h"
#include "PlayerRotation.h"
#include "PlayerInput.h"
#include "G4PlayerInput.h"
#include "NetPlayerInput.h"

#define REUSE_VECTOR(table, name, value)	\
	{ if (table->GetValueType(name) != svtObject) \
	{ \
	table->SetValue(name, (value)); \
	} \
		else \
	{ \
	SmartScriptTable v; \
	table->GetValue(name, v); \
	v->SetValue("x", (value).x); \
	v->SetValue("y", (value).y); \
	v->SetValue("z", (value).z); \
	} \
	}

// Collision ray piercability to ignore leaves and other things
#define COLLISION_RAY_PIERCABILITY 10

#define RANDOM() ((((float)rand()/(float)RAND_MAX)*2.0f)-1.0f)
#define RANDOMR(a,b) ((float)a + ((rand()/(float)RAND_MAX)*(float)(b-a)))


//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------

CPlayerG4::CPlayerG4() : 
  m_bCameraCut(false)
{	
	m_pAutoCombat=NULL;
  m_vWeaponTarget[0]=Vec3(0,1,0);
  m_vWeaponTarget[1]=Vec3(0,1,0);

  m_bLateInit=false;
  m_lateInitCount=0;
  m_bCinematicDeathMovement=false;
  m_psCinematicDeathAct=0;
	m_timeLastYawPitch=10.0f;	// Large enough that auto return is enabled
	m_nTickLastPitch=60;
	m_modes.bCoverMode=false;
	m_modes.bCombatMode=false;
	m_modes.bFirstPersonStaticMode=false;
	m_modes.bTransition=false;
	m_cover.idCover=0;
	m_cover.vCoverDir=Vec3(0,1,0);

	m_aiming.aimPitch=0;
	m_aiming.aimYaw=0;
	m_aiming.aimPitchRange=45*g_PI/180.0f;
	m_aiming.aimYawRange=45*g_PI/180.0f;
	m_aiming.idTarget=0;

	m_aiming.vRefDir=Vec3(0,1,0);
	m_aiming.vTurnDir=Vec3(0,1,0);
	m_aiming.bHaveTurnDir=false;

	m_bHolster=false;
	m_bActionsEnabled=true;

  //g_pGame->AddPlayer(this);
}

void CPlayerG4::EditorToGameMode()
{
	GetISystem()->GetILog()->Log("******* Editor to Game mode *******");

	m_bActionsEnabled=true;
	m_bHolster=false;
	ClearActionQueue();
}

CPlayerG4::~CPlayerG4()
{
  //g_pGame->RemovePlayer(this);
  g_pGame04->GetDirector()->PlayerDeleted(this);
	if (m_pAutoCombat)
		delete m_pAutoCombat;
  if(m_psCinematicDeathAct)
    free((void*)m_psCinematicDeathAct);
}

void CPlayerG4::ProcessEvent(SEntityEvent& event)
{
	CPlayer::ProcessEvent(event);
}

//-------------------------------------------------------------------------------
//Bone names:
static char *aBoneNames[]=
{
	// This is a special one that is on the ground, and linearly interpolates over the animation.
	 "Bip01",

	// ----------------------------
	// In order from hips up to head:
	"Bip01 Pelvis", 
	"Bip01 Spine", 
   "Bip01 Spine1", 
   "Bip01 Spine2", 
   "Bip01 Spine3", 
   "Bip01 Neck", 
   "Bip01 Head", 
	// ----------------------------
   "eye_left_bone", 
   "eye_right_bone", 
	// ----------------------------
   "Bip01 R Clavicle", //	(shoulder joint)
   "Bip01 R UpperArm", 
   "Bip01 R ForeArm", 
   "Bip01 R Hand", 
	// ----------------------------
   "Bip01 L Clavicle", //	(shoulder joint)
   "Bip01 L UpperArm", 
   "Bip01 L ForeArm", 
   "Bip01 L Hand", 
	// ----------------------------
   "weapon_bone", //		( at the right hand )
	// ----------------------------
   "Bip01 L Thigh", 
   "Bip01 L Calf", 
   "Bip01 L Foot", 
   "Bip01 L Heel", 
   "Bip01 L Toe0", //			( Ball of the foot )
   "Bip01 L Toe0Nub", //	( The toes (big toe))
	// ----------------------------
   "Bip01 R Thigh", 
   "Bip01 R Calf", 
   "Bip01 R Foot", 
   "Bip01 R Heel", 
   "Bip01 R Toe0", //			( Ball of the foot )
   "Bip01 R Toe0Nub", //	( The toes (big toe))

	"helperBone_right" ,	//	right hand
	"helperBone_left"		//	left hand
};

bool CPlayerG4::VerifySkeleton()
{
	bool bRet=false;
	string sMsg="";
	string sChr="unknown";

	ICharacterInstance * pCharacter = GetEntity()->GetCharacter(0);
	if (pCharacter)
	{
		ISkeleton * pSkeleton = pCharacter->GetISkeleton();
		if(pSkeleton)
		{
			bRet=true;
			int iBone;
			int nBones=sizeof(aBoneNames)/sizeof(aBoneNames[0]);
			for(iBone=0 ; iBone<nBones ; ++iBone)
			{
				if(-1 ==pSkeleton->GetIDByName(aBoneNames[iBone]))
				{
					if(bRet)
					{
						sMsg="Missing bone(s): ";
						bRet=false;
					}
					else
					{
						sMsg+=", ";
					}
					sMsg+=aBoneNames[iBone];
				}
			}
		}
		else
			sMsg="Missing Skeleton";

		if(!bRet)
			sChr=pCharacter->GetFilePath();
	}
	else
		sMsg="Missing Character";

	if(!bRet)
	{
		const char *psName=GetEntity()->GetName();
		const char *psMsg=sMsg.c_str();
		const char *psChar=sChr.c_str();
		GetISystem()->GetILog()->LogError("Error: VerifySkeleton Failed: Entity '%s' Character '%s' Err: %s ",
			psName,psChar,psMsg);
	}

	return bRet;
}
bool CPlayerG4::Init(IGameObject * pGameObject)
{
  bool bRet=false;
  if(CPlayer::Init(pGameObject))
  {
	  m_pAutoCombat=new CAutoCombat(this);

    m_vWeaponTarget[0]=Vec3(0,1,0);
    m_vWeaponTarget[1]=Vec3(0,1,0);
    m_weaponTargetDist[0]=0;
    m_weaponTargetDist[1]=0;

    if(!IsThirdPerson())
      ToggleThirdPerson();

    bRet=true;

		VerifySkeleton();
  }
	return bRet;
}

float CPlayerG4::GetStanceMaxSpeed(EStance stance) const
{
  float speed=CPlayer::GetStanceMaxSpeed(stance);

	if (IsClient())
	{
		// modify player' speed in combat mode
		if (m_pAutoCombat && (m_pAutoCombat->GetCurrentMode()==eCombatMode))
		{		
			ICVar *pSpeed=GetISystem()->GetIConsole()->GetCVar("g_PlayerSpeedActionMoveRate");
			if (pSpeed)
				speed*=pSpeed->GetFVal();
		}
	}
	return speed;
}

// ???
void CPlayerG4::GetStanceAngleLimits(float & minAngle,float & maxAngle)
{
  minAngle=-(m_stance != STANCE_STAND?55.0f:60.0f) * gf_PI/180.0f;
  maxAngle=(m_stance == STANCE_PRONE?60.0f:60.0f) * gf_PI/180.0f;
}

bool CPlayerG4::IsTimeForAutoReturn()
{
	bool bRet=false;

	if((m_timeLastYawPitch>1.0f)&&(m_nTickLastPitch>10))
		bRet=true;

	return bRet;
}

void CPlayerG4::PitchAutoReturn(float frameTime,float rate)
{
	if(0) //(IsTimeForAutoReturn())
	{
  float pitch=GetISystem()->GetIConsole()->GetCVar("cl_tpvPitchNav")->GetFVal();
  if(0!=pitch)
  {
    float kPitchReturn=GetISystem()->GetIConsole()->GetCVar("cl_tpvYawNavReturn")->GetFVal();
    if(pitch<0)
    {
      pitch+=frameTime*kPitchReturn*rate;
      if(pitch>0)
        pitch=0;
    }
    else if (pitch>0)
    {
      pitch-=frameTime*kPitchReturn*rate;
      if(pitch<0)
        pitch=0;
    }
		GetISystem()->GetIConsole()->GetCVar("cl_tpvPitchNav")->Set(pitch);
//SetLocalPitch(pitch*gf_PI/180);
  }
	}
}

void CPlayerG4::YawAutoReturn(float frameTime,float rate)
{
	if(IsTimeForAutoReturn())
	{
  //--- Nav look return with movement
  float yaw=GetISystem()->GetIConsole()->GetCVar("cl_tpvYawNav")->GetFVal();
  if(0!=yaw)
  {
    float kYawReturn=GetISystem()->GetIConsole()->GetCVar("cl_tpvYawNavReturn")->GetFVal();
    if(yaw<0)
    {
      yaw+=frameTime*rate*kYawReturn;
      if(yaw>0)
        yaw=0;
    }
    else if (yaw>0)
    {
      yaw-=frameTime*rate*kYawReturn;
      if(yaw<0)
        yaw=0;
    }
    GetISystem()->GetIConsole()->GetCVar("cl_tpvYawNav")->Set(yaw);
  }
	}
}

// View can be adjusted using right stick, but auto returns when stick released.
void CPlayerG4::UpdateReturnView(SEntityUpdateContext & ctx)
{
  const float frameTime = ctx.fFrameTime;
  bool client(IsClient());

	if(IsTimeForAutoReturn())
	{
		float kAutoRate=12.0f;

		YawAutoReturn(frameTime,kAutoRate);

		if(m_pAutoCombat->GetCurrentMode() == eNavigationMode )
		{
			PitchAutoReturn(frameTime,kAutoRate);
		}
	}
}

//float kAutoRate=1.0f;
void CPlayerG4::UpdateAsDoll(SEntityUpdateContext & ctx)
{
  if(IsClient())
  {
    UpdateReturnView(ctx);

    // Not the best place for this, but will do for now...
    g_pGame04->UpdateTick(ctx.fFrameTime);
  }
}

void CPlayerG4::UpdateAsLiveAndMobile(SEntityUpdateContext & ctx)
{
  bool client(IsClient());

  if(client)
  {
    if (m_pAutoCombat)
      m_pAutoCombat->Update(ctx.fFrameTime);

    UpdateReturnView(ctx);

    // Not the best place for this, but will do for now...
    g_pGame04->UpdateTick(ctx.fFrameTime);
  }
}

// Hook for inheritance.
IPlayerInput * CPlayerG4::CreatePlayerInput()
{
	return new CPlayerInputG4(this);
}

void CPlayerG4::Update(SEntityUpdateContext& ctx, int iUpdateSlot)
{
	const float frameTime = ctx.fFrameTime;
	bool client(IsClient());

  //--- Pre Update -----------------------
  // Hack to force third person start, yet allow user to switch to first person
  if(client && !m_bLateInit)
  {
    if(!IsThirdPerson())
      ToggleThirdPerson();

    ++m_lateInitCount;
    if(m_lateInitCount>50)
    {
      m_bLateInit=true;
    }
  }

	TickCover();
	TickAiming();
  //--- Update -----------------------
  CPlayer::Update(ctx,iUpdateSlot);

  //--- Post Update -----------------------

}



extern bool m_bWasCameraCut;

void CPlayerG4::UpdateView(SViewParams &viewParams)
{
	int iCamMode=GetISystem()->GetIConsole()->GetCVar("cl_cm")->GetIVal();

	if(1)//0==iCamMode)
	{
		// This block is for debugging/working round integration view problems
		//CPlayer::UpdateView(viewParams);
		CPlayerViewG4 playerView(*this,viewParams);
		playerView.Process(viewParams);
		playerView.Commit(*this,viewParams);
	}
	else	// This is the real view code
	{
		// Give the director a chance to handle the view
		if(!g_pGame04->GetDirector()->TickCamera(this,viewParams))
		{
			// Not handled by director, so let CPlayer handle it.
			CPlayer::UpdateView(viewParams);
		}
	}
}

void CPlayerG4::Revive( bool fromInit )
{
	CPlayer::Revive(fromInit);

	m_camViewMtxFinal=m_viewMtxFinal;
	m_modes.bCoverMode=false;
	m_modes.bCombatMode=false;
	m_modes.bFirstPersonStaticMode=false;
	m_modes.bTransition=false;
	m_cover.idCover=0;
	m_cover.vCoverDir=Vec3(0,1,0);

	m_aiming.aimPitch=0;
	m_aiming.aimYaw=0;
	m_aiming.aimPitchRange=45*g_PI/180.0f;
	m_aiming.aimYawRange=45*g_PI/180.0f;
	m_aiming.idTarget=0;
	m_aiming.vRefDir=Vec3(0,1,0);
	m_aiming.vTurnDir=Vec3(0,1,0);
	m_aiming.bHaveTurnDir=false;
}

//-------------------------------------------------------

#if 0
Vec3 CPlayerG4::GetDesiredDirection()
{
	SMovementState state;
	m_pMovementController->GetMovementState(state);
	//state.aimDirection
	//state.bodyDirection
	//state.eyeDirection
	//state.movementDirection
	if( state.movementDirection.len2() >0.0001f)
	{
		return state.movementDirection;
	}
	else
	{
		// state.bodyDirection
		return m_baseMtx.GetColumn(1);
	}
#if 0
  if( m_input.viewVector.len2() >0.0001f)
    return m_input.viewVector;
  else
    return m_baseMtx.GetColumn(1);
#endif
}
#endif

// Temporary method of saving edit cams (via log file)
void CPlayerG4::SaveEditCam()
{
  static int iCount=0;
  char acCamSetup[1024];

  ++iCount;

  int camCut=GetISystem()->GetIConsole()->GetCVar("cl_cam_cut")->GetIVal();
  float thirdPersonDist=GetISystem()->GetIConsole()->GetCVar("cl_tpvDist")->GetFVal();
  float thirdPersonYawDeg=GetISystem()->GetIConsole()->GetCVar("cl_tpvYaw")->GetFVal();
  float thirdPersonPitchDeg=GetISystem()->GetIConsole()->GetCVar("cl_tpvPitch")->GetFVal();
  float thirdPersonRollDeg=GetISystem()->GetIConsole()->GetCVar("cl_tpvRoll")->GetFVal();
  float thirdPersonHOff(GetISystem()->GetIConsole()->GetCVar("cl_tpvHOff")->GetFVal());
  float thirdPersonVOff(GetISystem()->GetIConsole()->GetCVar("cl_tpvVOff")->GetFVal());

  // format suitable for copy and paste into the cam cut table
  sprintf(acCamSetup,"CAM_DHPRVY(%ff,%ff,%ff,%ff,%ff,%ff,CAM_ILOW,CAM_TARGET,CAM_DOFMED,CAM_PAN)",
    thirdPersonDist,thirdPersonHOff,thirdPersonPitchDeg,thirdPersonRollDeg,thirdPersonVOff,thirdPersonYawDeg);
  CryLogAlways("--- Saved camera: %d ------------------------------",iCount);
  CryLogAlways(acCamSetup);
}


bool CPlayerG4::IsCombatMode()
{
	// Retire these auto combat modes asap
	if(IsClient() && m_pAutoCombat)
	{
		if(eCombatMode==m_pAutoCombat->GetCurrentMode())
			m_modes.bCombatMode=true;
		else
			m_modes.bCombatMode=false;
	}

	return m_modes.bCombatMode;
}

void CPlayerG4::SetCombatMode(bool bSet)
{
	// Retire these auto combat modes asap
	if(IsClient() && m_pAutoCombat)
	{
		if(bSet)
			m_pAutoCombat->SetGamePlayMode(eCombatMode);
		else
			m_pAutoCombat->SetGamePlayMode(eNavigationMode);
	}

	m_modes.bCombatMode=bSet;
}


//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------


void CPlayerG4::PushActionQueue(const char *actionName, int activationMode, float value)
{
	SPlayerActionQueueNode node;

	node.strAction=actionName;
	node.mode=activationMode;
	node.value=value;

	m_actionQueue.push_back(node);

}

bool CPlayerG4::PopActionQueue(string & strAction, int & activationMode, float & value)
{
	bool bRet=false;

	
	if(!m_actionQueue.empty())
	{
		bRet=true;
		SPlayerActionQueueNode & rNode=m_actionQueue.front();
		strAction=rNode.strAction;
		activationMode=rNode.mode;
		value=rNode.value;
		m_actionQueue.pop_front();
	}

	return bRet;
}

void CPlayerG4::ClearActionQueue()
{
	TPlayerActionQueue dummy;

	m_actionQueue.swap(dummy);	// Use dummy swap trick to clear container.
}

void CPlayerG4::EnterCover(const Vec3 &vCoverDir,SCover &rCover)
{
	m_modes.bCoverMode=true;
	m_cover=rCover;
	m_cover.vCoverDir=vCoverDir;
	
	CMovementRequest request;
	request.SetStance(STANCE_CROUCH);
	m_pMovementController->RequestMovement(request);

	CreateScriptEvent("printhud",0,"Entering cover");
}

void CPlayerG4::LeaveCover()
{
	m_modes.bCoverMode=false;
	m_cover.idCover=0;

	//CMovementRequest request;
	//request.SetStance(ACTION_CROUCH);
	//m_pMovementController->RequestMovement()

	CreateScriptEvent("printhud",0,"Leaving cover");
}

bool CPlayerG4::IsCoverInDir(const Vec3 & vTestDir,float distTest,SCover &rCover)
{
	return (GetCoverDist(vTestDir,distTest,rCover)>=0.0f);
}

float CPlayerG4::GetCoverDist(const Vec3 & vTestDir,float distTest,SCover &rCover)
{
	float distOut=-1;

	ray_hit rayHit;
	IPhysicalWorld *pW=GetISystem()->GetIPhysicalWorld();
	IPhysicalEntity *pIgnore1=GetEntity()->GetPhysics();

	//vCoverDir=m_viewMtxFinal.GetColumn(1);			// This is the player characters view dir
	//vCameraDir=m_camViewMtxFinal.GetColumn(1);	// This is the camera view dir

	if (pW->RayWorldIntersection(GetEntity()->GetWorldPos(), vTestDir*distTest, 
		ent_terrain|ent_static|ent_rigid,(rwi_ignore_noncolliding |  rwi_stop_at_pierceable), &rayHit, 1,pIgnore1, 0))
	{
		distOut=rayHit.dist;
		rCover.vNormal=rayHit.n;
		rCover.dist=distOut;
		IEntity *pEnt=GetISystem()->GetIEntitySystem()->GetEntityFromPhysics(rayHit.pCollider);
		if(pEnt)
			rCover.idCover=pEnt->GetId();
		else
			rCover.idCover=0;
		rCover.vCoverDir=vTestDir;
	}
	else
		rCover.idCover=0;

	return distOut;
}

#define ENTER_COVER_DIST				1.5f
#define ENTER_COVER_DIST_DIAG		1.5f
#define LEAVE_COVER_DIST				2.0f

static ColorB clrRed(255,64,64,128);
static ColorB clrDkRed(128,0,0,128);
static void DrawLineV1Dir(Vec3 vFrom,Vec3 vDir,float length,ColorB &rColorTo,ColorB &rColorFrom)
{
	{
		IRenderAuxGeom* pRenderAuxGeom( GetISystem()->GetIRenderer()->GetIRenderAuxGeom() ); 
		pRenderAuxGeom->SetRenderFlags( e_Def3DPublicRenderflags );
		pRenderAuxGeom->DrawLine( vFrom, rColorFrom, vFrom+vDir*length, rColorTo );
	}
}

bool CPlayerG4::GetCover(Vec3 &vCoverDir,SCover &rCover)
{
	bool bRet=false;
	Vec3 vCameraDir,vPlayerDir,vLeft,vRight;

	//vPlayerDir=m_viewMtxFinal.GetColumn(1);			// This is the player characters view dir
	vPlayerDir=GetEntity()->GetWorldTM().GetColumn(1);			// This is the player entities forward dir
	vPlayerDir.z=0;	// horizontal check

	if(vPlayerDir.len2() > 0.01f)
	{
		vPlayerDir.Normalize();
		vCameraDir=m_camViewMtxFinal.GetColumn(1);	// This is the camera view dir
		vPlayerDir*=-1;
		vLeft=vPlayerDir*Quat::CreateRotationZ(-65.0f*g_PI/180.0f);
		vRight=vPlayerDir*Quat::CreateRotationZ(65.0f*g_PI/180.0f);

		//if(IsCoverInDir(vCameraDir,1.0f))	// Cover in camera direction?
		//{
		//	vCoverDir=vCameraDir;
		//	bRet=true;
		//}
		//else
//		DrawLineV1Dir(GetEntity()->GetWorldPos(),vPlayerDir,ENTER_COVER_DIST,clrRed,clrDkRed);
		if(IsCoverInDir(vPlayerDir,ENTER_COVER_DIST,rCover))	// Cover in player view direction?
		{
			vCoverDir=vPlayerDir;
			bRet=true;
		}
		else if(IsCoverInDir(vLeft,ENTER_COVER_DIST_DIAG,rCover))	// Cover left of player view direction?
		{
			vCoverDir=vLeft;
			bRet=true;
		}
		else if(IsCoverInDir(vRight,ENTER_COVER_DIST_DIAG,rCover))	// Cover right of player view direction?
		{
			vCoverDir=vRight;
			bRet=true;
		}
	}

	return bRet;
}

void CPlayerG4::TickCover()
{
	bool client(IsClient());
	Vec3 vCoverDir;
	SCover cover;

	if(client && !m_modes.bCoverMode && GetCover(vCoverDir,cover))
	{
//--CreateScriptEvent("printhud",0,"Press use to enter cover");
	}
	else if (client && m_modes.bCoverMode && !IsCoverInDir(m_cover.vCoverDir,LEAVE_COVER_DIST,cover))
	{
//--CreateScriptEvent("printhud",0,"Leaving cover");
		LeaveCover();
	}
}





// The G02 version is now PrePhysicsUpdate
void CPlayerG4::AfterAction()
{

//	CPlayer::AfterAction();

	

	//OnPhysPostStep(min(0.1f,frameTime));


}

//void CPlayerG4::SetDesiredSpeed(const Vec3 &desiredSpeed)
//{
//  CPlayer::SetDesiredSpeed(desiredSpeed);
//}

//void CPlayerG4::SetDesiredDirection(const Vec3 &desiredDir)
//{
//  CPlayer::SetDesiredDirection(desiredDir);
//}

//---------------------------------
//AI Specific
#if 0
void CPlayerG4::SetActorMovement(SOBJECTSTATE &control)
{
	IVehicle* vehicle = GetLinkedVehicle();
 	if (vehicle)
 	{
		//const char *name = GetEntity()->GetName(); 
		//vehicle->SetPassengerMovement(control, GetEntityId());
 		return;
 	}

	bool exactPos(false);
	control.bGameInPositionReached = false;
	if (control.bExactPositioning) 
	{
		int nPoints = control.remainingPath.size();

		// activate exact positioning    
		// todo: determine a better threshold
		if (nPoints == 1)
		{      
			//threshold is relative to the 2d plane of the actor, that should make the check more precise in most cases.
			Vec3 dist(m_baseMtx.GetInverted() * (GetEntity()->GetWorldPos() - control.remainingPath[0].vPos));
			dist.z = 0;

			if(dist.len2()<.51f*.51f)
				// tell AI the position is reached, approach/trace should be finished
				control.bGameInPositionReached = true;

			m_input.posTarget = control.remainingPath[0].vPos;
			m_input.dirTarget = control.remainingPath[0].vDir;
			exactPos = true;
		}    
	}

	if (!exactPos)
	{
		m_input.posTarget.zero();
		m_input.dirTarget.zero();
	}
#if 0 //--- Nick - Disable for now
	if (!IsClient())
	{
		// cinematic AI hits / misses - modify fire direction
		m_pAutoCombat->GetCinematicFireDirection(control.vFireDir);
		if(m_bCinematicDeathMovement)
		{
			DoCinematicDeathMovement(control);
		}
		else
		{
			if(m_bCameraCut)
			{
				//control.fDesiredSpeed*=0.5f; // slow the ai's speed down during a cut. (may end up stopping it entirely)
			}
		}
	}
	else  // IsPlayer
	{
		if(m_bCameraCut)
		{
			control.fDesiredSpeed*=0.5f;    // slow the players speed down during a cut. (may end up stopping it entirely)
		}
	}
#endif
	//
	SetDesiredDirection(control.vLookDir);
	Vec3 desiredSpeed = control.vMoveDir * control.fDesiredSpeed * control.fDesiredSpeedMod;
		
  SetDesiredSpeed(desiredSpeed);

	//
	//m_input.actions = control.m_desiredActions;
	int actions;
	switch(control.bodystate)
	{
	case 1:
		actions = ACTION_CROUCH;
		break;
	case 2:
		actions = ACTION_PRONE;
		break;
	case 3:
		actions = 0; // was ACTION_RELAXED - disabled temp. for G02 milestone
		break;
	case 4:
		actions = ACTION_STEALTH;
		//FIXME:
		// stealth is not working currently (actor does not move)- replacing it with crouch for M12
		actions = ACTION_CROUCH;	
		break;
	default:
		actions = 0;
		break;
	}

	
	if(control.jump)
	{
		control.jump = false;
		actions |= ACTION_JUMP;
	}
	if(control.aimLook)
		actions |= ACTION_AIMING;

	m_input.actions = actions;

	//weapons
  if(control.vFireDir.len2()<0.00001f)
    control.vFireDir=Vec3(0,1,0);
	GetEntity()->GetScriptTable()->SetValue( "fireDir", control.vFireDir );

  // AI Firing code. Player version happens in response to input bound in GameG4::InitActionMaps()
	//FIXME:pretty bad, weapon system should take care of that
	if (control.fire)
	{
		if (!m_stats.isFiring)
			OnAction("attack1", eAAM_OnPress, 1.0f);
	}
	else
	{
		if (m_stats.isFiring)
			OnAction("attack1", eAAM_OnRelease, 1.0f);
	}

	m_stats.isFiring = control.fire;
}
#endif

//void CPlayerG4::SetAngles(const Ang3 &angles) 
//{
//	Matrix33 rot(Matrix33::CreateRotationXYZ(angles));
//	SetDesiredDirection(rot.GetColumn(1));
//}

//Ang3 CPlayerG4::GetAngles() 
//{
//	Ang3 angles;
//	angles.SetAnglesXYZ(m_viewMtxFinal);
//
//	return angles;
//}

Vec3 CPlayerG4::WorldToScreenCoords(Vec3 worldPos)
{
	IRenderer *pRenderer = GetISystem()->GetIRenderer();

	Vec3 screenPos;
	screenPos.x=screenPos.y=screenPos.z=0;
	pRenderer->ProjectToScreen(worldPos.x,worldPos.y,worldPos.z,&screenPos.x,&screenPos.y,&screenPos.z);

	// Scale for our virtual 800x600 display
	screenPos.x*=8;
	screenPos.y*=6;

	return screenPos;
}

void CPlayerG4::GetEyePosDir(Vec3 &rvEyePos,Vec3 &rvEyeDir)
{
	//GetActorInfo(bodyInfo);
	rvEyeDir=Vec3(0,1,0);	//bodyInfo.vEyeDir;
	//rvEyePos=bodyInfo.vEyePos;
	rvEyePos=Vec3(0,0,0.25f);
}

void CPlayerG4::TickAiming()
{
#if 0 //--- Nick - Disable whilst debugging other code

	if(IsClient())
	{
		IEntity *pPlayerEnt=GetEntity();
		//SAIBodyInfo bodyInfo;

		Vec3 vEyePos,vEyeDir;
		GetEyePosDir(vEyePos,vEyeDir);

		Vec3 vRefDir=vEyeDir;

		// If we're in combat mode, and free to move the player/camera.
		if(!m_bCameraCut && !g_pGame04->GetDirector()->InCinematic() && m_modes.bCombatMode && !m_modes.bCoverMode)
		{
			Vec3 vPos=vEyePos;

			Vec3 vDefaultDir=vRefDir;
			Vec3 vDefaultLookDir=vDefaultDir;
			Vec3 vTargetPos;
			Vec3 vScrPos;

			//	  if (m_eGamePlayMode==eNavigationMode)
			{
				float yawOld,yawNew,pitchOld,pitchNew,dist;
				CartesianToSpherical(m_aiming.vRefDir,yawOld,pitchOld,dist);
				CartesianToSpherical(vRefDir,yawNew,pitchNew,dist);

				m_aiming.aimYaw+=yawOld-yawNew;
				m_aiming.aimPitch+=pitchOld-pitchNew;
				m_aiming.vRefDir=vRefDir;

				// Update the target dir
				vDefaultDir=SphericalToCartesian(yawNew+m_aiming.aimYaw,pitchNew+m_aiming.aimPitch,1.0f);

				//vDefaultDir=Quat::CreateRotationZ(m_aiming.aimYaw)*vRefDir;
				vDefaultDir.Normalize();


				SetWeaponTargetDir(vDefaultDir,0);
				SetWeaponTargetDir(vDefaultDir,1);
				SetWeaponTargetDist(0,0);
				SetWeaponTargetDist(0,1);

				ray_hit rayHit;
				IPhysicalWorld *pW=GetISystem()->GetIPhysicalWorld();
				IPhysicalEntity *pIgnore1=GetEntity()->GetPhysics();
				float testDist=200;

				float width=0.75f*800;
				float height=0.75f*600;
				float xMin=400-width/2;
				float xMax=400+width/2;
				float yMin=300-height/2;
				float yMax=300+height/2;

				xMin=max(xMin,0.0f);
				xMax=min(xMax,800.0f);
				yMin=max(yMin,0.0f);
				yMax=min(yMax,600.0f);

				if (pW->RayWorldIntersection(vPos, vDefaultDir*testDist, 
					ent_terrain|ent_static|ent_rigid,(rwi_ignore_noncolliding |  rwi_stop_at_pierceable), &rayHit, 1,pIgnore1, 0))
				{
					//rayHit.dist;
					IEntity *pEnt=GetISystem()->GetIEntitySystem()->GetEntityFromPhysics(rayHit.pCollider);
					if(pEnt)
						m_aiming.idTarget=pEnt->GetId();
					else
						m_aiming.idTarget=0;

					vTargetPos=rayHit.pt;
				}
				else
				{
					vTargetPos=vPos+vDefaultDir*testDist;
				}
				
				vScrPos=WorldToScreenCoords(vTargetPos);
				if( (vScrPos.x<xMin) || (vScrPos.x>xMax) || (vScrPos.y<yMin) || (vScrPos.y>yMax) )
				{
					if(!m_aiming.bHaveTurnDir )
					{
						// turn actor towards aim dir
						m_aiming.bHaveTurnDir=true;
						m_aiming.vTurnDir=vDefaultDir;
					}
					else if(m_aiming.vTurnDir.Dot(vDefaultDir) < 0.996f)
					{
						// Already turning, but new desired aim dir is more than 5 degrees from previous one.
						m_aiming.bHaveTurnDir=true;
						m_aiming.vTurnDir=vDefaultDir;
					}
				}
			}
			if(m_aiming.bHaveTurnDir)
			{
				if( m_aiming.vTurnDir.Dot(vRefDir) >= 0.996f )	// within +/- 5 degrees
				{
					m_aiming.bHaveTurnDir=false;
				}
				else
				{
					SetDesiredDirection(m_aiming.vTurnDir);
				}
			}
		}
		else if (!m_modes.bCombatMode)	// Nav mode
		{
			m_aiming.bHaveTurnDir=false;
			m_aiming.aimYaw=0;
			m_aiming.aimPitch=0;
			m_aiming.idTarget=0;
			SetWeaponTargetDir(vRefDir,0);
			SetWeaponTargetDir(vRefDir,1);
			SetWeaponTargetDist(0,0);
			SetWeaponTargetDist(0,1);
		}
	}
#endif
}

float g_OldDist;
float g_OldTimeStep;
void CPlayerG4::BeginPlayerCameraCut()
{
//  if(!m_bCameraCut)
  {
    g_OldDist=GetISystem()->GetIConsole()->GetCVar("cl_tpvDist")->GetFVal();
    g_OldTimeStep=GetISystem()->GetIConsole()->GetCVar("fixed_time_step")->GetFVal();
    CryLogAlways( "+++xxx BeginPlayerCameraCut: saving dist:%f",g_OldDist);
  }
}

void CPlayerG4::EndPlayerCameraCut()
{
  if(m_bCameraCut)
  {
    CryLogAlways( "+++xxx EndPlayerCameraCut: restoring dist:%f",g_OldDist);
    GetISystem()->GetIConsole()->GetCVar("cl_tpvDist")->Set(g_OldDist);
    GetISystem()->GetIConsole()->GetCVar("fixed_time_step")->Set(g_OldTimeStep);
  }
 
  m_bCameraCut=false;
}

void CPlayerG4::DoCinematicDeathMovement(SOBJECTSTATE &control)
{
  if(0==stricmp("ShootObject",m_psCinematicDeathAct))
  {
    m_pAutoCombat->GetCinematicFireDirection(control.vFireDir,true);

    //weapons
    if(control.vFireDir.len2()>0.00001f)
    {
      GetEntity()->GetScriptTable()->SetValue( "fireDir", control.vFireDir );

      control.fire=true;

      if (!m_stats.isFiring)
        OnAction("attack1", eAAM_OnPress, 1.0f);
      m_stats.isFiring = control.fire;
    }
  }
}

char *STR_DUP(const char *psStr);
void CPlayerG4::CinematicDeathAct(const char *psDeathAct)
{
  if(m_psCinematicDeathAct)
  {
    free((void*)m_psCinematicDeathAct);
    m_psCinematicDeathAct=0;
  }

  if(psDeathAct)
  {
    m_psCinematicDeathAct=STR_DUP(psDeathAct);

    if(0==stricmp("ShootObject",psDeathAct))
    {
      m_bCinematicDeathMovement=true;
    }
    else if(0==stricmp("RandomBurst",psDeathAct))
    {
      // if the weapon's not pointing at the player, then just let rip - assuming the death anim/rag doll will move the gun bone
    }
  }
}

