#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "soundent.h"
#include "decals.h"
#include "effects.h"
#include "aura.h"
#include "classes.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "player.h"
#include "gamerules.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "beamattack.h"
#include "guidedattack.h"
#include "../common/particletypes.h"
extern int gmsgDetachTrail;

extern int gmsgAddEffect;
extern int gmsgRemoveEffect;

LINK_ENTITY_TO_CLASS( guidedattack, CGuidedAttack );

void CGuidedAttack::SetFollower(CBaseEntity *follower,CBasePlayer *pPlayer)
{
	if(follower!=NULL)
	{
		if(follower!=m_pFollower)
		{
			//ALERT(at_console,"Following attack\n");
			m_pFollower = follower;
			extern int gmsgAddEffect;		
			MESSAGE_BEGIN( MSG_ONE, gmsgAddEffect, NULL, pPlayer->edict() );
				WRITE_BYTE(BEAMBOXCROSSHAIR);								
				WRITE_SHORT(m_pFollower->entindex());				
			MESSAGE_END();		
		}
	}
	else
	{
		if(m_pFollower)
		{
			MESSAGE_BEGIN( MSG_ONE, gmsgRemoveEffect, NULL, pPlayer->edict() );
				WRITE_BYTE(BEAMBOXCROSSHAIR);				
			MESSAGE_END();
		}
		m_pFollower = NULL;
		//ALERT(at_console,"Not following attack\n");
	}
}

void CGuidedAttack :: FollowThink( void  )
{	entvars_t *pevOwner;

	//check of magic has an owner
	if (pev->owner)
	{	Vector vecOldVelocity = pev->velocity;
		
		//calculate crosshair position
		pevOwner = VARS(pev->owner);
		UTIL_MakeVectors( pevOwner->v_angle );
		Vector vecSrc = pevOwner->origin + pevOwner->view_ofs;
		Vector vecAiming = gpGlobals->v_forward;
		Vector vecEnd;
		/*
		if(m_pFollower)
		{
			vecEnd = m_pFollower->pev->origin;
		}
		else
		*/
		{
			TraceResult tr;
			UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, pev->owner, &tr );
			vecEnd = tr.vecEndPos;
		}
		Vector vecDir = (vecEnd - pev->origin);
		
		if(vecDir.Length()>0.05*m_flSpeed)		
		{
			pev->velocity = (pev->velocity).Normalize() * (1.0-m_flRateOfTurn) * m_flSpeed + vecDir.Normalize() * m_flSpeed * m_flRateOfTurn;
			pev->angles = UTIL_VecToAngles( pev->velocity );
		}		
	}
	else
	{	SetThink(&CGuidedAttack::NormalThink);
	}

	//draw bubbles (when underwater)
	DrawBubbles();

	//remove magic if it has moved out of the world
	if (!IsInWorld())
	{	Vaporize();
		return;
	}
	pev->nextthink = gpGlobals->time + 0.05;
}

void CGuidedAttack::Release(void)
{	CExplodingAttack::Release();
	m_fReleased = true;
	m_fRemoveAfterExplode = true;	
}

/*
void CGuidedAttack::SwatAway(CBasePlayer *pPlayer, int fRandomDir)
{	if(!m_fReleased)
	{
		Release();	
	}
	CExplodingAttack::SwatAway(pPlayer,fRandomDir);	
}
*/

void CGuidedAttack::StopTouch(CBaseEntity *pOther)
{	entvars_t *pevOwner;
	if (pev->owner)
	{	pevOwner = VARS(pev->owner);
	}
	else
	{	pevOwner=NULL;
	}
	
	//don't hit your owner
	if (pevOwner == pOther->pev)
	{	return;
	}

	if (!(pOther->Classify() == CLASS_EXPLODINGATTACK) && !pOther->IsPlayer())
	{	pev->velocity = Vector(0,0,0);
		m_fStopped = true;
		m_iRadius -= 1.0;
		if(m_iRadius<0)
		{	m_iRadius = 0;
		}
		SetThink(NULL);
	}
	else
	{	ExplodeTouch(pOther);
	}
}

void CGuidedAttack::PowerStruggleThink ()
{	/*
	entvars_t *pevOwner;
	if (pev->owner)
	{	//calculate crosshair position
		pevOwner = VARS(pev->owner);
		UTIL_MakeVectors( pevOwner->v_angle );
		Vector vecSrc = pevOwner->origin + pevOwner->view_ofs;
		Vector vecAiming = gpGlobals->v_forward;
		TraceResult tr;
		UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, pev->owner, &tr );
		Vector vecDir = tr.vecEndPos - pev->origin;

		//if we're not at the designated spot yet, stear a bit
		if(vecDir.Length()>30)
		{	Vector vecAngle = UTIL_VecToAngles(vecDir);
			pev->angles = pev->angles * (1.0-m_flRateOfTurn) + vecAngle * m_flRateOfTurn;
		}
	}
	*/
	//TODO: add delayed damage

	pev->nextthink=gpGlobals->time+0.2;
}

CGuidedAttack* CGuidedAttack::ShootGuidedMagic( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, int damage,char *attack, float size, int explosioncolor, short trail, short starta, short startb, short flarea, short flareb, int radius, float turn, int trailattachment,int trailquality)
{	CGuidedAttack *pMagicAttack = GetClassPtr( (CGuidedAttack *)NULL );
	pMagicAttack->Spawn();
	
	//pMagicAttack->pev->movetype = MOVETYPE_FLYMISSILE;
	pMagicAttack->pev->movetype = MOVETYPE_FLY;
	pMagicAttack->pev->solid = SOLID_TRIGGER;	//touches everything

	//set dummy model
	SET_MODEL(ENT(pMagicAttack->pev), "sprites/null.spr");
	
	pMagicAttack->SetDamage(damage);
	float flAttackSize = size * GUIDEDATTACK_SIZE * 0.25;//compensate for empty space in sprites
	
	//move forward by the half bbox size
	Vector vecForward = flAttackSize * vecVelocity.Normalize();
	TraceResult tr;
	UTIL_TraceLine(vecStart, vecStart + vecForward,ignore_monsters,ENT(pevOwner),&tr);
	vecStart = vecStart + vecForward * tr.flFraction;

	UTIL_SetOrigin(pMagicAttack->pev,vecStart);
	UTIL_SetSize(pMagicAttack->pev, Vector(-flAttackSize, -flAttackSize, -flAttackSize), Vector(flAttackSize, flAttackSize, flAttackSize));
	pMagicAttack->pev->velocity=vecVelocity;
	
	pMagicAttack->m_flSpeed=vecVelocity.Length();
	pMagicAttack->pev->angles=UTIL_VecToAngles(vecVelocity);
	pMagicAttack->pev->owner=ENT(pevOwner);
	pMagicAttack->pev->classname = MAKE_STRING( attack );
	pMagicAttack->m_fExploded = false;
	pMagicAttack->m_fRemoveAfterExplode = false;
	pMagicAttack->m_fReleased = false;
	pMagicAttack->m_fStopped = false;
	
	pMagicAttack->SetTouch( &CGuidedAttack::ExplodeTouch );

	pMagicAttack->AddEntEntTrail( (CBaseEntity::Instance(pevOwner))->entindex(), trailattachment, starta, startb, flarea, flareb, trail, size * GUIDEDATTACK_SIZE, trailquality,vecStart);
	
	pMagicAttack->SetThink( &CGuidedAttack::FollowThink );
	
	pMagicAttack->m_iRadius = radius;
		
	pMagicAttack->m_iExplosionColor = explosioncolor;
	
	pMagicAttack->m_flRateOfTurn = turn;

	EMIT_SOUND(ENT(pMagicAttack->pev), CHAN_WEAPON, "weapons/beamhead.wav", 1.0, ATTN_NORM);
	
	pMagicAttack->pev->nextthink = gpGlobals->time;
	pMagicAttack->m_pFollower=NULL;
	/*DEBUG by harSens: enable bbox	
	extern int gmsgBoundingBox;
	MESSAGE_BEGIN( MSG_ALL, gmsgBoundingBox);
		WRITE_LONG(pMagicAttack->entindex());
	MESSAGE_END();		
	*/
	
	return pMagicAttack;
}