
// Parachute grunt (based on repel grunt)
// Author: GeckonCZ

namespace THMonsterGruntRepel
{

const int TH_GRUNT_PARACHUTE_BODYPART = 3;
const int TH_GRUNT_PARACHUTE_HIDDEN = 0;
const int TH_GRUNT_PARACHUTE_VISIBLE = 1;

const string TH_GRUNT_MODEL = "models/hunger/hgrunt.mdl";

class CGruntRepel : ScriptBaseMonsterEntity
{
	private EHandle m_hHgrunt;

	void Spawn( void )
	{
		Precache();
		
		pev.solid = SOLID_NOT;

		SetUse( UseFunction( RepelUse ) );
	}

	void Precache()
	{
		g_Game.PrecacheOther( "monster_human_grunt" );
		
		g_Game.PrecacheModel( TH_GRUNT_MODEL );
	}
	
	void RepelUse( CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue )
	{
		TraceResult tr;
		g_Utility.TraceLine( pev.origin, pev.origin + Vector( 0, 0, -4096.0), dont_ignore_monsters, self.edict(), tr );
		/*
		if ( tr.pHit !is null && g_EntityFuncs.Instance( tr.pHit ).pev.solid != SOLID_BSP )
			return null;
		*/
		
		// Use custom model
		dictionary keyvalues = { { "model", TH_GRUNT_MODEL } };
		CBaseEntity@ pEntity = g_EntityFuncs.CreateEntity( "monster_human_grunt", keyvalues, false ); // Delayed spawn
		
		CBaseMonster@ pGrunt = pEntity.MyMonsterPointer();
		
		pGrunt.pev.origin = pev.origin;
		pGrunt.pev.angles = pev.angles;
		pGrunt.pev.spawnflags = pev.spawnflags;
		pGrunt.pev.health = pev.health;
		pGrunt.pev.netname = pev.netname;
		pGrunt.pev.weapons = pev.weapons;
		
		g_EntityFuncs.DispatchSpawn( pGrunt.edict() );
		
		pGrunt.pev.movetype = MOVETYPE_FLY;
		pGrunt.pev.velocity = Vector( 0, 0, Math.RandomFloat( -196, -128 ) );
		pGrunt.SetActivity( ACT_GLIDE );
		// UNDONE: position?
		pGrunt.m_vecLastPosition = tr.vecEndPos;
		pGrunt.m_iTriggerCondition = self.m_iTriggerCondition;
		pGrunt.m_iszTriggerTarget = self.m_iszTriggerTarget;
		
		m_hHgrunt = EHandle( pGrunt );
		
		ShowParachute();
		
		// The spawner entity may be killed by the mapper right after
		// triggering it (so it can't spawn a second grunt), which
		// would happen before its own pev.nextthink could fire. Use
		// a scheduler callback instead of SetThink/pev.nextthink so
		// hiding the parachute doesn't depend on this entity still
		// being alive 4 seconds from now.
		// NOTE: the callback function is declared in the GLOBAL scope
		// (below, outside this namespace) and scheduled by its plain
		// name, because g_Scheduler.SetTimeout looks up functions by
		// unqualified name and can't resolve a namespaced one like
		// "THMonsterGruntRepel::HideParachuteCallback".
		g_Scheduler.SetTimeout( "HideParachuteCallback", 4.0, EHandle( pGrunt ) );
	}
	
	void ShowParachute( void )
	{
		if ( !m_hHgrunt.IsValid() )
			return;
			
		CBaseMonster@ pGrunt = m_hHgrunt.GetEntity().MyMonsterPointer();
		pGrunt.SetBodygroup( TH_GRUNT_PARACHUTE_BODYPART, TH_GRUNT_PARACHUTE_VISIBLE );
	}
}

void Register()
{
	g_CustomEntityFuncs.RegisterCustomEntity( "THMonsterGruntRepel::CGruntRepel", "monster_th_grunt_repel" );
}

} // end of namespace

// Declared in the GLOBAL scope (outside the namespace) so g_Scheduler can
// find it by its plain, unqualified name. Also lets it run even if the
// CGruntRepel spawner entity that requested it has already been killed,
// since it only needs the grunt's own handle, not the spawner.
void HideParachuteCallback( EHandle hGrunt )
{
	if ( !hGrunt.IsValid() )
		return;

	CBaseMonster@ pGrunt = hGrunt.GetEntity().MyMonsterPointer();
	pGrunt.SetBodygroup( THMonsterGruntRepel::TH_GRUNT_PARACHUTE_BODYPART, THMonsterGruntRepel::TH_GRUNT_PARACHUTE_HIDDEN );
}
