//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Draws the normal TF2 or HL2 HUD.
//
// $Workfile:     $
// $Date:         $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl2wars/clientmode_hl2warsnormal.h"
#include "vgui_int.h"
#include "hud.h"
#include <vgui/IInput.h>
#include <vgui/IPanel.h>
#include <vgui/ISurface.h>
#include <vgui_controls/AnimationController.h>
#include "iinput.h"
#include "ienginevgui.h"
#include <vgui_controls/Panel.h>
#include <vgui/IVGui.h>

#include "hl2wars/c_hl2wars_player.h"
#include "hl2wars/in_buttons_rts.h"
#include "c_ai_basenpc.h"
#include "in_buttons.h"
#include "c_rts_globalresource.h"
#include "hl2wars/rts_tracefilter.h"
#include "tempent.h"
#include "c_te_legacytempents.h"
#include "hl2wars/c_rts_mouse_brush.h"
#include "hl2wars/c_rts_mouse_model.h"
#include "hl2wars/c_rts_basebuilding.h"
#include "fx_quad.h"
#include "ClientEffectPrecacheSystem.h"

#include "engine/IVDebugOverlay.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
vgui::HScheme g_hVGuiCombineScheme = 0;

CLIENTEFFECT_REGISTER_BEGIN( PrecacheMouseCursorFX)
CLIENTEFFECT_MATERIAL( "effects/select" )
CLIENTEFFECT_REGISTER_END()

// Instance the singleton and expose the interface to it.
IClientMode *GetClientModeNormal()
{
	static ClientModeHL2WarsNormal g_ClientModeNormal;
	return &g_ClientModeNormal;
}

ClientModeHL2WarsNormal* GetClientModeHL2WarsNormal()
{
	Assert( dynamic_cast< ClientModeHL2WarsNormal* >( GetClientModeNormal() ) );

	return static_cast< ClientModeHL2WarsNormal* >( GetClientModeNormal() );
}

int ClientModeHL2WarsNormal::GetDeathMessageStartHeight( void )
{
	return m_pViewport->GetDeathMessageStartHeight();
}

IViewPortPanel* CHudViewport::CreatePanelByName( const char *szPanelName )
{
	return BaseClass::CreatePanelByName( szPanelName ); 
}

CHudViewport::CHudViewport()
{
	m_iCursor = CURSOR_NORMAL;

	m_clrMouseCursor = Color(255, 255, 255, 255);

	// load mouse cursors
	m_iMouseCursor[CURSOR_NORMAL] = vgui::surface()->CreateCursorFromFile( "resource/arrows/default_cursor.cur" );
	m_iMouseCursor[CURSOR_ATTACK] = vgui::surface()->CreateCursorFromFile( "resource/arrows/attack_cursor.cur" );
	m_iMouseCursor[CURSOR_ABILITY] = vgui::surface()->CreateCursorFromFile( "resource/arrows/ability_cursor.ani" );
	m_iMouseCursor[CURSOR_CAPTURE] = vgui::surface()->CreateCursorFromFile( "resource/arrows/capture_cursor.ani" );

	SetCursor( m_iMouseCursor[0] );

	// init on null
	m_pMainPreviewEnt = NULL;
	m_pMouseOverEnt = NULL;
	pCursorEnt = NULL;
	m_bDrawDirectionArrow = true;
	m_pDrawSelectionB = NULL;
}

void CHudViewport::LevelInit()
{
	/*MDLCACHE_CRITICAL_SECTION();
	struct model_t *pBuildModel = (model_t *) engine->LoadModel( "models/combine_turrets/floor_turret.mdl" );
	pCursorEnt = tempents->SpawnTempModel( pBuildModel, Vector(0, 0, 0), QAngle(0, 0, 0), Vector( 0.0f, 0.0f, 0.0f), 1, FTENT_NEVERDIE );
	pCursorEnt->AddEffects(EF_NODRAW);
	m_ProjectTextureArrow.Init("decals/arrow", TEXTURE_GROUP_DECAL );*/
}

void CHudViewport::LevelShutdown( void )
{
	m_pMouseOverEnt = NULL;
	m_bAllowBuildEnt = false;
	pCursorEnt = NULL;

	m_pMainPreviewEnt = NULL;
	m_SubPreviewEnts.Purge();

	// this code is useless. Tempents are already removed before this is being called!
	/*if( m_pMainPreviewEnt )
	{
		m_pMainPreviewEnt->DestroyProjectedTextureUnlit();
		m_pMainPreviewEnt->die = NULL;
		m_pMainPreviewEnt = NULL;
	}

	if( pCursorEnt )
	{
		pCursorEnt->DestroyProjectedTextureUnlit();
		pCursorEnt->die = NULL;
		pCursorEnt = NULL;
	}*/

	m_ProjectTextureArrow.Shutdown();
}

void CHudViewport::Paint()
{
	BaseClass::Paint();

	DrawSelectionBox();
	DrawVisualsSelection();
}

void CHudViewport::OnThink()
{
	BaseClass::OnThink();

	if( !engine->IsInGame() )
		return;

	// get local player
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	pPlayer->UpdateCurPosition();

	UpdateHover();
	UpdateMouseCursor();
	::input->GetFullscreenMousePosRTS(&m_iX, &m_iY);
	UpdateAbility();	
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::UpdateHover( void )
{
	// get local player
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	// Check if the mouse points to a npc, if so, return the npc
    //trace_t tr;
    //Vector forward;
    //AngleVectors(pPlayer->EyeAngles(),&forward);	//Get the forward vector frow our own eye angles.
    
	//CTraceFilterRTS TraceFiler( pPlayer );
	//CTraceFilterRTS *pTraceFiler = &TraceFiler;

	//UTIL_TraceHull( pPlayer->Weapon_ShootPosition(), pPlayer->Weapon_ShootPosition() + (pPlayer->m_vecPickingRayMouse *  8192), -Vector(16, 16, 16), Vector(16, 16, 16), MASK_SOLID, pTraceFiler, &tr ); 

	C_BaseEntity *pEnt = GetEntityMouse();

	// update selection visuals
	if( pEnt )		// we hitted an entity, now find out if it interests us
	{
		if( pEnt != m_pMouseOverEnt.Get() )
		{
			if( m_pMouseOverEnt.Get() )
			{
				// Clear old
				if( m_pMouseOverEnt.Get()->IsRTSBrush() )
				{
					C_MouseRTSBrush *pBrush = dynamic_cast<C_MouseRTSBrush *>(m_pMouseOverEnt.Get());
					if( pBrush )
						pBrush->OnCursorExited();
				}
				else if( m_pMouseOverEnt.Get()->IsRTSModel() )
				{
					C_MouseRTSModel *pModel = dynamic_cast<C_MouseRTSModel *>(m_pMouseOverEnt.Get());
					if( pModel )
						pModel->OnCursorExited();
				}
			}

			m_pMouseOverEnt = dynamic_cast<C_BaseEntity *>(pEnt);

			// activate new
			if( m_pMouseOverEnt->IsRTSBrush() )
			{
				C_MouseRTSBrush *pBrush = dynamic_cast<C_MouseRTSBrush *>(m_pMouseOverEnt.Get());
				if( pBrush )
					pBrush->OnCursorEntered();
			}
			else if( m_pMouseOverEnt->IsRTSModel() )
			{
				C_MouseRTSModel *pModel = dynamic_cast<C_MouseRTSModel *>(m_pMouseOverEnt.Get());
				if( pModel )
					pModel->OnCursorEntered();			
			}
		}
		
		/*if( m_pMouseOverEnt.Get() )
		{
			if( m_pMouseOverEnt->IsRTSBrush() )
			{
				C_MouseRTSBrush *pBrush = dynamic_cast<C_MouseRTSBrush *>(m_pMouseOverEnt.Get());
				if( pBrush )
					pBrush->OnCursorHover();
			}
			else if( m_pMouseOverEnt->IsRTSModel() )
			{
				C_MouseRTSModel *pModel = dynamic_cast<C_MouseRTSModel *>(m_pMouseOverEnt.Get());
				if( pModel )
					pModel->OnCursorHover();			
			}
		}*/
	}
	else
	{
		// We should always hit an entity ( the world )
		Assert( 0 );
	}

	// update mouse cursor visuals
	if( pPlayer->GetSelectedAbility() != 0 )
	{
		m_iCursor = CURSOR_ABILITY;
	}
	else if( pEnt )
	{
		if( pEnt->IsNPC() )
		{
			m_iCursor = CURSOR_ATTACK;
		}
		else if( pEnt->IsRTSBrush() )
		{
			C_MouseRTSBrush *pBrush = dynamic_cast<C_MouseRTSBrush *>(m_pMouseOverEnt.Get());
			if( pBrush && ( pBrush->GetBrushType() == MOUSEBRUSH_ORDER ) )
			{
				m_iCursor = CURSOR_CAPTURE;
			}
			else
			{
				m_iCursor = CURSOR_ATTACK;
			}
		}
		else if( pEnt->IsRTSModel() )
		{
			C_MouseRTSModel *pModel = dynamic_cast<C_MouseRTSModel *>(m_pMouseOverEnt.Get());
			if( pModel && pModel->IsAlive() && ( pModel->GetBrushType() == MOUSEBRUSH_ORDER ) )
			{
				m_iCursor = CURSOR_CAPTURE;
			}
			else
			{
				m_iCursor = CURSOR_ATTACK;
			}
		}
		else
		{
			m_iCursor = CURSOR_NORMAL;
		}
	}
	else
	{
		m_iCursor = CURSOR_NORMAL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudViewport::UpdateMouseCursor()
{
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	// this shouldn't happen
	if( !pCursorEnt )
	{
		MDLCACHE_CRITICAL_SECTION();
		struct model_t *pBuildModel = (model_t *) engine->LoadModel( "models/combine_turrets/floor_turret.mdl" );
		pCursorEnt = tempents->SpawnTempModel( pBuildModel, Vector(0, 0, 0), QAngle(0, 0, 0), Vector( 0.0f, 0.0f, 0.0f), 1, FTENT_NEVERDIE );
		pCursorEnt->AddEffects(EF_NODRAW);
		m_ProjectTextureArrow.Init("decals/arrow", TEXTURE_GROUP_DECAL );
	}

	// draw the mouse arrow if needed
	if( (pPlayer->m_nMouseButtons & IN_MOUSERIGHT) && pCursorEnt )
	{
		if( (pPlayer->GetPressedPosition() - pPlayer->GetCurPosition() ).Length2D() > 64.0f )
		{
			if( !pCursorEnt->HasProjectedTextureUnlit() )
			{
				ProjectTextureUnlitInfo_t info;
				info.m_PTUnlitShadow = &(m_ProjectTextureArrow);
				info.m_PTUnlitMins = Vector(-8, -16, 0);
				info.m_PTUnlitMaxs = Vector(112, 16, 50);
				info.m_vOrigin = pCursorEnt->GetRenderOrigin();
				info.m_Angle = pCursorEnt->GetRenderAngles();

				pCursorEnt->CreateProjectedTextureUnlit( info );
			}

			pCursorEnt->SetAbsAngles( UTIL_CalculateDirection(pPlayer->GetPressedPosition(), pPlayer->GetCurPosition()) );
		}
		else
		{
			if( pCursorEnt->HasProjectedTextureUnlit() )
			{
				pCursorEnt->DestroyProjectedTextureUnlit();
			}
		}
	}
	else
	{
		if( pCursorEnt->HasProjectedTextureUnlit() )
		{
			pCursorEnt->DestroyProjectedTextureUnlit();
		}
	}

	// change cursor
	SetCursor( m_iMouseCursor[m_iCursor] );
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudViewport::DrawRightClick()
{
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	Vector pos = pPlayer->GetPressedPosition();

	const Vector color = Vector(0.0f, 1.0f, 0.0f);
	pos[2] += 1.0f; // let it fly just a little bit above the ground

	FX_AddQuad(pos, pPlayer->GetPressedNormal(), 40.0f, 0.0f, 4.5f, 0.0f, 255.0f, 100.0f, 
		0.0f, 0.0f, color, 1.0f, QUAD_TO_SELECT, 0);
}

//-----------------------------------------------------------------------------
// Purpose: Draw health bars of selection units
//-----------------------------------------------------------------------------
void CHudViewport::DrawVisualsSelection()
{
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	const Vector color = g_RTSR->GetColor( pPlayer->GetTeamRTSID() );
	switch( pPlayer->GetSelectionType() ) {
		case SELECTION_UNIT:
			for( int i = 0; i < MAXSELECTED; i++) 
			{
				if( pPlayer->m_HLWLocal.m_hSelectedUnits[i] ) 
				{
					DrawHealthBar( pPlayer->m_HLWLocal.m_hSelectedUnits[i].Get());
				}
			}

			break;
		case SELECTION_BUILDING:
			if( pPlayer->GetSelectedBuilding() && pPlayer->GetSelectedBuilding()->IsRTSModel() ) 
			{
				DrawHealthBar( pPlayer->GetSelectedBuilding() );
			}

			break;
		default:
			DevMsg("Invalid selection type! \n");
			break;
	}

	DrawMouseOverEntity();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::DrawMouseOverEntity( void )
{
	if( GetMouseOverEntity() )
	{
		if( GetMouseOverEntity()->IsNPC() )
			DrawHealthBar( GetMouseOverEntity()->MyNPCPointer() );
		else if( GetMouseOverEntity()->IsRTSModel() )
		{
			C_MouseRTSModel *pModel = dynamic_cast<C_MouseRTSModel *>(m_pMouseOverEnt.Get());
			if( pModel )
				pModel->OnCursorHover();		

			/*C_BaseBuildingModel *pBuilding = dynamic_cast<C_BaseBuildingModel *>(GetMouseOverEntity());
			if( pBuilding )
			{
				//if( pBuilding->GetRealMouseOverEntity() )
				//	DrawHealthBar(pBuilding->GetRealMouseOverEntity());
				//else
					DrawHealthBar(pBuilding);
			}*/
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Draw health bar
//-----------------------------------------------------------------------------
void CHudViewport::DrawHealthBar( C_BaseEntity *pTarget )
{
	/*
	// get the percentage health
	float weigth = (float)pTarget->GetHealth() / (float)pTarget->GetMaxHealth();
	int healthSize = (int)(weigth * vgui::scheme()->GetProportionalScaledValue( 30 ) );

	// get the position on the screen of the npc
	int xpos = 0, ypos = 0;
	GetVectorInScreenSpace(pTarget->GetAbsOrigin(), xpos, ypos);
	//Msg("Draw health, x: %d, y: %d \n", xpos, ypos );

	// calculate the colors
	int red = 255 - (int)(weigth * 255.0f);
	int green = (int)(weigth * 255.0f);

	// draw the outlined rect
	vgui::surface()->DrawSetColor( Color( 255,255,255,200 ) );
	vgui::surface()->DrawOutlinedRect(
		xpos - vgui::scheme()->GetProportionalScaledValue( 15 ), 
		ypos + vgui::scheme()->GetProportionalScaledValue( 15 ), 
		xpos + vgui::scheme()->GetProportionalScaledValue( 15 ), 
		ypos + vgui::scheme()->GetProportionalScaledValue( 17 )
	);

	// draw how much health we still got
	vgui::surface()->DrawSetColor( Color( red, green, 20, 160 ) );
	vgui::surface()->DrawFilledRect(
		xpos - vgui::scheme()->GetProportionalScaledValue( 15 ), 
		ypos + vgui::scheme()->GetProportionalScaledValue( 15 ), 
		( xpos - vgui::scheme()->GetProportionalScaledValue( 15 ) ) + healthSize, 
		ypos + vgui::scheme()->GetProportionalScaledValue( 17 )
	);
*/
	// new: 
	Vector mins, maxs, origin, position;
	QAngle angles;
	float weigth;
	int mins_x, mins_y, maxs_x, maxs_y, healthSize, width, red, green; 

	// get the percentage health
	weigth = (float)pTarget->GetHealth() / (float)pTarget->GetMaxHealth();

	// calculate the colors
	red = 255 - (int)(weigth * 255.0f);
	green = (int)(weigth * 255.0f);

	// get the mins and maxs and origin
	ICollideable* pCol = pTarget->GetCollideable(); 
	mins = pCol->OBBMins();
	maxs = pCol->OBBMaxs();
	position = pTarget->GetAbsOrigin();

	// transform into the world
	matrix3x4_t xform; 
	AngleMatrix( pTarget->GetAbsAngles(), position, xform ); 
	Vector transformedMins, transformedMaxs; 
	TransformAABB( xform, mins, maxs, transformedMins, transformedMaxs ); 

	// get the other three points
	Vector point1, point2, point3;

	point1.x = transformedMaxs.x;
	point1.y = transformedMins.y;
	point1.z = transformedMins.z;

	point2.x = transformedMins.x;
	point2.y = transformedMaxs.y;
	point2.z = transformedMins.z;

	point3.x = transformedMaxs.x;
	point3.y = transformedMaxs.y;
	point3.z = transformedMins.z;

	int temp_x, temp_y;

	mins_x = 9999999;
	maxs_x = -1;
	mins_y = -1;
	maxs_y = -1;

	// find the smallest and biggest values
	GetVectorInScreenSpace(transformedMins, temp_x, temp_y ); 
	if( temp_x < mins_x )
		mins_x = temp_x;
	if( temp_x > maxs_x )
		maxs_x = temp_x;
	if( temp_y > mins_y )
		mins_y = temp_y;

	GetVectorInScreenSpace(point1, temp_x, temp_y ); 
	if( temp_x < mins_x )
		mins_x = temp_x;
	if( temp_x > maxs_x )
		maxs_x = temp_x;
	if( temp_y > mins_y )
		mins_y = temp_y;

	GetVectorInScreenSpace(point2, temp_x, temp_y ); 
	if( temp_x < mins_x )
		mins_x = temp_x;
	if( temp_x > maxs_x )
		maxs_x = temp_x;
	if( temp_y > mins_y )
		mins_y = temp_y;

	GetVectorInScreenSpace(point3, temp_x, temp_y ); 
	if( temp_x < mins_x )
		mins_x = temp_x;
	if( temp_x > maxs_x )
		maxs_x = temp_x;
	if( temp_y > mins_y )
		mins_y = temp_y;

	// calculate the health bar
	width = maxs_x - mins_x;
	healthSize = (int)(weigth * width );

	// draw the health bar
	vgui::surface()->DrawSetColor( Color( 255,255,255,200 ) );
	vgui::surface()->DrawOutlinedRect(
		mins_x, 
		mins_y - vgui::scheme()->GetProportionalScaledValue( 3 ), 
		maxs_x, 
		mins_y 
	);

	// draw how much health we still got
	vgui::surface()->DrawSetColor( Color( red, green, 100, 160 ) );
	vgui::surface()->DrawFilledRect(
		mins_x, 
		mins_y - vgui::scheme()->GetProportionalScaledValue( 3 ), 
		mins_x + healthSize, 
		mins_y
	);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudViewport::DrawSelectionBox( )
{
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	if( pPlayer->m_nMouseButtons & IN_MOUSELEFT ) {
		Color color = Color( 75, 75, 75, 90 );
		Color colorol = Color( 0, 0, 0, 115 );
		if( pPlayer->m_iMouse_x_pressed_left < m_iX && pPlayer->m_iMouse_y_pressed_left < m_iY) {
			vgui::surface()->DrawSetColor( colorol );
			vgui::surface()->DrawOutlinedRect( pPlayer->m_iMouse_x_pressed_left, pPlayer->m_iMouse_y_pressed_left, m_iX, m_iY);
			vgui::surface()->DrawSetColor( color );
			vgui::surface()->DrawFilledRect( pPlayer->m_iMouse_x_pressed_left, pPlayer->m_iMouse_y_pressed_left, m_iX, m_iY); 
		}
		else if( pPlayer->m_iMouse_x_pressed_left < m_iX && pPlayer->m_iMouse_y_pressed_left > m_iY) {
			vgui::surface()->DrawSetColor( colorol );
			vgui::surface()->DrawOutlinedRect( pPlayer->m_iMouse_x_pressed_left, m_iY, m_iX, pPlayer->m_iMouse_y_pressed_left);
			vgui::surface()->DrawSetColor( color );
			vgui::surface()->DrawFilledRect( pPlayer->m_iMouse_x_pressed_left, m_iY, m_iX, pPlayer->m_iMouse_y_pressed_left); 
		}
		else if(pPlayer->m_iMouse_x_pressed_left > m_iX && pPlayer->m_iMouse_y_pressed_left < m_iY) {
			vgui::surface()->DrawSetColor( colorol );
			vgui::surface()->DrawOutlinedRect(m_iX, pPlayer->m_iMouse_y_pressed_left, pPlayer->m_iMouse_x_pressed_left, m_iY);
			vgui::surface()->DrawSetColor( color );
			vgui::surface()->DrawFilledRect(m_iX, pPlayer->m_iMouse_y_pressed_left, pPlayer->m_iMouse_x_pressed_left, m_iY); 
		}
		else {
			vgui::surface()->DrawSetColor( colorol );
			vgui::surface()->DrawOutlinedRect( m_iX, m_iY, pPlayer->m_iMouse_x_pressed_left, pPlayer->m_iMouse_y_pressed_left);
			vgui::surface()->DrawSetColor( color );
			vgui::surface()->DrawFilledRect(m_iX, m_iY, pPlayer->m_iMouse_x_pressed_left, pPlayer->m_iMouse_y_pressed_left); 
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudViewport::UpdateAbility()
{
	C_HL2Wars_Player* pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer || pPlayer->GetSelectedAbility() == 0 ) {
		m_iCurrentAbility = 0;
		m_bDrawDirectionArrow = true;
		DestroyPreviewEnt();
		return;
	}

	// check for change
	if( pPlayer->GetSelectedAbility() != m_iCurrentAbility )
	{
		DestroyPreviewEnt();
		m_iCurrentAbility = pPlayer->GetSelectedAbility();
		m_bAllowBuildEnt = true;
		m_bDrawDirectionArrow = true;
	}

	C_AI_BaseNPC *pNPC = pPlayer->m_HLWLocal.m_hSelectedUnits[ pPlayer->GetHighLightedUnit() ].Get();
	if( !pNPC )
		return;

	FileUnitInfo_t *pFUI = GetFileUnitInfoFromHandle( LookupUnitInfoSlot( STRING( pNPC->GetUnitType() ) ) );
	if( !pFUI )
		return;

	FileAbilityInfo_t *pFAI = GetFileAbilityInfoFromHandle( pFUI->m_iAbilities[pPlayer->GetSelectedAbility()-1] );
	if( !pFAI )
		return;

	m_bDrawDirectionArrow = pFAI->m_bRotate;

	// now check if we need to do something
	int visual_helper = pFAI->m_iVisualHelper;
	switch( visual_helper )
	{
		case VISUAL_NONE:
			break;
		case VISUAL_BUILD:
			{
				if( m_pMainPreviewEnt )
				{	
					Vector mins, maxs;
					m_pMainPreviewEnt->GetRenderBounds( mins, maxs );

					if( UTIL_ValidBuildingPosition( m_pMainPreviewEnt->GetAbsOrigin(), m_pMainPreviewEnt->GetAbsAngles(), mins, maxs, pFAI->m_fTolerance, false, pNPC->GetTeamRTSID() ) )
						UpdatePreviewEnt(0, 255, 0, 200);
					else
						UpdatePreviewEnt(255, 0, 0, 200);

					if( !(pPlayer->m_nMouseButtons & IN_MOUSERIGHT) )
					{
						
						// update position
						UpdatePreviewEnt( pPlayer->GetCurPosition() + pFAI->m_vOffSet );
					}
					else if( pFAI->m_bRotate )
					{
						// leave position, but update direction
						UpdatePreviewEnt( UTIL_CalculateDirection( pPlayer->GetPressedPosition(), pPlayer->GetCurPosition() ) );
					}
				}
				else 
				{
					// avoid creating a new one directly after the last one is destroyed
					if( m_bAllowBuildEnt )
					{
						CreatePreviewEnt( pFAI, pPlayer );
					}
				}
				break;
			}
		default:
			break;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::CreatePreviewEnt( FileAbilityInfo_t *pFAI, C_HL2Wars_Player* pPlayer )
{
	m_bAllowBuildEnt = false;		// allow create once after current abiltiy change.

	MDLCACHE_CRITICAL_SECTION();
	struct model_t *pBuildModel = (model_t *) engine->LoadModel( pFAI->m_szModel );
	QAngle angles;
	angles[0] = angles[1] = angles[2] = 0.0f;
	m_pMainPreviewEnt = tempents->SpawnTempModel( pBuildModel, pPlayer->GetCurPosition() + pFAI->m_vOffSet, angles, Vector( 0.0f, 0.0f, 0.0f), 1, FTENT_NEVERDIE );
	if( m_pMainPreviewEnt )
	{
		m_pMainPreviewEnt->SetRenderMode( kRenderTransColor );
		m_pMainPreviewEnt->SetRenderColor( 0, 255, 0, 200 );

		// if we have a projected texture, create it
		if( pFAI->m_ProjectTexture.IsValid() )
		{
			ProjectTextureUnlitInfo_t info;
			info.m_PTUnlitShadow = &(pFAI->m_ProjectTexture);
			info.m_PTUnlitMins = pFAI->m_vPTMin;
			info.m_PTUnlitMaxs = pFAI->m_vPTMax;
			info.m_cR = pFAI->m_cR;
			info.m_cG = pFAI->m_cG;
			info.m_cB = pFAI->m_cB;
			info.m_cA = pFAI->m_cA;
			info.m_vOrigin = m_pMainPreviewEnt->GetRenderOrigin();
			info.m_Angle = m_pMainPreviewEnt->GetRenderAngles();

			m_pMainPreviewEnt->CreateProjectedTextureUnlit( info );
		}
	}

	// create the sub ents. Parent them to the main preview ent
	if( !pFAI->m_pComponentKeyValues )
		return;

	C_LocalTempEntity *sub_ent;
	Vector origin, temp;
	for ( KeyValues *sub = pFAI->m_pComponentKeyValues->GetFirstSubKey(); sub != NULL ; sub = sub->GetNextKey() )
	{
		UTIL_StringToVector( origin.Base(), sub->GetString("origin", "0 0 0") );
		UTIL_StringToVector( temp.Base(), sub->GetString("angles", "0 0 0") );
		angles = QAngle(temp.x, temp.y, temp.z);

		pBuildModel = (model_t *) engine->LoadModel( sub->GetString("model") );
		QAngle angles;
		angles[0] = angles[1] = angles[2] = 0.0f;
		sub_ent = tempents->SpawnTempModel( pBuildModel, m_pMainPreviewEnt->GetAbsOrigin() + origin, angles, Vector( 0.0f, 0.0f, 0.0f), 1, FTENT_NEVERDIE );
		if( sub_ent )
		{
			sub_ent->SetRenderMode( kRenderTransColor );
			sub_ent->SetRenderColor( 0, 255, 0, 200 );
			sub_ent->SetParent(m_pMainPreviewEnt);	// follow the main ent!
			m_SubPreviewEnts.AddToTail(sub_ent);
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::UpdatePreviewEnt( byte r, byte g, byte b, byte a )
{
	m_pMainPreviewEnt->SetRenderColor( r, g, b, a );

	for( int i = 0; i < m_SubPreviewEnts.Count(); i++ )
	{
		if( m_SubPreviewEnts.Element(i) )
		{
			m_SubPreviewEnts.Element(i)->SetRenderColor( r, g, b, a );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::UpdatePreviewEnt( Vector origin )
{
	Vector old_origin = m_pMainPreviewEnt->GetAbsOrigin();
	m_pMainPreviewEnt->SetAbsOrigin( origin );

	for( int i = 0; i < m_SubPreviewEnts.Count(); i++ )
	{
		if( m_SubPreviewEnts.Element(i) )
		{
			m_SubPreviewEnts.Element(i)->SetAbsOrigin( m_SubPreviewEnts.Element(i)->GetAbsOrigin() + (origin - old_origin ) );	
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::UpdatePreviewEnt( QAngle angle )
{
	m_pMainPreviewEnt->SetAbsAngles( angle );

	for( int i = 0; i < m_SubPreviewEnts.Count(); i++ )
	{
		if( m_SubPreviewEnts.Element(i) )
		{
			m_SubPreviewEnts.Element(i)->SetAbsAngles( angle );	
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudViewport::DestroyPreviewEnt()
{
	if( m_pMainPreviewEnt )
	{
		m_pMainPreviewEnt->DestroyProjectedTextureUnlit();
		m_pMainPreviewEnt->die = NULL;
		m_pMainPreviewEnt = NULL;
	}

	for( int i = 0; i < m_SubPreviewEnts.Count(); i++ )
	{
		if( m_SubPreviewEnts.Element(i) )
		{
			m_SubPreviewEnts.Element(i)->DestroyProjectedTextureUnlit();
			m_SubPreviewEnts.Element(i)->die = NULL;
		}
	}

	m_SubPreviewEnts.Purge();
}


// mouse listeners for the panel
void CHudViewport::OnCursorMoved(int x, int y)
{
}

void CHudViewport::OnCursorEntered()
{
}

void CHudViewport::OnCursorExited()
{
}


//-----------------------------------------------------------------------------
// Purpose:  Sends the mouse clicks to the server side.
//-----------------------------------------------------------------------------
void CHudViewport::OnMousePressed( MouseCode code )
{
	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	pPlayer->SetActivePanel( this );

	pPlayer->UpdatePressedPosition();

	switch( code ) {
		case MOUSE_LEFT:
			pPlayer->m_nMouseButtons |= IN_MOUSELEFT;
			::input->GetFullscreenMousePosRTS(&pPlayer->m_iMouse_x_pressed_left, &pPlayer->m_iMouse_y_pressed_left);
			break;
		case MOUSE_RIGHT:
			{
				if( !m_pMouseOverEnt.Get() || !m_pMouseOverEnt.Get()->IsNPC() )
					DrawRightClick();

				if( pCursorEnt )
					pCursorEnt->SetAbsOrigin( pPlayer->GetCurPosition() );

				pPlayer->m_nMouseButtons |= IN_MOUSERIGHT;
				//::input->GetFullscreenMousePosRTS(&pPlayer->m_iMouse_x_pressed_right, &pPlayer->m_iMouse_y_pressed_right);
			}
			break;
	}	
}

//-----------------------------------------------------------------------------
// Purpose:  Sends the mouse clicks to the server side.
//-----------------------------------------------------------------------------
void CHudViewport::OnMouseDoublePressed(MouseCode code)
{
	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	switch( code ) {
		case MOUSE_LEFT:
			SelectAllInScreenOfType(GetEntityMouse());
			pPlayer->m_nMouseButtons |= IN_MOUSELEFTDOUBLE;
			::input->GetFullscreenMousePosRTS(&pPlayer->m_iMouse_x_pressed_left, &pPlayer->m_iMouse_y_pressed_left);
			break;
		case MOUSE_RIGHT:
			pPlayer->m_nMouseButtons |= IN_MOUSERIGHTDOUBLE;
			::input->GetFullscreenMousePosRTS(&pPlayer->m_iMouse_x_pressed_right, &pPlayer->m_iMouse_y_pressed_right);
			break;
	}

	
}

void CHudViewport::OnMouseTriplePressed(MouseCode code)
{
}

//-----------------------------------------------------------------------------
// Purpose:  Sends the mouse clicks to the server side.
//-----------------------------------------------------------------------------
void CHudViewport::OnMouseReleased(MouseCode code)
{
	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	if( !pPlayer->IsActivePanel( this ) )
	{
		if( pPlayer->ReleaseActivePanel( code ) )
			return;
	}

	// do everything we need before clearing the masks
	pPlayer->UpdateReleasedPosition();

	// clear
	switch( code ) {
		case MOUSE_LEFT:
			{
				if( abs(pPlayer->GetReleasedPosition().x - pPlayer->GetPressedPosition().x) > 10 &&
					abs(pPlayer->GetReleasedPosition().y - pPlayer->GetPressedPosition().y) > 10) {
					SelectBox();	
				}
				pPlayer->m_nMouseButtons &= ~IN_MOUSELEFT;
				pPlayer->m_nMouseButtons &= ~IN_MOUSELEFTDOUBLE;
				break;
			}
		case MOUSE_RIGHT:
			pPlayer->m_nMouseButtons &= ~IN_MOUSERIGHT;
			pPlayer->m_nMouseButtons &= ~IN_MOUSERIGHTDOUBLE;
			break;
	}

	pPlayer->SetActivePanel( NULL );
}

extern ConVar cl_scrolltimeout;
void CHudViewport::OnMouseWheeled(int delta)
{
	C_HL2Wars_Player* player = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if (player) 
	{
		if( delta > 0 )
			player->m_fScrollBackwardsTimeOut = gpGlobals->curtime + cl_scrolltimeout.GetFloat();
		else
			player->m_fScrollForwardTimeOut = gpGlobals->curtime + cl_scrolltimeout.GetFloat();

		// we are in rts mode, so we don't care about the rest
		return;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHudViewport::SelectBox()
{
	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	int x, y;
	::input->GetFullscreenMousePosRTS(&x, &y);

	// first clear selection, if duck key ain't pressed
	if( (pPlayer->m_nButtons & IN_DUCK) == 0 )
	{
		engine->ServerCmd( VarArgs( "hl2wars_clearselection") );
	}

	// find out the mins and maxs
	int xmin, xmax, ymin, ymax;
	xmin = ( pPlayer->m_iMouse_x_pressed_left < x ) ? pPlayer->m_iMouse_x_pressed_left : x;
	xmax = ( pPlayer->m_iMouse_x_pressed_left > x ) ? pPlayer->m_iMouse_x_pressed_left : x;
	ymin = ( pPlayer->m_iMouse_y_pressed_left < y ) ? pPlayer->m_iMouse_y_pressed_left : y;
	ymax = ( pPlayer->m_iMouse_y_pressed_left > y ) ? pPlayer->m_iMouse_y_pressed_left : y;

	// loop through all units we have
	for( int i = 0; i < g_RTSR->GetSize( pPlayer->GetTeamRTSID() ); i++ ) {
		// if we have a unit, check if the unit is in the box, else we break.
		C_AI_BaseNPC *pNPC = g_RTSR->GetUnit( pPlayer->GetTeamRTSID(), i);
		if( pNPC && pNPC->IsAlive() ) {
			int xnpc, ynpc;
			if( GetVectorInScreenSpace( pNPC->GetAbsOrigin(), xnpc, ynpc) )
			{
				if( xnpc > xmin && xnpc < xmax && ynpc > ymin && ynpc < ymax ) 
				{
					engine->ServerCmd( VarArgs( "hl2wars_addunit %i", pNPC->index ) );
				}
			}
		}
		else
			break;		// array is sorted, all units are placed in the begin, so break on first NULL pointer
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the first entity in the mouse ray
//-----------------------------------------------------------------------------
void CHudViewport::SelectAllInScreenOfType( C_BaseEntity *pType )
{
	if( !pType )
		return;

	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return;

	C_AI_BaseNPC *pNPCType = pType->MyNPCPointer();
	if( !pNPCType )
		return;

	// first clear selection, if duck key ain't pressed
	if( !(pPlayer->m_nButtons & IN_DUCK) )
	{
		engine->ServerCmd( VarArgs( "hl2wars_clearselection") );
	}

	// find out the mins and maxs
	int xmin, xmax, ymin, ymax;
	xmin = 0;
	xmax = ScreenWidth();
	ymin = 0;
	ymax = ScreenHeight();

	// loop through all units we have
	for( int i = 0; i < g_RTSR->GetSize( pPlayer->GetTeamRTSID() ); i++ ) {
		// if we have a unit, check if the unit is in the box, else we break.
		C_AI_BaseNPC *pNPC = g_RTSR->GetUnit( pPlayer->GetTeamRTSID(), i);
		if( pNPC && pNPC->IsAlive() ) {
			int xnpc, ynpc;
			if( GetVectorInScreenSpace( pNPC->GetAbsOrigin(), xnpc, ynpc) )
			{
				if( xnpc > xmin && xnpc < xmax && ynpc > ymin && ynpc < ymax ) {
					if( !stricmp(pNPCType->GetUnitType(), pNPC->GetUnitType() )  )
					{
						engine->ServerCmd( VarArgs( "hl2wars_addunit %i", pNPC->index ) );
					}
				}
			}
		}
		else
			break;		// array is sorted, all units are placed in the begin, so break on first NULL pointer
	}
}

//-----------------------------------------------------------------------------
// Hits triggers with raycasts
//-----------------------------------------------------------------------------
/*class C_TriggerTraceEnum2 : public IEntityEnumerator
{
public:
	C_TriggerTraceEnum2( Ray_t *pRay, const Vector& dir, int contentsMask ) :
		m_VecDir(dir), m_ContentsMask(contentsMask), m_pRay(pRay)
	{
		m_pEnt = NULL;
		m_fDistance = 9999999.0f;
	}

	virtual bool EnumEntity( IHandleEntity *pHandleEntity )
	{
		if( m_pEnt )
			return false;

		C_BaseEntity *pEnt = EntityFromEntityHandle( pHandleEntity );
		Msg("CLIENT: Filtering entity in enum %s\n", pEnt->GetClassname() );

		// Done to avoid hitting an entity that's both solid & a trigger.
		if ( pEnt->IsRTSBrush() )
		{
			m_pEnt = pEnt;
			m_fDistance = (m_pRay->m_Start - pEnt->GetAbsOrigin() ).Length();
		}

		return true;
	}

	CBaseEntity *GetHitEnt() { return m_pEnt; }
	float GetDistance() { return m_fDistance; }

private:
	Vector m_VecDir;
	int m_ContentsMask;
	Ray_t *m_pRay;
	CBaseEntity *m_pEnt;
	float m_fDistance;
};*/

//-----------------------------------------------------------------------------
// Purpose: Get the first entity in the mouse ray
//-----------------------------------------------------------------------------
C_BaseEntity *CHudViewport::GetEntityMouse( void ) 
{
	// get local player
	C_HL2Wars_Player *pPlayer = C_HL2Wars_Player::GetLocalHL2WarsPlayer();
	if( !pPlayer )
		return NULL;

	// Check if the mouse points to a npc, if so, return the npc
    trace_t tr;

	CTraceFilterRTS TraceFiler( pPlayer );
	CTraceFilterRTS *pTraceFiler = &TraceFiler;

	// first try with mask_solid
	UTIL_TraceHull( pPlayer->Weapon_ShootPosition(), pPlayer->Weapon_ShootPosition() + (pPlayer->m_vecPickingRayMouse *  8192), -Vector(16,16,16), Vector(16,16,16), MASK_SOLID, pTraceFiler, &tr ); 
	//UTIL_TraceHull( pPlayer->Weapon_ShootPosition(), pPlayer->Weapon_ShootPosition() + (pPlayer->m_vecPickingRayMouse *  8192), -Vector(16,16,16), Vector(16,16,16), MASK_ALL, pTraceFiler, &tr ); 
	//debugoverlay->AddLineOverlay( Weapon_ShootPosition(), Weapon_ShootPosition() + (m_vecPickingRayMouse *  8192), 100, 55, 255, false, 5 ); 

	// oh, this looks hacky! Stupid bitches at valve don't give us the possibility to traceline a none solid?
	/*Ray_t ray;
	ray.Init( pPlayer->Weapon_ShootPosition(), pPlayer->Weapon_ShootPosition() + (pPlayer->m_vecPickingRayMouse *  8192) );

	C_TriggerTraceEnum2 triggerTraceEnum( &ray, pPlayer->m_vecPickingRayMouse, MASK_SHOT );
	enginetrace->EnumerateEntities( ray, true, &triggerTraceEnum );

	// check entity
    if (tr.m_pEnt ) 
    {
		if( triggerTraceEnum.GetHitEnt() )
		{
			float distance = (pPlayer->Weapon_ShootPosition() - tr.m_pEnt->GetAbsOrigin()).Length();
			Msg("CLIENT: Distance 1: %f %s, distance 2: %f %s\n", distance, tr.m_pEnt->GetClassname(), 
				triggerTraceEnum.GetDistance(), triggerTraceEnum.GetHitEnt()->GetClassname() );
			if( distance > triggerTraceEnum.GetDistance() )
			{
				Msg("CLIENT: Returning hit ent\n");
				return triggerTraceEnum.GetHitEnt();
			}
		}

		//Msg("Returning normal solid ent\n");

  	    return tr.m_pEnt;
    }
	else if( triggerTraceEnum.GetHitEnt() )
	{
		return triggerTraceEnum.GetHitEnt();
	}*/

    if (tr.m_pEnt ) 
    {
		//Msg("Client entity is %s\n", tr.m_pEnt->GetClassname() );
  	    return tr.m_pEnt;
    }

	return NULL;
}

//-----------------------------------------------------------------------------
// ClientModeHLNormal implementation
//-----------------------------------------------------------------------------
ClientModeHL2WarsNormal::ClientModeHL2WarsNormal()
{
	m_pViewport = new CHudViewport();
	m_pViewport->Start( gameuifuncs, gameeventmanager );

	m_pHL2WarsViewport = (CHudViewport *)m_pViewport;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
ClientModeHL2WarsNormal::~ClientModeHL2WarsNormal()
{
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ClientModeHL2WarsNormal::Init()
{
	BaseClass::Init();

	// Load up the combine control panel scheme
	g_hVGuiCombineScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/CombinePanelScheme.res", "CombineScheme" );
	if (!g_hVGuiCombineScheme)
	{
		Warning( "Couldn't load combine panel scheme!\n" );
	}
}

void ClientModeHL2WarsNormal::LevelInit( const char *newmap )
{
	BaseClass::LevelInit(newmap);

	CHudViewport *hudviewport = (CHudViewport *)m_pViewport;
	if( !hudviewport )
		return;		// huh?

	hudviewport->LevelInit();
}

void ClientModeHL2WarsNormal::LevelShutdown( void )
{
	BaseClass::LevelShutdown();

	CHudViewport *hudviewport = (CHudViewport *)m_pViewport;
	if( !hudviewport )
		return;		// huh?

	hudviewport->LevelShutdown();
}