//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Console commands for debugging and manipulating units and rts players.
//
//===========================================================================//

#include "cbase.h"
#include "ai_basenpc.h"
#include "hl2wars/hl2wars_player.h"
#include "hl2wars/rts_globalresource.h"
#include "entitylist.h"
#include "ndebugoverlay.h"
#include "datacache/imdlcache.h"
#include "hl2wars/rts_parsedata.h"
#include "hl2wars/ai_rts_strategic.h"
#include "hl2wars/util_hl2wars.h"
#include "hl2wars/npc/hlw_npc_strider.h"
#include "hl2wars/util_hl2wars_shared.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

extern ConVar npc_create_equipment;

//------------------------------------------------------------------------------
// Purpose: Create an NPC of the given type and given team id
//------------------------------------------------------------------------------
void CC_Unit_Create_c( const CCommand &args )
{
	MDLCACHE_CRITICAL_SECTION();

	bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
	CBaseEntity::SetAllowPrecache( true );

	// Try to create entity
	CAI_BaseNPC *baseNPC = dynamic_cast< CAI_BaseNPC * >( CreateEntityByName(args[1]) );
	if (baseNPC)
	{
		baseNPC->KeyValue( "additionalequipment", npc_create_equipment.GetString() );
		baseNPC->Precache();

			CHL2Wars_Player* pPlayer = ToHL2WarsPlayer( UTIL_GetCommandClient() );
		if ( args.ArgC() == 4 )
		{
			baseNPC->SetTeamRTSID( atoi( args[2] ) );
			baseNPC->SetName( AllocPooledString( args[3] ) );
		}
		else if( args.ArgC() == 3 )
		{
			baseNPC->SetTeamRTSID( atoi( args[2] ) );
		}
		else
		{
			baseNPC->SetTeamRTSID( pPlayer->GetTeamRTSID() );
		}

		DispatchSpawn(baseNPC);
		// Now attempt to drop into the world
		trace_t tr;
		Vector aim;
		VectorCopy( pPlayer->GetMouseAim(), aim );
    
		AI_TraceLine(pPlayer->Weapon_ShootPosition(),
			pPlayer->Weapon_ShootPosition() + aim * MAX_TRACE_LENGTH,MASK_NPCSOLID, 
			pPlayer, COLLISION_GROUP_NONE, &tr );
		if ( tr.fraction != 1.0)
		{
			if (baseNPC->CapabilitiesGet() & bits_CAP_MOVE_FLY)
			{
				Vector pos = tr.endpos - aim * 36;
				baseNPC->Teleport( &pos, NULL, NULL );
			}
			else
			{
				// Raise the end position a little up off the floor, place the npc and drop him down
				tr.endpos.z += 12;
				baseNPC->Teleport( &tr.endpos, NULL, NULL );
				UTIL_DropToFloor( baseNPC, MASK_NPCSOLID );
			}

			// fix for strider, because we love having fun with it
			if( FClassnameIs( baseNPC, "hlw_npc_strider" ) )
			{
				CHLW_NPC_Strider *strider = (CHLW_NPC_Strider *)baseNPC;
				baseNPC->SetAbsOrigin( baseNPC->GetAbsOrigin() + Vector( 0, 0, strider->GetMaxHeight() ) );
			}

			// Now check that this is a valid location for the new npc to be
			Vector	vUpBit = baseNPC->GetAbsOrigin();
			vUpBit.z += 1;

			AI_TraceHull( baseNPC->GetAbsOrigin(), vUpBit, baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), 
				MASK_NPCSOLID, baseNPC, COLLISION_GROUP_NONE, &tr );
			if ( tr.startsolid || (tr.fraction < 1.0) )
			{
				baseNPC->SUB_Remove();
				DevMsg("Can't create %s.  Bad Position!\n",args[1]);
				NDebugOverlay::Box(baseNPC->GetAbsOrigin(), baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), 255, 0, 0, 0, 0);
			}
		}

		baseNPC->Activate();
	}
	CBaseEntity::SetAllowPrecache( allowPrecache );
}
static ConCommand unit_create_c("unit_create_c", CC_Unit_Create_c, "Creates an unit of the given type where the mouse of the player is aimed to. \n\tArguments:	{npc_class_name}, { teamid }", FCVAR_CHEAT);

//------------------------------------------------------------------------------
// Purpose: Create an NPC of the given type
//------------------------------------------------------------------------------
void CC_Unit_Create( const CCommand &args )
{
	MDLCACHE_CRITICAL_SECTION();

	const char *unit_type = args[1]; 

	bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
	CBaseEntity::SetAllowPrecache( true );

	//Msg("Creating unit %s\n", unit_type );
	int unit_index = g_pRTSResource->GetUnitIndex( unit_type );	// this will create a new entry, if the unit ain't loaded yet


	FileUnitInfo_t *pFUI = GetFileUnitInfoFromHandle( LookupUnitInfoSlot( unit_type ) );
	if( !pFUI ) {
		Msg("Missing unit entry for %s!\n", unit_type );
		return;
	}

	// Try to create entity
	CAI_BaseNPC *baseNPC = dynamic_cast< CAI_BaseNPC * >( CreateEntityByName( pFUI->m_szUnit ) );
	if (baseNPC)
	{
		//baseNPC->KeyValue( "additionalequipment", npc_create_equipment.GetString() );

		for ( KeyValues *sub = pFUI->m_pUnitKeyValues->GetFirstSubKey(); sub != NULL ; sub = sub->GetNextKey() )
		{
			//Msg("name: %s, value: %s \n", sub->GetName(), sub->GetString() );
			baseNPC->KeyValue( sub->GetName(), sub->GetString() );
		}

		baseNPC->Precache();

		CHL2Wars_Player* pPlayer = ToHL2WarsPlayer( UTIL_GetCommandClient() );

		if ( args.ArgC() == 4 )
		{
			baseNPC->SetTeamRTSID( atoi( args[2] ) );
			baseNPC->SetName( AllocPooledString( args[3] ) );
		}
		else if( args.ArgC() == 3 )
		{
			baseNPC->SetTeamRTSID( atoi( args[2] ) );
		}
		else
		{
			baseNPC->SetTeamRTSID( pPlayer->GetTeamRTSID() );
		}

		DispatchSpawn(baseNPC);
		// Now attempt to drop into the world
		trace_t tr;
		Vector aim;
		aim = pPlayer->GetMouseAim();
		//AngleVectors(pPlayer->EyeAngles(),&forward);	//Get the forward vector frow our own eye angles.
    
		AI_TraceLine(pPlayer->Weapon_ShootPosition(),
			pPlayer->Weapon_ShootPosition() + aim * MAX_TRACE_LENGTH,MASK_NPCSOLID, 
			pPlayer, COLLISION_GROUP_NONE, &tr );
		if ( tr.fraction != 1.0)
		{
			if (baseNPC->CapabilitiesGet() & bits_CAP_MOVE_FLY)
			{
				Vector pos = tr.endpos - aim * 36;
				baseNPC->Teleport( &pos, NULL, NULL );
			}
			else
			{
				// Raise the end position a little up off the floor, place the npc and drop him down
				tr.endpos.z += 12;
				baseNPC->Teleport( &tr.endpos, NULL, NULL );
				UTIL_DropToFloor( baseNPC, MASK_NPCSOLID );
			}

			// fix for strider, because we love having fun with it
			if( FClassnameIs( baseNPC, "hlw_npc_strider" ) )
			{
				CHLW_NPC_Strider *strider = (CHLW_NPC_Strider *)baseNPC;
				baseNPC->SetAbsOrigin( baseNPC->GetAbsOrigin() + Vector( 0, 0, strider->GetMaxHeight() ) );
			}

			// Now check that this is a valid location for the new npc to be
			Vector	vUpBit = baseNPC->GetAbsOrigin();
			vUpBit.z += 1;

			AI_TraceHull( baseNPC->GetAbsOrigin(), vUpBit, baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), 
				MASK_NPCSOLID, baseNPC, COLLISION_GROUP_NONE, &tr );
			if ( tr.startsolid || (tr.fraction < 1.0) )
			{
				baseNPC->SUB_Remove();
				DevMsg("Can't create %s.  Bad Position!\n",args[1]);
				NDebugOverlay::Box(baseNPC->GetAbsOrigin(), baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), 255, 0, 0, 0, 0);
			}
		}

		baseNPC->SetUnitIndex( unit_index );	// InitUnitIndex might not have set the right one.
		baseNPC->InitUnitScripts(pFUI);			// do this again, override the original
		baseNPC->Activate();
	}
	CBaseEntity::SetAllowPrecache( allowPrecache );
}
static ConCommand unit_create("unit_create", CC_Unit_Create, "Creates an unit of the given unit type ( found in scripts/rts_units) where the mouse of the player is aimed to. \n\tArguments:	{npc_class_name}, { teamid }", FCVAR_CHEAT);

//------------------------------------------------------------------------------
// Purpose: Toggle rts mode
//------------------------------------------------------------------------------
void CC_ToggleRTSMode( const CCommand &args )
{
	CHL2Wars_Player* pPlayer = ToHL2WarsPlayer( UTIL_GetCommandClient() );

	pPlayer->SetRTSMode( !pPlayer->IsPlayerInRTSMode() );

}
static ConCommand toggle_rtsmode("toggle_rtsmode", CC_ToggleRTSMode, "Toggles rts mode.", FCVAR_CHEAT);

//------------------------------------------------------------------------------
// Purpose: Change team
//------------------------------------------------------------------------------
void CC_ChangeTeamRTSID( const CCommand &args )
{
	CHL2Wars_Player* pPlayer = ToHL2WarsPlayer( UTIL_GetCommandClient() );

	pPlayer->SetTeamRTSID( atof( args[1] ) );

}
static ConCommand change_team_rtsid("change_team_rtsid", CC_ChangeTeamRTSID, "Change team rts id. \n\tArguments: { teamid }", FCVAR_CHEAT);

//------------------------------------------------------------------------------
// Purpose: Give resources to a team
//------------------------------------------------------------------------------
void CC_GiveResource( const CCommand &args )
{
	CHL2Wars_Player* pPlayer = ToHL2WarsPlayer( UTIL_GetCommandClient() );

	if( args.ArgC() == 2 )
		g_pRTSResource->AddResources( pPlayer->GetTeamRTSID(), atoi( args[1] ) );
	else 
		g_pRTSResource->AddResources( atoi( args[2] ), atoi( args[1] ) );

}
static ConCommand give_resource("give_resource", CC_GiveResource, "Gives resources. \n\tArguments: { amount, team }", FCVAR_CHEAT);

//------------------------------------------------------------------------------
// Purpose: Enable/Disable a strategic AI for a certain teamid
//------------------------------------------------------------------------------
void CC_EnableStrategicAI( const CCommand &args )
{
	if( args.ArgC() < 3 )
	{
		Msg("USAGE: enable_strategicai [teamid] [state]. State should be 0 or 1\n");
		return;
	}

	int teamid = atoi( args[1] );
	if( !UTIL_IsValidTeam( teamid, false ) )
		return;
		
	if( atoi( args[2] ) )
		g_StrategicAI[teamid - DEFAULT_TEAMS]->InputEnable();
	else
		g_StrategicAI[teamid - DEFAULT_TEAMS]->InputDisable();
}
static ConCommand enable_strategicai("enable_strategicai", CC_EnableStrategicAI, "Enable a strategic ai. \n\tArguments: { teamid, state }", FCVAR_CHEAT);
