// ----------------------------------------------------------------------- //
//
// MODULE  : LOFAlienWalker.cpp
//
// PURPOSE : AlienWalker - Implementation
//
// CREATED : 28/12/98 - by Ewen Vowels for Anarchy-Arts
//
// ----------------------------------------------------------------------- //

#include "LOFAlienWalker.h"


#define ANIM_ASSAULTRIFLE		"SHREDDER"
#define ANIM_ROCKETS			"ROCKETS"

#define ASSAULTRIFLE_PERCENTAGE	50

// These values are used as offsets from the model position for the indicated
// weapon...

#define NUM_ROCKET_POS	28
DVector s_vAWalkerRocketPos[NUM_ROCKET_POS] = 
{   // F,     U,     R
	DVector(20.0f, 10.0f, 10.0f),
	DVector(20.0f, 10.0f, -10.0f),
	DVector(20.0f, -5.0f, 10.0f),
	DVector(20.0f, -5.0f, -10.0f),
	DVector(20.0f, -20.0f, 10.0f),
	DVector(20.0f, -20.0f, -10.0f),
	DVector(20.0f, 5.0f, 10.0f),
	DVector(20.0f, 5.0f, -10.0f),
	DVector(20.0f, 0.0f, 10.0f),
	DVector(20.0f, 0.0f, -10.0f),
	DVector(20.0f, -10.0f, 10.0f),
	DVector(20.0f, -10.0f, -10.0f),
	DVector(20.0f, -15.0f, 10.0f),
	DVector(20.0f, -15.0f, -10.0f),
	DVector(20.0f, 10.0f, 5.0f),
	DVector(20.0f, 10.0f, -5.0f),
	DVector(20.0f, -5.0f, 5.0f),
	DVector(20.0f, -5.0f, -5.0f),
	DVector(20.0f, -20.0f, 5.0f),
	DVector(20.0f, -20.0f, -5.0f),
	DVector(20.0f, 5.0f, 5.0f),
	DVector(20.0f, 5.0f, -5.0f),
	DVector(20.0f, 0.0f, 5.0f),
	DVector(20.0f, 0.0f, -5.0f),
	DVector(20.0f, -10.0f, 5.0f),
	DVector(20.0f, -10.0f, -5.0f),
	DVector(20.0f, -15.0f, 5.0f),
	DVector(20.0f, -15.0f, -5.0f)
};

#define NUM_ASSAULTRIFLE_POS 1
DVector s_vAWalkerAssaultRiflePos[1] =
{	// F,     U,     R
	DVector(42.0f, 13.0f, 0.0f)
};

BEGIN_CLASS(AlienWalker)
	ADD_LONGINTPROP( State, Vehicle::AGGRESSIVE )
	ADD_LONGINTPROP(WeaponId, GUN_ASSAULTRIFLE_ID)
	ADD_STRINGPROP_FLAG(Filename, GetModel(MI_AI_ALIENWALKER_ID), PF_DIMS | PF_HIDDEN )
	ADD_BOOLPROP_FLAG(Small, 0, PF_HIDDEN)
END_CLASS_DEFAULT(AlienWalker, Vehicle, NULL, NULL)

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::AlienWalker()
//
//	PURPOSE:	Constructor
//
// ----------------------------------------------------------------------- //

AlienWalker::AlienWalker() : Vehicle()
{
	m_nModelId	 = MI_AI_ALIENWALKER_ID;
	m_bIsMecha	 = DTRUE;

	m_hShredderAni	= INVALID_ANI;
	m_hRocketsAni	= INVALID_ANI;

	m_pIdleSound = "Sounds\\Enemies\\Vehicle\\AlienWalker\\Idle.wav";
	m_pRunSound	 = "Sounds\\Enemies\\Vehicle\\AlienWalker\\Run.wav";

	m_bCreateHandHeldWeapon	= DFALSE;
	m_bChangeAnimation		= DFALSE;
	m_cc		 = ALIEN;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::SetAnimationIndexes()
//
//	PURPOSE:	Initialize model animation indexes
//
// ----------------------------------------------------------------------- //
	
void AlienWalker::SetAnimationIndexes()
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !m_hObject) return;

	Vehicle::SetAnimationIndexes();

	m_hShredderAni	= pServerDE->GetAnimIndex(m_hObject, ANIM_ASSAULTRIFLE);
	m_hRocketsAni	= pServerDE->GetAnimIndex(m_hObject, ANIM_ROCKETS);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::UpdateWeapon()
//
//	PURPOSE:	Update the our weapon
//
// ----------------------------------------------------------------------- //

void AlienWalker::UpdateWeapon()
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !m_hObject) return;

	m_bChangeAnimation = DFALSE;

	// See if we are firing...

	if (IsFiring())
	{
		// If we just started firing, figure out what weapon/animation to use...

		if (!(m_dwLastAction & AI_AFLG_FIRE))
		{
			m_bChangeAnimation = DTRUE;
		}
	}

	Vehicle::UpdateWeapon();
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::UpdateAnimation()
//
//	PURPOSE:	Update the current animation
//
// ----------------------------------------------------------------------- //

void AlienWalker::UpdateAnimation()
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !m_hObject) return;


	// See if we should change our animation...

	if (m_bChangeAnimation)
	{
		m_bAllowMovement = DFALSE;

		ModelSize eSize				= MS_NORMAL;
		DFLOAT	fMinFireDuration	= 1.0f;
		DFLOAT	fMaxFireDuration	= 2.0f;
		DFLOAT	fMinFireRest		= 3.0f;
		DFLOAT	fMaxFireRest		= 6.0f;

		if (GetRandom(1, 100) <= ASSAULTRIFLE_PERCENTAGE)
		{
			m_nWeaponId = GUN_ASSAULTRIFLE_ID;
			SetAnimation(m_hShredderAni, DTRUE);
		}
		else
		{
			m_nWeaponId = GUN_TOW_ID;
			SetAnimation(m_hRocketsAni, DTRUE);
			eSize = MS_SMALL;
		}

		m_weapons.ObtainWeapon(m_nWeaponId);
		m_weapons.DeselectCurWeapon();
		m_weapons.ChangeWeapon(m_nWeaponId);
		m_weapons.AddAmmo(m_nWeaponId, GetWeaponMaxAmmo(m_nWeaponId));

		CWeapon* pWeapon = m_weapons.GetCurWeapon();
		if (pWeapon) 
		{
			pWeapon->SetSize(eSize);
			pWeapon->SetMinFireDuration(fMinFireDuration);
			pWeapon->SetMaxFireDuration(fMaxFireDuration);
			pWeapon->SetMinFireRest(fMinFireRest);	
			pWeapon->SetMaxFireRest(fMaxFireRest);
		}
	}
	else if (!IsFiring())
	{
		m_bAllowMovement = DTRUE;

		Vehicle::UpdateAnimation();
	}
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::GetFirePos()
//
//	PURPOSE:	Get the current weapon fire position
//
// ----------------------------------------------------------------------- //

DVector AlienWalker::GetFirePos(DVector* pvPos)
{
	DVector vPos;
	VEC_INIT(vPos);

	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !m_hObject || !pvPos) return vPos;

	DVector vOffset;
	if (m_nWeaponId == GUN_ASSAULTRIFLE_ID)
	{
		int nIndex = GetRandom(0, NUM_ASSAULTRIFLE_POS-1);
		VEC_COPY(vOffset, s_vAWalkerAssaultRiflePos[nIndex]);
	}
	else
	{
		int nIndex = GetRandom(0, NUM_ROCKET_POS-1);
		VEC_COPY(vOffset, s_vAWalkerRocketPos[nIndex]);
	}

	// Adjust fire position...

	DRotation rRot;
	pServerDE->GetObjectRotation(m_hObject, &rRot);

	DVector vU, vF, vR;
	pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);

	DVector vTemp;
	VEC_MULSCALAR(vTemp, vF, vOffset.x);
	VEC_ADD(vPos, *pvPos, vTemp);

	VEC_MULSCALAR(vTemp, vU, vOffset.y);
	VEC_ADD(vPos, *pvPos, vTemp);

	VEC_MULSCALAR(vTemp, vR, vOffset.z);
	VEC_ADD(vPos, *pvPos, vTemp);

	return vPos;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::EngineMessageFn
//
//	PURPOSE:	Handle engine messages
//
// ----------------------------------------------------------------------- //

DDWORD AlienWalker::EngineMessageFn(DDWORD messageID, void *pData, DFLOAT fData)
{
	switch(messageID)
	{
		case MID_SAVEOBJECT:
		{
			Save((HMESSAGEWRITE)pData, (DDWORD)fData);
		}
		break;

		case MID_LOADOBJECT:
		{
			Load((HMESSAGEREAD)pData, (DDWORD)fData);
		}
		break;

		default : break;
	}

	return Vehicle::EngineMessageFn(messageID, pData, fData);
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::Save
//
//	PURPOSE:	Save the object
//
// ----------------------------------------------------------------------- //

void AlienWalker::Save(HMESSAGEWRITE hWrite, DDWORD dwSaveFlags)
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !hWrite) return;

	pServerDE->WriteToMessageDWord(hWrite, m_hShredderAni);
	pServerDE->WriteToMessageDWord(hWrite, m_hRocketsAni);
	pServerDE->WriteToMessageByte(hWrite, m_bSaveAllowmovement);
	pServerDE->WriteToMessageByte(hWrite, m_bChangeAnimation);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	AlienWalker::Load
//
//	PURPOSE:	Load the object
//
// ----------------------------------------------------------------------- //

void AlienWalker::Load(HMESSAGEREAD hRead, DDWORD dwLoadFlags)
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !hRead) return;

	m_hShredderAni			= pServerDE->ReadFromMessageDWord(hRead);
	m_hRocketsAni			= pServerDE->ReadFromMessageDWord(hRead);
	m_bSaveAllowmovement	= pServerDE->ReadFromMessageByte(hRead);
	m_bChangeAnimation		= pServerDE->ReadFromMessageByte(hRead);
}
