// ----------------------------------------------------------------------- //
//
// MODULE  : LOFClientShellAdditions.cpp
//
// PURPOSE : LOF's Additions to the Riot Client Shell - Implementation
//
// CREATED : 18th December 1998 by Ewen Vowels for Anarchy-Arts
//
// ----------------------------------------------------------------------- //
#include "RiotClientShell.h"
#include "RiotMsgIds.h"
#include "RiotCommandIds.h"
#include "WeaponModel.h"
#include "WeaponDefs.h"
#include "ClientUtilities.h"
#include "vkdefs.h"
#include "ClientRes.h"
#include "RiotSoundTypes.h"
#include "Music.h"
#include "TextHelper.h"
#include "PopupMenu.h"
#include "VolumeBrushFX.h"
#include "client_physics.h"
#include "CameraFX.h"
#include "WinUtil.h"
#include "Font28.h"
#include "Font08.h"
#include "NetStart.h"
#include "WeaponStringDefs.h"
#include "CMoveMgr.h"
#include "physics_lt.h"
#include "VarTrack.h"
#include "ClientWeaponUtils.h"

// new ev - added includes
#include "WeaponFX.h"
#include "cpp_client_de.h"
#include "DynamicLightFX.h"
#include "RiotMsgIDs.h"

// end ev - added includes

#define FLASHLIGHT_R 0.75f
#define FLASHLIGHT_G 0.75f
#define FLASHLIGHT_B 0.75f

extern CRiotClientShell* g_pRiotClientShell; // new ev - 18/12/98 need a link to static riotclientshell

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CRiotClientShell::Update3rdPersonFlashLight()
//
//	PURPOSE:	Update the 3rd person flashlight pos
//
// ----------------------------------------------------------------------- //

void CRiotClientShell::Update3rdPersonFlashLight(DFLOAT fDistance)
// new ev - 12/12/98 for flash light
{
	CClientDE* pClientDE = GetClientDE();
	if (!m_MoveMgr || !pClientDE || !m_playerCamera.IsChaseView() || !m_bFlashLightOn) return;

	//HLOCALOBJ hPlayerObj = pClientDE->GetClientObject();
	HLOCALOBJ hPlayerObj = m_MoveMgr->GetObject();
	if (!hPlayerObj) return;

	DVector vU, vR, vF;
	pClientDE->GetRotationVectors(&m_rRotation, &vU, &vR, &vF);
	VEC_NORM(vF);

	DVector vPos;
	pClientDE->GetObjectPos(hPlayerObj, &vPos);

	DFLOAT fDist = fDistance > 100.0f ? fDistance - 20.0f : fDistance;

	DVector vTemp;
	VEC_MULSCALAR(vTemp, vF, fDist);
	VEC_ADD(vPos, vPos, vTemp);

	// Set the 3rd person flashlight the correct position...

// new ev - start here add a dynamic light for the torch (only if the torch is on and the 
// distance is less than 3000)
	if (fDistance < 3000.0f)
	{
		CSFXMgr* psfxMgr = g_pRiotClientShell->GetSFXMgr();
		if (!psfxMgr) return;

		// Create dynamic light...

		DLCREATESTRUCT dl;
		VEC_COPY(dl.vPos, vPos);
		DFLOAT fRadius   = fDistance > 300.0f ? ((fDistance / 20.0f) + 55.0f) : 70.0f;
		dl.fMinRadius    = fRadius;
		dl.fMaxRadius	 = fRadius;
		dl.fRampUpTime	 = 0.01f;
		dl.fMaxTime		 = 0.0f;
		dl.fMinTime		 = 0.0f;
		dl.fRampDownTime = 0.01f;
		dl.dwFlags		 = FLAG_VISIBLE;

		VEC_SET(dl.vColor, FLASHLIGHT_R, FLASHLIGHT_G, FLASHLIGHT_B);

		psfxMgr->CreateSFX(SFX_DYNAMICLIGHT_ID, &dl);
	}
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CRiotClientShell::UpdateFlashLight
//
//	PURPOSE:	Update any client side container fx
//
// --------------------------------------------------------------------------- //

void CRiotClientShell::UpdateFlashLight()
// new ev - 12/12/98 for flash light
{
	CClientDE* pClientDE = GetClientDE();
	if (!pClientDE || !m_bFlashLightOn) return;
	// new ev - first person flash light (fixed properly 12/12/98)
	// To cast a ray at the 3d pos where the crosshair points to;
	//	1) you get the rotation of the player (this gives the exact direction)
	//  2) you get the position of the camera and then cast a ray forward in the direction of the
	//     player's forward vector
	// This places the torch at the exact position of the crosshair
	if (m_playerCamera.IsFirstPerson() && !m_playerCamera.IsChaseView())
	{
		HLOCALOBJ hPlayerObj = pClientDE->GetClientObject();
		if (!hPlayerObj) return;

	    // filter out the player, the client movement object for the player and the weapon models
		HOBJECT hFilterList[] = {hPlayerObj, m_MoveMgr->GetObject(), m_weaponModel.GetHandle(), DNULL};
		ClientIntersectInfo info;
		ClientIntersectQuery query;
		memset(&query, 0, sizeof(query));
		DVector vStartPos, vUp, vRight, vForward;

		DFLOAT fLightDistance = 3000.0f;// cast a ray 3000 long

		pClientDE->GetObjectPos(m_hCamera, &vStartPos);
		
		pClientDE->GetRotationVectors(&m_rRotation, &vUp, &vRight, &vForward);

		// Determine where the light should be...

		DVector vStart, vEnd, vPos;
		VEC_COPY(vStart, vStartPos);
		VEC_MULSCALAR(vEnd, vForward, fLightDistance);
		VEC_ADD(vEnd, vEnd, vStart);

		VEC_COPY(query.m_From, vStart);
		VEC_COPY(query.m_To, vEnd);

		query.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY;// | IGNORE_NONSOLID;
		query.m_FilterFn = ObjListFilterFn;
		query.m_pUserData = hFilterList;

		if (pClientDE->IntersectSegment (&query, &info))
		{
			// only display a light if we hit something
			VEC_COPY(vPos, info.m_Point);

			DVector vTemp;
			VEC_SUB(vTemp, vPos, vStart);

			fLightDistance = VEC_MAG(vTemp);

			VEC_MULSCALAR(vTemp, vForward, fLightDistance);
			VEC_ADD(vTemp, vStartPos, vTemp);

			CSFXMgr* psfxMgr = g_pRiotClientShell->GetSFXMgr();
			if (!psfxMgr) return;

			// Create dynamic light...

			DLCREATESTRUCT dl;
			VEC_COPY(dl.vPos, vTemp);
			DFLOAT fRadius   = fLightDistance > 300.0f ? ((fLightDistance / 20.0f) + 55.0f)  : 70.0f;
			dl.fMinRadius    = fRadius;
			dl.fMaxRadius	 = fRadius;
			dl.fRampUpTime	 = 0.01f;
			dl.fMaxTime		 = 0.0f;
			dl.fMinTime		 = 0.0f;
			dl.fRampDownTime = 0.01f;
			dl.dwFlags		 = FLAG_VISIBLE;

			VEC_SET(dl.vColor, FLASHLIGHT_R, FLASHLIGHT_G, FLASHLIGHT_B);

			//finally create the light
			psfxMgr->CreateSFX(SFX_DYNAMICLIGHT_ID, &dl);	
		}
	}
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CRiotClientShell::PlayMusic
//
//	PURPOSE:	Play the in-game music (especially CD audio)
//
// --------------------------------------------------------------------------- //

void CRiotClientShell::PlayMusic()
{
	// paranoia check - don't try to play unless the CMusic object is initialised
	if (m_Music.IsInitialized())
	{
		// play the correct music type!
		if (!m_Music.UsingIMA())
		{
			if (!m_Music.PlayCDList())
				g_pRiotClientShell->GetClientDE()->CPrint("PlayCDList FAILED");	
		}
		else
		{
			//g_pRiotClientShell->GetClientDE()->CPrint("PlayMusicLevel (IMA)");	
			m_Music.PlayMusicLevel(m_eMusicLevel);
		}
	}
}

// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CRiotClientShell::HandleGhostToggle
//
//	PURPOSE:	Toggle the ghosting capability of the Anubis
//
// --------------------------------------------------------------------------- //

void CRiotClientShell::HandleGhostToggle()
{
	ClientDE *pClientDE = g_pRiotClientShell->GetClientDE();
	if (m_nPlayerMode == PM_MODE_MCA_SA)
	{
		HMESSAGEWRITE hMessage = pClientDE->StartMessage(m_bGhostOn ? MID_GHOST_OFF : MID_GHOST_ON);
		pClientDE->EndMessage(hMessage);
		m_bGhostOn = m_bGhostOn ? DFALSE : DTRUE;
		m_stats.SetGhosted(m_bGhostOn);
	}
	else
	{
		HSTRING hStr = pClientDE->FormatString (IDS_NOTGHOSTCAPABLE);
		pClientDE->CPrint(pClientDE->GetStringData (hStr));
		m_infoDisplay.AddInfo(pClientDE->GetStringData (hStr), m_menu.GetFont08s(), 1.5f, DI_CENTER | DI_TOP);
		pClientDE->FreeString (hStr);
		// paranoia check.. make sure that ghosting is turned off if the player
		// is not in the Anubis
		if (m_bGhostOn)
		{
			m_bGhostOn = DFALSE;
			HMESSAGEWRITE hMessage = pClientDE->StartMessage(MID_GHOST_OFF);
			pClientDE->EndMessage(hMessage);
		}
		m_stats.SetGhosted(DFALSE);
	}
}