#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "dragonball.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "effects.h"
#include "aura.h"
#include "classes.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "player.h"
#include "gamerules.h"

extern cvar_t dbrespawntime;

char *dragonball_pmodels[]=
{	"models/p_db1.mdl",
	"models/p_db2.mdl",
	"models/p_db3.mdl",
	"models/p_db4.mdl",
	"models/p_db5.mdl",
	"models/p_db6.mdl",
	"models/p_db7.mdl",
};


LINK_ENTITY_TO_CLASS( dragonball, CDragonBall );

void CDragonBall::Spawn()
{	Precache();
	pev->movetype = MOVETYPE_BOUNCE;
	pev->solid = SOLID_TRIGGER;
	pev->classname = MAKE_STRING("dragonball");
}

void CDragonBall::Precache()
{	PRECACHE_MODEL("models/db1.mdl");
	PRECACHE_MODEL("models/db2.mdl");
	PRECACHE_MODEL("models/db3.mdl");
	PRECACHE_MODEL("models/db4.mdl");
	PRECACHE_MODEL("models/db5.mdl");
	PRECACHE_MODEL("models/db6.mdl");
	PRECACHE_MODEL("models/db7.mdl");
	m_sTrailSprite = PRECACHE_MODEL("sprites/dragonballtrail.spr");
	PRECACHE_SOUND("weapons/db_glowing.wav");
	PRECACHE_SOUND("weapons/db_flying.wav");
}

CDragonBall *CDragonBall::CreateDragonBall(Vector origin, int nr)
{	if ( nr < 1 || nr > 7 )
	{	ALERT(at_console,"Attempting to create Dragonball with invalid nr\n");
		return NULL;
	}

	CDragonBall *pDragonBall = GetClassPtr( (CDragonBall *)NULL );
	pDragonBall->Spawn();
	
	char model[255];
	sprintf(model,"models/db%d.mdl",nr);
	SET_MODEL(ENT(pDragonBall->pev), model);
	UTIL_SetSize(pDragonBall->pev,Vector(-1,-1,0),Vector(1,1,2));
	pDragonBall->pev->owner = NULL;

	UTIL_SetOrigin(pDragonBall->pev,origin);
	pDragonBall->SetTouch(&CDragonBall::PickupTouch);

	pDragonBall->m_iNumber = nr;
		
	if (DROP_TO_FLOOR(ENT(pDragonBall->pev)) == 0)
	{
		ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pDragonBall->pev->classname ), pDragonBall->pev->origin.x, pDragonBall->pev->origin.y, pDragonBall->pev->origin.z);
		UTIL_Remove( pDragonBall );
		return NULL;
	}

	return pDragonBall;
}

void CDragonBall::PickupTouch(CBaseEntity *pOther)
{	//can't catch when spreading out
	if(m_fSpreading)
		return;

	//you can pick up your ball again after 0.5 secs
	if(gpGlobals->time > m_flDropped + 0.5)
	{
		pev->owner = NULL;
	}
	
	entvars_t *pevOwner;
	if(pev->owner)
	{	pevOwner = VARS(pev->owner);
	}
	else
	{	pevOwner=NULL;
	}
	
	entvars_t *pevOtherOwner;
	if(pOther->pev->owner)
	{	pevOtherOwner=VARS(pOther->pev->owner);
	}
	else
	{	pevOtherOwner=NULL;
	}

	//don't hit your owner
	if(pevOwner == pOther->pev)
	{	return;
	}
	
	//don't hit your brother (aura, other attacks fired by dad)
	if(pevOtherOwner == pevOwner)
	{	if (pevOwner) return;
	}
	if(pOther->IsPlayer())
	{	CBasePlayer *pPlayer = (CBasePlayer*)pOther;
		// added by Rick: m_flDragonBallDrop check
		if(!pPlayer->m_fStrangled && !pPlayer->m_fBecomeCandy && !pPlayer->m_iDragonball && !pPlayer->m_fCharging && !pPlayer->m_fControl && !pPlayer->m_fPowerUp && !pPlayer->m_fBlock && !pPlayer->m_fAscending && pPlayer->IsAlive() && !pPlayer->m_fSpawnInvulnerable && (pPlayer->m_flDragonballDrop < (gpGlobals->time - 0.75f)))
		{	//stop glowing sound and remove
			EMIT_SOUND(ENT(pev), CHAN_BODY, "common/null.wav", 1.0, ATTN_NORM);
			UTIL_Remove(this);
			
			
			pPlayer->m_iDragonball = m_iNumber;
			// Added by Pcjoe
			pPlayer->m_flDragonBallPickup = gpGlobals->time + 1;
			pPlayer->GiveNamedItem("weapon_dragonball");
			pPlayer->SelectItem("weapon_dragonball");
			g_pGameRules->DragonBallPickUp(m_iNumber, pPlayer->entindex());

			return;
		}
	}

	//ignore other dragonballs, we're not jue de bouling
	if(FClassnameIs(pOther->pev, "dragonball"))
	{	return;
	}

	pev->velocity = pev->velocity * 0.5;	
}

void CDragonBall::Glow()
{	pev->renderfx = kRenderFxGlowShell;
	pev->rendercolor = Vector (255,255,0);
	if (m_iNumber == 1)
	{
		//only let one of 'em glow
		EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/db_glowing.wav", 1.0, ATTN_NORM);
	}
}

void CDragonBall::UnGlow()
{	pev->renderfx = kRenderFxNone;
	EMIT_SOUND(ENT(pev), CHAN_BODY, "common/null.wav", 1.0, ATTN_NORM);
}

void CDragonBall::SpreadThink()
{	if ( pev->origin.z < m_flPreviousZ)
	{	pev->movetype = MOVETYPE_NOCLIP;
		pev->solid = SOLID_NOT;
		
		Vector vecDir;
		vecDir.x = RANDOM_FLOAT( -1, 1 );
		vecDir.y = RANDOM_FLOAT( -1, 1 );
		vecDir.z = 0;
	

		pev->velocity = vecDir.Normalize() * 1500;
		MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
			WRITE_BYTE  (TE_BEAMFOLLOW);			//create a line of decaying beam segments until entity stops moving
			WRITE_SHORT	(entindex());				//entity:attachment to follow)
			WRITE_SHORT	(m_sTrailSprite);			//short (sprite index)
			WRITE_BYTE	(50);						//life in 0.1's) 
			WRITE_BYTE	(5);						//(line width in 0.1's) 
			WRITE_BYTE  (200);						//byte,byte,byte (color)
			WRITE_BYTE  (200);			
			WRITE_BYTE  (200);
			WRITE_BYTE  (254);						//brightness
		MESSAGE_END();
		SetThink(&CDragonBall::SUB_Remove);
		pev->nextthink = gpGlobals->time + 30;
		return;
	}
	m_flPreviousZ = pev->origin.z;
	pev->nextthink = gpGlobals->time + 0.2;
}

void CDragonBall::Stonify()
{	pev->skin = 1;
	SetThink(&CDragonBall::UnStoneThink);
	SetTouch(NULL);
	pev->nextthink = gpGlobals->time + dbrespawntime.value;
}

void CDragonBall::UnStoneThink()
{	pev->skin = 0;
	SetTouch(&CDragonBall::PickupTouch);
	SetThink(NULL);
}

void CDragonBall::Spread()
{	UnGlow();
	pev->skin = 1;
	EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/db_flying.wav", 1.0, ATTN_NORM);
	pev->movetype = MOVETYPE_TOSS;
	pev->velocity = Vector(0,0,1000);
	m_flPreviousZ = pev->origin.z;
	SetThink(&CDragonBall::SpreadThink);
	//give them time to fly up
	pev->nextthink = gpGlobals->time + 0.2;
}

CDragonBall *CDragonBall::ThrowDragonBall(entvars_t *pevOwner,Vector vecStart, Vector vecVelocity, int nr)
{	if ( nr < 1 || nr > 7 )
	{	ALERT(at_console,"Attempting to create Dragonball with invalid nr\n");
		return NULL;
	}

	CDragonBall *pDragonBall = GetClassPtr( (CDragonBall *)NULL );
	pDragonBall->Spawn();

	char model[255];
	sprintf(model,"models/db%d.mdl",nr );
	SET_MODEL(ENT(pDragonBall->pev), model);
	UTIL_SetSize(pDragonBall->pev,Vector(-1,-1,0),Vector(1,1,2));
	
	pDragonBall->pev->owner = ENT(pevOwner);

	UTIL_SetOrigin(pDragonBall->pev,vecStart);
	pDragonBall->pev->velocity = vecVelocity;
	pDragonBall->m_iNumber = nr;
	pDragonBall->m_flDropped = gpGlobals->time;
	pDragonBall->SetTouch(&CDragonBall::PickupTouch);

	g_pGameRules->DragonBallDrop(nr, pDragonBall);

	return pDragonBall;
}


/**
* Dragonball "Weapon"
* @version : 3-12-2001
* @author Herwin 'harSens' van Welbergen
*/
class CCariedDragonBall:public CBasePlayerWeapon
{	
public:
	/**
	* Init function
	*/
	void Spawn( void );

	/**
	* Precaches sprites and sounds
	*/
	void Precache( void );

	/**
	* Get dragonball slot
	* return int: the slot, is 8 for dragonball
	*/
	int iItemSlot( void ) { return 8; }

	/**
	* Get dragonball item info
	* @param ItemInfo *p: The ItemInfo gets stored here
	* @return int: Always returns 1 (why???)
	*/
	int GetItemInfo(ItemInfo *p);

	/**
	* Called when dragonball is selected as weapon
	*/
	BOOL Deploy( void );

	/**
	* Holsters the attack
	*/
	void Holster(int skiplocal);

	/**
	* Throws a dragonball
	*/
	void PrimaryAttack( void );

	/**
	* 2nd attack: drops a dragonball
	*/
	void SecondaryAttack( void );

	/**
	* Only deploy if the player has a dragonball
	*/
	BOOL CanDeploy(void);
private:
	/**
	* Drops the dragonball
	*/
	void DropBall( void );	
};

LINK_ENTITY_TO_CLASS( weapon_dragonball, CCariedDragonBall );

void CCariedDragonBall::Spawn( void )
{	Precache();
	m_iId = WEAPON_DRAGONBALL;
	m_iDefaultAmmo = 0;
	m_iClip = -1;
	FallInit();// get ready to fall down.
}

void CCariedDragonBall::Precache( void )
{	PRECACHE_MODEL("models/p_db1.mdl");
	PRECACHE_MODEL("models/p_db2.mdl");
	PRECACHE_MODEL("models/p_db3.mdl");
	PRECACHE_MODEL("models/p_db4.mdl");
	PRECACHE_MODEL("models/p_db5.mdl");
	PRECACHE_MODEL("models/p_db6.mdl");
	PRECACHE_MODEL("models/p_db7.mdl");
}

int CCariedDragonBall::GetItemInfo(ItemInfo *p)
{	p->pszName = STRING(pev->classname);
	p->pszAmmo1 = "ki";
	p->iMaxAmmo1 = -1;	//max ammo is weapon independent
	p->pszAmmo2 = NULL;
	p->iMaxAmmo2 = -1;
	p->iMaxClip = WEAPON_NOCLIP;
	p->iSlot = 7;
	p->iPosition = 0;
	p->iId = m_iId = WEAPON_DRAGONBALL;
	p->iWeight = DRAGONBALL_WEIGHT;
	p->iFlags = 0;
	return 1;
}


BOOL CCariedDragonBall::CanDeploy( void )
{	//return (m_pPlayer->m_iDragonball > 0 && m_pPlayer->m_iDragonball<8);		
	return true;
}

BOOL CCariedDragonBall::Deploy( void )
{	m_pPlayer->pev->weaponmodel = MAKE_STRING(dragonball_pmodels[m_pPlayer->m_iDragonball-1]);
	m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75;
	return DefaultDeploy( "dragonball" );
}

void CCariedDragonBall::Holster(int skiplocal)
{	//remove from hud
	extern int gmsgWeaponUpdate;
	MESSAGE_BEGIN( MSG_ONE, gmsgWeaponUpdate, NULL, m_pPlayer->pev );
		WRITE_CHAR( -m_iId );
	MESSAGE_END();

	DropBall();
	m_pPlayer->pev->weaponmodel = 0;

	// Added by Pcjoe
	m_pPlayer->m_flDragonBallPickup = 0;

	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
	SetThink( &CCariedDragonBall::DestroyItem );
	pev->nextthink = gpGlobals->time + 0.1;	
}

void CCariedDragonBall::PrimaryAttack( void )
{	if (m_pPlayer->m_iDragonball && m_pPlayer->m_flDragonBallPickup < gpGlobals->time)
	{	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
		UTIL_MakeVectors( m_pPlayer->pev->v_angle );
		Vector vecThrow = gpGlobals->v_forward * DRAGONBALL_SPEED;
		CDragonBall::ThrowDragonBall(m_pPlayer->pev,m_pPlayer->GetGunPosition(),vecThrow, m_pPlayer->m_iDragonball);
		m_pPlayer->m_iDragonball = 0;

		// Added by Rick
		m_pPlayer->m_flDragonballDrop = gpGlobals->time;

		RetireWeapon();
	}
}

void CCariedDragonBall::SecondaryAttack( void )
{	if (m_pPlayer->m_iDragonball && m_pPlayer->m_flDragonBallPickup < gpGlobals->time)
	{	m_pPlayer->SetAnimation( PLAYER_ATTACK2 );
		DropBall();
		RetireWeapon();
	}
}

void CCariedDragonBall::DropBall()
{	if (m_pPlayer->m_iDragonball)
	{	UTIL_MakeVectors( m_pPlayer->pev->v_angle );
		CDragonBall::ThrowDragonBall(m_pPlayer->pev, m_pPlayer->GetGunPosition(), m_pPlayer->pev->velocity + gpGlobals->v_forward * 200, m_pPlayer->m_iDragonball);
		m_pPlayer->m_iDragonball = 0;

		// Added by Rick
		m_pPlayer->m_flDragonballDrop = gpGlobals->time;		
	}
}