#include "extdll.h"
#include "util.h"
#include "cbase.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"
#include "magicattack.h"
#include "explodingattack.h"
#include "beamattack.h"
#include "guidedattack.h"
#include "chargedattack.h"
#include "discattack.h"


/**
* Frieza disc attack
* @version 30-3-2002
* @author Herwin 'harSens' van Welbergen
*/
class CFriezaDiscAttack:public CDiscAttack
{	
public:
	/**
	 * Shoots the friezadisc
	 * @param Vector vecOrigin: Origin of the disc
	 * @param Vector vecVelocity: Velocity of the disc
	 */
	void Shoot(Vector vecOrigin,Vector vecVelocity);

	/**
	 * Disc returned to it's owner
	 */
	void Returned();

	/**
	 * Create magical attack Frieza Disc
	 * @param entvars_t *pevOwner: Monster/Player who shoots it
	 * @param Vector vecStart: Origin vector of the friezadisc
	 * @param Vector vecVelocity: Velocity of the friezadisc
	 * @param float size: the size of the friezadisc
	 * @param int discsprite: the texture sprite for the triapi disc
	 * @return *CMagicAttack: The created MagicAttack 
	 */
	static CFriezaDiscAttack *ChargeFriezaDisc( entvars_t *pevOwner, Vector vecStart, float size);

	/**
	 * Boomerangs the magic back to the player, used for friezadisc
	 */
	void EXPORT HomeThink ( void );

	/**
	 * Follows the crosshair
	 */	
	void EXPORT FollowThink(void);	

	
};

CFriezaDiscAttack* CFriezaDiscAttack::ChargeFriezaDisc( entvars_t *pevOwner, Vector vecStart, float size)
{	CFriezaDiscAttack *pMagicAttack=GetClassPtr( (CFriezaDiscAttack *)NULL );
	pMagicAttack->Spawn();	
	pMagicAttack->pev->effects &= ~EF_BRIGHTLIGHT;
	pMagicAttack->pev->renderamt = 100;
	pMagicAttack->pev->solid=SOLID_TRIGGER;//only touch players
	pMagicAttack->pev->movetype=MOVETYPE_NOCLIP;//go through walls

	//set model 
	SET_MODEL(ENT(pMagicAttack->pev), "models/w_friezadisc.mdl");

	pMagicAttack->pev->scale = size;

	pMagicAttack->pev->dmg=999; //instant death
	UTIL_SetOrigin(pMagicAttack->pev,vecStart);
	pMagicAttack->pev->owner=ENT(pevOwner);

	pMagicAttack->pev->velocity=Vector(0,0,0);
	
	//HACK HACK: rendercolor indicates owner to charge to
	pMagicAttack->pev->rendercolor.x=ENTINDEX(ENT(pevOwner));
	pMagicAttack->pev->classname = MAKE_STRING( "Frieza Disc" );

	//rotate it
	pMagicAttack->pev->gaitsequence = 0;
	pMagicAttack->pev->sequence = 0;
	pMagicAttack->pev->frame = 0;
	pMagicAttack->ResetSequenceInfo( );	
	
	//let the weapon handle the removing of the attack
	pMagicAttack->m_fReleased = false;

	pMagicAttack->SetTouch(NULL);
	// Edited by Pcjoe
//	pMagicAttack->SetThink(NULL);
	pMagicAttack->SetThink(&CDiscAttack::AuraCheck);
	pMagicAttack->pev->nextthink = gpGlobals->time;
	pMagicAttack->CDiscAttack::AuraCheck();
	
	return pMagicAttack;
}

void CFriezaDiscAttack::Returned()
{
	entvars_t *pevOwner;

	//check of magic has an owner
	if (pev->owner)
	{	pevOwner=VARS(pev->owner);
		UTIL_SetOrigin(pev,pevOwner->origin);
	
		//HACK HACK: rendercolor indicates owner to charge to
		pev->rendercolor.x=ENTINDEX(pev->owner);
	}
	pev->effects &= ~EF_BRIGHTLIGHT;	
	pev->velocity=Vector(0,0,0);
	pev->angles = Vector(0,0,0);

	pev->scale*=0.5;
	SetTouch(NULL);
	// Edited by Pcjoe
//	SetThink(NULL);
	SetThink(&CDiscAttack::AuraCheck);
	pev->nextthink = gpGlobals->time;
	CDiscAttack::AuraCheck();

	//silence rotating sound
	STOP_SOUND(ENT(pev), CHAN_WEAPON, "weapons/rotating.wav");
}

void CFriezaDiscAttack ::Shoot(Vector vecOrigin, Vector vecVelocity)
{	// Added by Pcjoe
	pev->movetype = MOVETYPE_NOCLIP;//go through walls
	pev->aiment = NULL;

	pev->effects |= EF_BRIGHTLIGHT;
	UTIL_SetOrigin(pev,vecOrigin);
	UTIL_SetSize(pev, pev->scale * Vector(-7, -7 , -7), pev->scale * Vector (7, 7, 7));
	pev->velocity=vecVelocity;
	m_flSpeed=vecVelocity.Length();
	pev->angles=UTIL_VecToAngles(pev->velocity);
	pev->rendercolor.x = 0;
	pev->scale*=2;
	SetTouch( &CFriezaDiscAttack::HitTouch );
	SetThink( &CFriezaDiscAttack::FollowThink );
	pev->nextthink = gpGlobals->time;

	//emit fly sound
	EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/rotating.wav", 1.0, ATTN_NORM);
}

void CFriezaDiscAttack :: HomeThink( void  )
{	entvars_t *pevOwner;

	//check of magic has an owner
	if (pev->owner)
	{	pevOwner=VARS(pev->owner);
		Vector vecHome = pevOwner->origin + pevOwner->view_ofs;
		//vecHome.z += 2;
		Vector vecDir = vecHome - pev->origin;
		Vector vecTargetVel = vecDir.Normalize() * m_flSpeed;
		pev->velocity = pev->velocity * 0.2 + vecTargetVel * 0.8;
		pev->angles = UTIL_VecToAngles(pev->velocity);
	}
	else
	{	SetThink(&CFriezaDiscAttack::NormalThink);		
	}

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

	//set up disc for removal, when it leaves the world
	if (!IsInWorld())
	{	Vaporize();
	}
	pev->nextthink = gpGlobals->time + 0.3;
}

void CFriezaDiscAttack :: 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;
		TraceResult tr;
		UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, pev->owner, &tr );
		tr.vecEndPos = tr.vecEndPos - 10 * gpGlobals->v_forward;//move it a little from edges of the hitpoint

		UTIL_MakeAimVectors( pev->angles );
		Vector vecTarget = gpGlobals->v_forward;
		
		float flDist, flMax, flDot;
		flMax = 4096;
		
		Vector vecDir = tr.vecEndPos - pev->origin;
		flDist = vecDir.Length( );
		vecDir = vecDir.Normalize( );
		flDot = DotProduct( gpGlobals->v_forward, vecDir );
		if ((flDot > 0) && (flDist * (1 - flDot) < flMax))
		{	vecTarget = vecDir;
		}
		
		pev->velocity = (pev->velocity).Normalize() * 0.8 * m_flSpeed + vecTarget * m_flSpeed * 0.2;
		pev->angles = UTIL_VecToAngles( pev->velocity );		
	}
	else
	{	SetThink(&CFriezaDiscAttack::NormalThink);
	}

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

	//set up disc for removal, when it leaves the world
	if (!IsInWorld())
	{	
		Vaporize();
	}
	pev->nextthink = gpGlobals->time + 0.3;
}
//-------------------------------------------------------------------
/**
* Frieza's Destructo Disc Weapon
* @version 15-6-2001
* @author Herwin 'harSens' van Welbergen
*/
class CFriezaDisc:public CChargedAttack
{	
public:
	/**
	* Init function
	*/
	void Spawn( void );

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

	/**
	* Get frieza disc slot
	* return int: the slot, is 5 for frieza disc
	*/
	int iItemSlot( void ) { return 5; }

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

	/**
	 * Called when the friezadisc is selected as weapon
	 * @return BOOL: true, if deploy succeeded
	 */
	BOOL Deploy( void );

	/** 
	 * charges the disc
	 */
	void PrimaryAttack( void );

	/**
	 * Homes the disc(s)
	 */
	void SecondaryAttack( void );

	/**
	 * Idle
	 */
	void WeaponIdle(void);

	/**
	 * Holsters the disc
	 */
	void Holster(int skiplocal);
	
	/**
	 * Emits shoot sound
	 */
	void EmitShootSound();
	
	/*
	* Pcjoe: Holster when meleed
	*/
	BOOL HolsterWhenMeleed( void ) { return TRUE; }

	void Shoot();
private:
	/**
	 * Stops aiming the frieza disc
	 */
	void StopControl(void);

	/**
	 * Handles the different disc states
	 */
	void HandleDiscStatus(void);

	/**
	* enables the chargesprite
	*/
	void EnableChargeSprite();
	
	/**
	 * disables the chargesprite
	 */
	void DisableChargeSprite();

	/**
	 * Grow charge sprite
	 */
	void GrowChargeSprite();
	
	/**
 	 * shoots a friezadisc
 	 */
	void ShootAttack();	

	/**
	 * Release the disc
	 */
	void Release();

	/**
	 * Emits the charge sound
	 */
	void EmitChargeSound();

	enum { DISK_IDLE, DISK_SHOOTING, DISK_RETURNING, DISK_RETURNED} m_eDiscStatus;
	CFriezaDiscAttack *m_pDisc;

};

LINK_ENTITY_TO_CLASS( weapon_friezadisc, CFriezaDisc);

void CFriezaDisc::Spawn( void )
{	Precache();
	m_iId = WEAPON_FRIEZADISC;
	m_iDefaultAmmo = 0;
	m_iClip = -1;
	m_iMaxCharge = FRIEZADISC_MAXCHARGETIME;
	m_iKiCost = FRIEZADISC_KI_COST;
	m_flPlayerSlowDown = 0.5;
	strcpy(m_pAttackName,"friezadisc");

	FallInit();// get ready to fall down.
}

void CFriezaDisc::Precache( void )
{	PRECACHE_MODEL("models/w_friezadisc.mdl");
	PRECACHE_SOUND("weapons/rotating.wav");
	PRECACHE_SOUND("weapons/disc_fire.wav");
	PRECACHE_SOUND("weapons/miscdisc_charge.wav");
	PRECACHE_SOUND("weapons/disckill.wav");
}

int CFriezaDisc::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 = 4;
	p->iPosition = 1;
	p->iId = m_iId = WEAPON_FRIEZADISC;
	p->iWeight = FRIEZADISC_WEIGHT;
	p->iFlags = 0;
	return 1;
}

void CFriezaDisc::DisableChargeSprite()
{
}

void CFriezaDisc::EnableChargeSprite()
{	m_pDisc = CFriezaDiscAttack::ChargeFriezaDisc(m_pPlayer->pev, m_pPlayer->GetGunPosition(),0.5 *(float)m_iCharge/(float)m_iMaxCharge);
}

void CFriezaDisc::GrowChargeSprite()
{	m_pDisc->pev->scale = 0.5 * (float)m_iCharge / (float)m_iMaxCharge;
}

BOOL CFriezaDisc::Deploy( void )
{	m_eDiscStatus = DISK_IDLE;
	m_pDisc = NULL;
	return CChargedAttack::Deploy( );	
}

void CFriezaDisc::Release()
{	m_pPlayer->m_fAimAnimation = false;
	if(m_pDisc->m_fRemoved)
	{	m_pDisc->Remove();
	}
	else
	{	m_pDisc->SetThink(&CFriezaDiscAttack::NormalThink);
		m_pDisc->m_fReleased=true;
	}
}

void CFriezaDisc::Holster(int skiplocal=0)
{	if (m_eDiscStatus == DISK_RETURNING || m_eDiscStatus == DISK_SHOOTING)
	{	Release();	
	}
	if (m_eDiscStatus == DISK_SHOOTING)
	{	StopControl();
	}
	if(m_eDiscStatus == DISK_RETURNED || (m_eDiscStatus == DISK_IDLE && m_pDisc))
	{	//DisableChargeSprite();
		m_pDisc->Remove();
		m_pPlayer->m_fHoldDisc = false;
		m_pPlayer->m_flSlowDown = 1.0;	
	}
	CChargedAttack::Holster(skiplocal);	
	m_pPlayer->m_fHoldDisc = false;
	m_pPlayer->m_fAimAnimation = false;	
}

void CFriezaDisc::WeaponIdle(void)
{	if (m_eDiscStatus == DISK_IDLE)
	{	CChargedAttack::WeaponIdle();			
	}		
	HandleDiscStatus();	
}
	
void CFriezaDisc::HandleDiscStatus(void)
{	Vector vecHome;
	Vector vecDir;
	switch (m_eDiscStatus)
	{
	case DISK_RETURNING:
		vecHome = m_pPlayer->GetGunPosition();
		vecDir = m_pDisc->pev->origin-vecHome;
		if (vecDir.Length()<100)
		{	//returned home
			m_eDiscStatus = DISK_RETURNED;
			m_pDisc->Returned();
			m_pPlayer->m_fHoldDisc = true;
			m_pPlayer->m_flSlowDown = 0.5;
			break;
		}
		//stop shoot ani
		m_pPlayer->StopAniTrigger(PLAYER_ATTACK1);
		
		//go down, to do check if the disc is still there
	case DISK_SHOOTING:
		if (m_pDisc->m_fRemoved)
		{	m_pDisc->Remove();
			m_pDisc = NULL;
			StopControl();
			m_eDiscStatus = DISK_IDLE;
		}

		//hit by melee, release attack
		else if(m_pPlayer->m_fMelee)
		{	Release();
			StopControl();
			m_eDiscStatus = DISK_IDLE;
		}
		break;
	case DISK_IDLE:
		//do idle animation stuff here
		break;
	default:
		break;
	}
}

void CFriezaDisc::StopControl()
{	m_pPlayer->m_fControl = false;
	m_pPlayer->m_flSlowDown = 1.0;
}

void CFriezaDisc::Shoot()	
{	m_pPlayer->m_flSlowDown=1.0;
	m_pPlayer->m_fCharging=false;

	

	m_pPlayer->DrawChargeBar(0); // undo drawing charge bar

	//prevent mass shooting
	if (m_iCharge <= m_iMaxCharge/3)
	{	SilenceVoice();
		SilenceWeaponSounds();
		return;
	}
		
	

	EmitShootSound();
	
	//shoot the attack
	ShootAttack();
	
	//should be called last, in case the charge sprite IS the attack (e.g. telekinesis)
	DisableChargeSprite();
}

void CFriezaDisc::ShootAttack( void )
{	
	m_eDiscStatus=DISK_SHOOTING;
	
	UTIL_MakeVectors( m_pPlayer->pev->v_angle );
	Vector vecSrc = m_pPlayer->GetGunPosition() + Vector(0,0,2);
	
	Vector vecThrow = gpGlobals->v_forward * FRIEZADISC_SPEED;
	m_pDisc->Shoot(vecSrc, vecThrow);
		
	//remove disc
	/*
	MESSAGE_BEGIN(MSG_ALL, gmsgRemoveDisc);
		WRITE_SHORT(m_pPlayer->entindex());
	MESSAGE_END();
	*/

	//player in control mode
	m_pPlayer->m_fCharging = false;
	m_pPlayer->m_fHoldDisc = false;
	m_pPlayer->m_fAimAnimation = false;
	m_pPlayer->m_fControl = true;
	m_pPlayer->m_flSlowDown = 0.0;	
}

void CFriezaDisc::EmitShootSound()
{	EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/disc_fire.wav", 1.0, ATTN_NORM);
}

void CFriezaDisc::EmitChargeSound()
{	EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/miscdisc_charge.wav", 1.0, ATTN_NORM);
}

void CFriezaDisc::PrimaryAttack( void )
{
	//can't  if we have already launced a disc
	if (m_eDiscStatus==DISK_IDLE)
	{	CChargedAttack::PrimaryAttack();		
	}
	else if(m_eDiscStatus==DISK_RETURNED)
	{	EmitShootSound();
		ShootAttack();		
	}
	else
	{	HandleDiscStatus();
	}
}

void CFriezaDisc::SecondaryAttack( void )
{	if (m_eDiscStatus == DISK_SHOOTING)
	{	StopControl();
		m_pDisc->SetThink(&CFriezaDiscAttack::HomeThink);
		m_eDiscStatus = DISK_RETURNING;
		m_pPlayer->m_fHoldDisc = true;
		m_pPlayer->m_fAimAnimation = true;
	}
	else
	{	HandleDiscStatus();
	}
}