//========= Copyright Valve Corporation, All rights reserved. ============//
//
// TF Pumpkin Bomb
//
//=============================================================================
#include "cbase.h"
#include "tf_pumpkin_bomb.h"
#include "takedamageinfo.h"
#include "tf_shareddefs.h"
#include "props_shared.h"
#ifdef GAME_DLL
#include "te_effect_dispatch.h"
#include "tf_fx.h"
#include "tf_projectile_base.h"
#include "basegrenade_shared.h"
#include "tf_gamerules.h"
#include "tf_weaponbase_rocket.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

#define PUMPKIN_MODEL "models/props_halloween/pumpkin_explode.mdl"
#define TEAM_PUMPKIN "models/props_halloween/pumpkin_explode_teamcolor.mdl"

LINK_ENTITY_TO_CLASS( tf_pumpkin_bomb, CTFPumpkinBomb );

IMPLEMENT_NETWORKCLASS_ALIASED( TFPumpkinBomb, DT_TFPumpkinBomb )

BEGIN_NETWORK_TABLE( CTFPumpkinBomb, DT_TFPumpkinBomb )
END_NETWORK_TABLE()

IMPLEMENT_AUTO_LIST( ITFPumpkinBomb );

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFPumpkinBomb::CTFPumpkinBomb()
{
#ifdef GAME_DLL
	m_bIsSpell = false;
#endif

	m_bDead = false;
	m_bPrecached = false;

	m_iTeam		= TF_TEAM_HALLOWEEN;
	m_flDamage	= 150.0f;
	m_flScale	= 1.0f;
	m_flRadius	= 300.0f;
	m_flLifeTime = -1.0f;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFPumpkinBomb::Precache()
{
	BaseClass::Precache();

	// always allow late precaching, so we don't pay the cost of the
	// Halloween pumpkin bomb for the entire year

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

	int iModel = PrecacheModel( PUMPKIN_MODEL );
	PrecacheGibsForModel( iModel );

	PrecacheModel( TEAM_PUMPKIN );

	PrecacheScriptSound( "Halloween.PumpkinExplode" );

	CBaseEntity::SetAllowPrecache( bAllowPrecache );
	
	m_bPrecached = true;
}

//-----------------------------------------------------------------------------
void CTFPumpkinBomb::SetInitParams( float scale, float damage, float radius, int iTeam, float flLifeTime )
{
	m_iTeam		= iTeam;
	m_flDamage	= damage;
	m_flScale	= scale;
	m_flRadius	= radius;
	
	if ( flLifeTime > 0 )
	{
		m_flLifeTime = flLifeTime;
	}
}

//-----------------------------------------------------------------------------
void CTFPumpkinBomb::Spawn()
{
	if ( !m_bPrecached )
	{
		Precache();
	}

	if ( m_iTeam != TF_TEAM_HALLOWEEN )
	{
		SetModel( TEAM_PUMPKIN );
		m_nSkin = m_iTeam == TF_TEAM_BLUE ? 2 : 1;	// This is actually opposite of what you'd think so Blue team can Hurt Blue Pumpkins
		SetCollisionGroup( TFCOLLISION_GROUP_TANK );
		SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
		SetSolid( SOLID_BBOX );
		SetHealth( 1 );
	}
	else
	{
		SetModel( PUMPKIN_MODEL );
		SetMoveType( MOVETYPE_VPHYSICS );
		SetSolid( SOLID_VPHYSICS );
		SetHealth( 1 );
	}
	
	BaseClass::Spawn();
	
	SetModelScale( m_flScale );
	m_takedamage = DAMAGE_YES;
	m_bDead = false;

	SetTouch( &CTFPumpkinBombShim::Touch );
#ifdef GAME_DLL
	if ( m_flLifeTime > 0 )
	{
		SetContextThink( &CTFPumpkinBomb::RemovePumpkin, gpGlobals->curtime + m_flLifeTime, "RemovePumpkin" );
	}
#endif
}

//-----------------------------------------------------------------------------
void CTFPumpkinBomb::RemovePumpkin()
{
#ifdef GAME_DLL
	CPVSFilter filter( GetAbsOrigin() );
	TE_TFParticleEffect( filter, 0.0, m_iTeam == TF_TEAM_RED ? "spell_pumpkin_mirv_goop_red" : "spell_pumpkin_mirv_goop_blue", GetAbsOrigin(), vec3_angle );
	UTIL_Remove( this );
#endif // GAME_DLL
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFPumpkinBomb::PumpkinTouch( CBaseEntity *pOther )
{
	if ( !pOther )
		return;

#ifdef GAME_DLL
	if ( pOther->GetFlags() & FL_GRENADE )
	{
		// Only let my team destroy
		CBaseEntity *pAttacker = NULL;

		CBaseGrenade *pGrenade = dynamic_cast<CBaseGrenade*>(pOther);
		if ( pGrenade )
		{
			pAttacker = pGrenade->GetThrower();
			// Do a proper explosion
			Vector velDir = pGrenade->GetAbsVelocity();
			VectorNormalize( velDir );
			Vector vecSpot = pGrenade->GetAbsOrigin() - velDir * 32;
			trace_t	tr;
			UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
			// Boom
			pGrenade->Explode( &tr, DMG_BLAST );
		}
		else
		{
			CTFBaseRocket *pRocket = dynamic_cast<CTFBaseRocket*>(pOther);
			if ( pRocket )
			{
				Vector velDir = pRocket->GetAbsVelocity();
				VectorNormalize( velDir );
				Vector vecSpot = pRocket->GetAbsOrigin() - velDir * 32;
				trace_t	tr;
				UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
				pRocket->Explode( &tr, this );
			}
		}

		if ( !pAttacker )
		{
			CTFBaseProjectile *pProj = dynamic_cast<CTFBaseProjectile*>(pOther);
			if ( pProj )
			{
				pAttacker = pProj->GetScorer();
			}
		}

		if ( m_iTeam != TF_TEAM_HALLOWEEN && pOther->GetTeamNumber() != m_iTeam )
		{
			RemovePumpkin();
		}
		else
		{
			TakeDamage( CTakeDamageInfo( pOther, pAttacker, 10.f, DMG_CRUSH ) );
		}
	}
	else if ( FStrEq( STRING(pOther->m_iClassname), "trigger_hurt" ) )
	{
		RemovePumpkin();
	}
#endif
}

//-----------------------------------------------------------------------------
#ifdef GAME_DLL
int	CTFPumpkinBomb::OnTakeDamage( const CTakeDamageInfo &info )
{
	CPVSFilter filter( GetAbsOrigin() );
	if ( m_iTeam != TF_TEAM_HALLOWEEN )
	{
		TE_TFParticleEffect( filter, 0.0, m_iTeam == TF_TEAM_RED ? "spell_pumpkin_mirv_goop_red" : "spell_pumpkin_mirv_goop_blue", GetAbsOrigin(), vec3_angle );
	}

	// if damage is from same team, Setlife to one and pass to base class
	if ( info.GetAttacker()->GetTeamNumber() == m_iTeam )
	{
		SetHealth( 1 );
	}
	else if ( m_iTeam != TF_TEAM_HALLOWEEN )
	{
		RemovePumpkin();
		return 0;
	}

	return BaseClass::OnTakeDamage( info );
}
//-----------------------------------------------------------------------------
void CTFPumpkinBomb::Event_Killed( const CTakeDamageInfo &info )
{
	if ( m_bDead )
		return;

	m_bDead = true;

	if ( m_iTeam != TF_TEAM_HALLOWEEN && info.GetAttacker()->GetTeamNumber() != m_iTeam )
	{
		RemovePumpkin();
		return;
	}
	
	trace_t tr;
	Vector vecSpot = GetAbsOrigin() + Vector ( 0 , 0 , 8 );
	UTIL_TraceLine( vecSpot, vecSpot + Vector ( 0, 0, -32 ), MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, &tr );

	// Explosion effect and gibs.
	Vector vecOrigin = GetAbsOrigin();
	QAngle vecAngles = GetAbsAngles();
	CPVSFilter filter( vecOrigin );
	TE_TFExplosion( filter, 0.0f, vecOrigin, tr.plane.normal, TF_WEAPON_PUMPKIN_BOMB, -1 );
	TE_TFParticleEffect( filter, 0.0f, "pumpkin_explode", vecOrigin, vecAngles );

	// Deal damage.
	SetSolid( SOLID_NONE );
	if ( info.GetAttacker() )
	{
		ChangeTeam( info.GetAttacker()->GetTeamNumber() );
	}
	CTakeDamageInfo damage_info( this, info.GetAttacker(), NULL, m_flDamage, DMG_BLAST | DMG_HALF_FALLOFF | DMG_NOCLOSEDISTANCEMOD );
	damage_info.SetDamageCustom( m_bIsSpell ? TF_DMG_CUSTOM_SPELL_MIRV : TF_DMG_CUSTOM_PUMPKIN_BOMB );

	if ( TFGameRules() )
	{
		CTFRadiusDamageInfo radiusinfo( &damage_info, vecOrigin, m_flRadius, this );
		TFGameRules()->RadiusDamage( radiusinfo );
	}

	// Don't decal players with scorch.
	if ( tr.m_pEnt && !tr.m_pEnt->IsPlayer() )
	{
		UTIL_DecalTrace( &tr, "Scorch" );
	}

	Break();
	
	BaseClass::Event_Killed( info );
}

void CTFPumpkinBomb::Break( void )
{
	CPVSFilter filter( GetAbsOrigin() );
	UserMessageBegin( filter, "BreakModel" );
		WRITE_SHORT( GetModelIndex() );
		WRITE_VEC3COORD( GetAbsOrigin() );
		WRITE_ANGLES( GetAbsAngles() );
		WRITE_SHORT( m_nSkin );
	MessageEnd();
}
#endif