//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Things thrown from the hand
//
//=============================================================================//

#include "cbase.h"
#include "player.h"
#include "ammodef.h"
#include "gamerules.h"
#include "grenade_brickbat.h"
#include "weapon_brickbat.h"
#include "soundent.h"
#include "decals.h"
#include "IEffects.h"
#include "engine/IEngineSound.h"

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

// Global Savedata for changelevel trigger
BEGIN_DATADESC( CGrenade_Brickbat )

	DEFINE_FIELD( m_nType, FIELD_INTEGER ),
	DEFINE_FIELD( m_bExplodes, FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bBounceToFlat, FIELD_BOOLEAN ),

	// Function Pointers
	DEFINE_FUNCTION( BrickbatTouch ),
	DEFINE_FUNCTION( BrickbatThink ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( brickbat, CGrenade_Brickbat );

void CGrenade_Brickbat::Spawn( void )
{
	SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
	SetTouch( BrickbatTouch );
	SetThink( BrickbatThink );
	SetNextThink( gpGlobals->curtime + 0.1f );

	m_takedamage = DAMAGE_YES;
	m_iHealth = 1;

	SetGravity( 1.0 );
	SetSequence( 1 );

	CreateVPhysics();
}

bool CGrenade_Brickbat::CreateVPhysics()
{
	VPhysicsInitNormal( SOLID_VPHYSICS, 0, false );
	IPhysicsObject *pPhysics = VPhysicsGetObject();
	if ( pPhysics )
	{
		// we want world touches
		unsigned int flags = pPhysics->GetCallbackFlags();
		pPhysics->SetCallbackFlags( flags | CALLBACK_GLOBAL_TOUCH_STATIC );
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CGrenade_Brickbat::BrickbatTouch( CBaseEntity *pOther )
{
	// -----------------------------------------------------------
	// Might be physically simulated so get my velocity manually
	// -----------------------------------------------------------
	Vector vVelocity;
	GetVelocity(&vVelocity,NULL);

	// -----------------------------------
	// Do damage if we moving fairly fast
	// -----------------------------------
	if (vVelocity.Length() > 100)
	{
		if (GetThrower())
		{
			trace_t tr;
			tr = CBaseEntity::GetTouchTrace( );
			ClearMultiDamage( );
			Vector forward;
			AngleVectors( GetLocalAngles(), &forward );

			CTakeDamageInfo info( this, GetThrower(), m_flDamage, DMG_CRUSH );
			CalculateMeleeDamageForce( &info, forward, tr.endpos );
			pOther->DispatchTraceAttack( info, forward, &tr );
			ApplyMultiDamage();
		}
		// If this thrown item explodes, blow it up
		if (m_bExplodes) 
		{
			Detonate();
			return;
		}
	}
	else if (pOther->GetFlags() & FL_CLIENT)
	{
		SpawnBrickbatWeapon();
		return;
	}
}

//------------------------------------------------------------------------------
// Purpose : Brickbat grenade turns back into a brickbat weapon
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CGrenade_Brickbat::SpawnBrickbatWeapon( void )
{
	CWeaponBrickbat *pBrickbat = (CWeaponBrickbat*)CBaseEntity::CreateNoSpawn( 
		"weapon_brickbat", GetLocalOrigin(), GetLocalAngles(), NULL );
	// Spawn after we set the ammo type so the correct model is used
	if (pBrickbat)
	{
		pBrickbat->m_iCurrentAmmoType = m_nType;
		pBrickbat->Spawn();
		VPhysicsDestroyObject();
		SetThink(NULL);
		UTIL_Remove(this);
	}
}

//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CGrenade_Brickbat::BrickbatThink( void )
{
	// -----------------------------------------------------------
	// Might be physically simulated so get my velocity manually
	// -----------------------------------------------------------
	Vector vVelocity;
	AngularImpulse vAngVel;
	GetVelocity(&vVelocity,&vAngVel);

	// See if I can lose my owner (has dropper moved out of way?)
	// Want do this so owner can throw the brickbat
	if (GetOwnerEntity())
	{
		trace_t tr;
		Vector	vUpABit = GetAbsOrigin();
		vUpABit.z += 5.0;

		CBaseEntity* saveOwner = GetOwnerEntity();
		SetOwnerEntity( NULL );
		UTIL_TraceEntity( this, GetAbsOrigin(), vUpABit, MASK_SOLID, &tr );
		if ( tr.startsolid || tr.fraction != 1.0 )
		{
			SetOwnerEntity( saveOwner );
		}
	}

	// ---------------------------------------------------------------
	//	Make sure we're not resting on a living thing's bounding box
	// ---------------------------------------------------------------
	if (vVelocity.Length() < 0.01)
	{
		trace_t tr;
		UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );

		if ( tr.fraction < 1.0 && tr.m_pEnt)
		{
			CBaseEntity *pEntity = tr.m_pEnt;
			if (pEntity->GetFlags() & (FL_CLIENT | FL_NPC))
			{
				// --------------------
				// Bounce me off 
				// --------------------
				Vector vNewVel;
				vNewVel.y = 100;
				vNewVel.x = random->RandomInt(-100,100);
				vNewVel.z = random->RandomInt(-100,100);

				// If physically simulated
				IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
				if ( pPhysicsObject )
				{
					pPhysicsObject->AddVelocity( &vNewVel, &vAngVel );
				}
				// Otherwise
				else
				{
					SetAbsVelocity( vNewVel );
				}
			}
		}
	}

	if (vVelocity.Length() < 0.01)
	{
		SpawnBrickbatWeapon();
	}
	SetNextThink( gpGlobals->curtime + 0.1f );
}

//=====================================================================
//	> Rock
//=====================================================================
class CGrenadeRockBB : public CGrenade_Brickbat
{
public:
	DECLARE_CLASS( CGrenadeRockBB, CGrenade_Brickbat );

	void Spawn(void)
	{
		m_nType = BRICKBAT_ROCK;
		SetModel( "models/props_junk/Rock001a.mdl" );
		BaseClass::Spawn();
	}
	void Precache( void )
	{
		PrecacheModel("models/props_junk/Rock001a.mdl");
		BaseClass::Precache();
	}
};
LINK_ENTITY_TO_CLASS( grenade_rockbb, CGrenadeRockBB );
PRECACHE_REGISTER(grenade_rockbb);


//=====================================================================
//	> BeerBottle
//=====================================================================
class CGrenadeBottle : public CGrenade_Brickbat
{
public:
	DECLARE_CLASS( CGrenadeBottle, CGrenade_Brickbat );

	void Spawn(void)
	{
		m_nType	= BRICKBAT_BOTTLE;
		m_bExplodes	= true;
		SetModel( "models/weapons/w_bb_bottle.mdl" );
		BaseClass::Spawn();
	}
	void Precache( void );
	void Detonate( void );
};

void CGrenadeBottle::Precache( void )
{
	PrecacheModel("models/weapons/w_bb_bottle.mdl");

	PrecacheScriptSound( "GrenadeBottle.Detonate" );

	BaseClass::Precache();
}

void CGrenadeBottle::Detonate( void )
{	
	trace_t trace;

	UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity(), MASK_SOLID, this, COLLISION_GROUP_NONE, &trace);
	UTIL_DecalTrace( &trace, "BeerSplash" );

	EmitSound( "GrenadeBottle.Detonate" );

	CSoundEnt::InsertSound(SOUND_COMBAT, GetAbsOrigin(), 400, 0.5);

	UTIL_Remove( this );
}

LINK_ENTITY_TO_CLASS( grenade_beerbottle, CGrenadeBottle );
PRECACHE_REGISTER(grenade_beerbottle);