#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 "controlledbeam.h"
#define GENERICBALL_TRAILLENGTH		40

extern const char *g_pAuraColorString[];
extern Vector g_vecAuraColor[];

extern int gmsgFlare;

/**
 * generic ball attack
 * @version 21-10-2003
 * @author Herwin 'harSens' van Welbergen
 */
class CGenericBall:public CBeamAttack
{	
public:
	/**
	* Create a guided magical attack 
	* @param entvars_t *pevOwner: Monster/Player who shoots it
	* @param Vector vecStart: Origin vector of the attack
	* @param Vector vecVelocity: Velocity of the attack
	* @param int damage: Amount of damage the attack does
	* @param char *attack: Name of the attack
	* @param float size: relative size of the attack (0..1)
	* @param int explosioncolor: the color of the explosion
	* @param int trail: the sprite for the trailing beam
	* @param int starta: the sprite for the beam flare
	* @param int startb: the sprite for the beam flare
	* @param int flarea: the sprite for the beam start
	* @param int flareb: the sprite for the beam start
	* @param int radius: the radius for the beam
	* @return *CGuidedAttack: The created MagicAttack 
	*/
	static CGenericBall *ShootGenericBall( 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);
};

CGenericBall* CGenericBall::ShootGenericBall( 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)
{	CGenericBall *pMagicAttack = GetClassPtr( (CGenericBall *)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 flSize = size * GUIDEDATTACK_SIZE;
	float flAttackSize = flSize * 0.25;//compensate for empty space in sprites
	UTIL_SetOrigin(pMagicAttack->pev,vecStart+ flAttackSize * vecVelocity.Normalize());	
	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(pMagicAttack->pev->velocity);
	pMagicAttack->pev->owner=ENT(pevOwner);
	pMagicAttack->pev->classname = MAKE_STRING( attack );
	
	pMagicAttack->SetTouch( &CGenericBall::ExplodeTouch );

	//pMagicAttack->AddEntEntTrail( (CBaseEntity::Instance(pevOwner))->entindex(), trailattachment, starta, startb, flarea, flareb, trail, size * GUIDEDATTACK_SIZE, 2);
	MESSAGE_BEGIN( MSG_ALL, gmsgFlare, NULL );
		WRITE_LONG(pMagicAttack->entindex());		//end entity
		WRITE_SHORT(flarea);						//start attachment
		WRITE_SHORT(flareb);						//start sprites
		WRITE_SHORT(flSize * 0.1);					//size in .1's
		WRITE_SHORT(trail);							//trail sprite
		WRITE_SHORT(GENERICBALL_TRAILLENGTH * size);//trail length
		WRITE_COORD(vecStart.x);					//start pos
		WRITE_COORD(vecStart.y);
		WRITE_COORD(vecStart.z);
	MESSAGE_END();


	pMagicAttack->SetThink( &CGenericBall::NormalThink );
	pMagicAttack->m_iRadius = radius;
		
	pMagicAttack->m_iExplosionColor = explosioncolor;

	EMIT_SOUND(ENT(pMagicAttack->pev), CHAN_WEAPON, "weapons/beamhead.wav", 1.0, ATTN_NORM);
	
	pMagicAttack->pev->nextthink = gpGlobals->time;

	/*DEBUG by harSens: enable bbox	
	extern int gmsgBoundingBox;
	MESSAGE_BEGIN( MSG_ALL, gmsgBoundingBox);
		WRITE_LONG(pMagicAttack->entindex());
	MESSAGE_END();		
	*/
	
	return pMagicAttack;
}

/**
* Generic Beam
* @version: 24-3-2002
* @author Herwin 'harSens' van Welbergen
*/
class CGenericBeam:public CControlledBeam
{	
public:
	/**
	* Init function
	*/
	void Spawn( void );

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

	/**
	* Deploys attack
	*/
	BOOL Deploy(void);

	/**
	* Get kamehameha slot
	* return int: the slot, is 3 for generic beam
	*/
	int iItemSlot( void ) { return 3; }

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

	/**
	 * charge generic ball, if appropiate
	 */
	void SecondaryAttack();

	/**
	 * charge generic beam
	 */
	void PrimaryAttack();

	/**
	 * Shoot
	 */
	virtual void Shoot();

private:
	CSprite *m_pChargeSprite;		//the sprites wich appears after charging
	/**
	* Inits charge sprite
	*/
	virtual void InitChargeSprite();

	/**
	* Enable charge sprite
	*/
	virtual void EnableChargeSprite(){m_pChargeSprite->SetScale(0.015);m_pChargeSprite->TurnOn();};

	/**
	* Disable charge sprite
	*/
	virtual void DisableChargeSprite(){m_pChargeSprite->TurnOff();};

	/**
	* Grow charge sprite
	*/
	virtual void GrowChargeSprite(){m_pChargeSprite->SetScale((float)m_iCharge * 0.015);};

	/**
	* Remove charge sprite
	*/
	virtual void RemoveChargeSprite(){UTIL_Remove(m_pChargeSprite);};
	
	/**
	 * Emits shoot sound
	 */
	virtual void EmitShootSound();

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

	bool m_fChargeBall;	
	short m_sTrails[5];
	short m_sFlareAs[5];
	short m_sFlareBs[5];
	short m_sStartAs[5];
	short m_sStartBs[5];
};

LINK_ENTITY_TO_CLASS( weapon_genericbeam, CGenericBeam );

void CGenericBeam::Spawn( void )
{	Precache();
	m_eAttackState = ATTACK_IDLE; //not firing
	m_iCharge = 0;
	m_pMagic = NULL;
	m_iId = WEAPON_GENERICBEAM;
	m_iDefaultAmmo = 0;
	m_iClip = -1;

	m_iMaxCharge = GENERICBEAM_MAXCHARGETIME;
	m_iSpeed = GENERICBEAM_SPEED;
	m_iKiCost = GENERICBEAM_KI_COST;
	m_iDamage = GENERICBEAM_DAMAGE;
	m_iRadius = GENERICBEAM_RADIUS;
	m_flPlayerSlowdown = GENERICBEAM_PLAYERSLOWDOWN;
	strcpy(m_pAttackName,"genericbeam");
	m_flRateOfTurn = GENERICBEAM_ROT;
	m_iAttachment =	1;

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

void CGenericBeam::Precache( void )
{	m_sFlareAs[0] = PRECACHE_MODEL("sprites/blueattacka.spr");
	m_sFlareAs[1] = PRECACHE_MODEL("sprites/greenattacka.spr");
	m_sFlareAs[2] = PRECACHE_MODEL("sprites/purpleattacka.spr");
	m_sFlareAs[3] = PRECACHE_MODEL("sprites/redattacka.spr");
	m_sFlareAs[4] = PRECACHE_MODEL("sprites/yellowattacka.spr");

	m_sFlareBs[0] = PRECACHE_MODEL("sprites/blueattackb.spr");
	m_sFlareBs[1] = PRECACHE_MODEL("sprites/greenattackb.spr");
	m_sFlareBs[2] = PRECACHE_MODEL("sprites/purpleattackb.spr");
	m_sFlareBs[3] = PRECACHE_MODEL("sprites/redattackb.spr");
	m_sFlareBs[4] = PRECACHE_MODEL("sprites/yellowattackb.spr");

	m_sStartAs[0] = PRECACHE_MODEL("sprites/blueattackastart.spr");
	m_sStartAs[1] = PRECACHE_MODEL("sprites/greenattackastart.spr");
	m_sStartAs[2] = PRECACHE_MODEL("sprites/purpleattackastart.spr");
	m_sStartAs[3] = PRECACHE_MODEL("sprites/redattackastart.spr");
	m_sStartAs[4] = PRECACHE_MODEL("sprites/yellowattackastart.spr");

	m_sStartBs[0] = PRECACHE_MODEL("sprites/blueattackbstart.spr");
	m_sStartBs[1] = PRECACHE_MODEL("sprites/greenattackbstart.spr");
	m_sStartBs[2] = PRECACHE_MODEL("sprites/purpleattackbstart.spr");
	m_sStartBs[3] = PRECACHE_MODEL("sprites/redattackbstart.spr");
	m_sStartBs[4] = PRECACHE_MODEL("sprites/yellowattackbstart.spr");

	m_sTrails[0] = PRECACHE_MODEL("sprites/bluetrail.spr");
	m_sTrails[1] = PRECACHE_MODEL("sprites/greentrail.spr");
	m_sTrails[2] = PRECACHE_MODEL("sprites/purpletrail.spr");
	m_sTrails[3] = PRECACHE_MODEL("sprites/redtrail.spr");
	m_sTrails[4] = PRECACHE_MODEL("sprites/yellowtrail.spr");

	PRECACHE_MODEL("sprites/bluecharge.spr");
	PRECACHE_MODEL("sprites/greencharge.spr");
	PRECACHE_MODEL("sprites/purplecharge.spr");
	PRECACHE_MODEL("sprites/redcharge.spr");
	PRECACHE_MODEL("sprites/yellowcharge.spr");

	PRECACHE_SOUND("weapons/basicbeam_charge.wav");
	PRECACHE_SOUND("weapons/basicbeam_fire.wav");

	CControlledBeam::Precache();
}

BOOL CGenericBeam::Deploy( void )
{	InitChargeSprite();
	m_fChargeBall = false;

	int iSpriteColor = m_pPlayer->m_pClass->GetAuraSkin();

	m_sTrail = m_sTrails[iSpriteColor];
	m_sFlareA = m_sFlareAs[iSpriteColor];
	m_sFlareB = m_sFlareBs[iSpriteColor];
	m_sStartA = m_sStartAs[iSpriteColor];
	m_sStartB = m_sStartBs[iSpriteColor];
	
	//set explosion color
	switch (iSpriteColor)
	{
	case AURA_WHITE_SKIN: m_iExplosionColor = BLUE_EXPLOSION;break;
	case AURA_GREEN_SKIN: m_iExplosionColor = GREEN_EXPLOSION;break;
	case AURA_PURPLE_SKIN:m_iExplosionColor = PURPLE_EXPLOSION;break;
	//case AURA_RED_SKIN:m_iExplosionColor = RED_EXPLOSION;break;
	case AURA_YELLOW_SKIN:m_iExplosionColor = YELLOW_EXPLOSION;break;
	default:break;
	};
	
	sprintf(m_pAttackName,"%sattack", g_pAuraColorString[iSpriteColor]);

	m_eAttackState = ATTACK_IDLE;
	return DefaultDeploy( "genericbeam" );
}

int CGenericBeam::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 = 2;
	p->iPosition = 0;
	p->iId = m_iId = WEAPON_GENERICBEAM;
	p->iWeight = GENERICBEAM_WEIGHT;
	p->iFlags = 0;
	return 1;
}

void CGenericBeam::InitChargeSprite( void )
{	char pAuraColor[255];
	strcpy(pAuraColor,g_pAuraColorString[m_pPlayer->m_pClass->GetAuraSkin()]);
	char pChargeSprite[255];
	sprintf(pChargeSprite,"sprites/%scharge.spr",pAuraColor);
	m_pChargeSprite = CSprite::SpriteCreate( pChargeSprite, m_pPlayer->pev->origin, true);
	m_pChargeSprite->SetAttachment(m_pPlayer->edict(),1);
	m_pChargeSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 254, kRenderFxGlowShell );
	m_pChargeSprite->SetScale(0.1);
	m_pChargeSprite->pev->framerate = 10;
	m_pChargeSprite->TurnOff();	
}

void CGenericBeam::Shoot()
{
	if(!m_fChargeBall)
	{	CControlledBeam::Shoot();
		return;
	}

	// Moved by Pcjoe
	//set the right animation
//	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
	
	m_fChargeBall = false;
	/* Modified by Rick
	//disable charge bar
	MESSAGE_BEGIN( MSG_ONE, gmsgCharge, NULL, m_pPlayer->pev ); 
		WRITE_BYTE( 0 );	//amount charged in %
	MESSAGE_END();*/

	m_pPlayer->DrawChargeBar(0); // disable charge bar
	
	//silence charge sounds
	SilenceWeaponSounds();
		
	m_pPlayer->m_fCharging = false;
	
	m_eAttackState=ATTACK_IDLE;
		
	//charge to low?
	if (m_iCharge<m_iMaxCharge/3)
	{	m_pPlayer->m_flSlowDown = 1.0;

		SilenceVoice();
		return;
	}

	// Moved by Pcjoe
	//set the right animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	//turn the charging sprite off
	DisableChargeSprite();
		
	//make shoot/control sounds
	EmitShootSound();
	
	UTIL_MakeVectors( m_pPlayer->pev->v_angle );
	Vector vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 10;
	Vector vecThrow = gpGlobals->v_forward * m_iSpeed;
	
	//shoot the magic
	float flSize = (float)m_iCharge/(float)m_iMaxCharge;	
	// Edited by Pcjoe, generic ball gets its own ( reduced ) damage
//	CGenericBall::ShootGenericBall( m_pPlayer->pev, vecSrc, vecThrow, m_iCharge * m_iDamage * GetPowerRatio(),m_pAttackName ,flSize, m_iExplosionColor,m_sTrail, m_sStartA, m_sStartB, m_sFlareA, m_sFlareB, m_iRadius);
	CGenericBall::ShootGenericBall( m_pPlayer->pev, vecSrc, vecThrow, m_iCharge * GENERICBALL_DAMAGE * GetPowerRatio(),m_pAttackName ,flSize, m_iExplosionColor,m_sTrail, m_sStartA, m_sStartB, m_sFlareA, m_sFlareB, m_iRadius);
}

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

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

void CGenericBeam::PrimaryAttack()
{	m_fChargeBall = false;
	CControlledBeam::PrimaryAttack(); 	
}

void CGenericBeam::SecondaryAttack()
{	if(m_eAttackState != ATTACK_AIM)
	{	m_fChargeBall = true;
		Charge();
		m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + CHARGETIME;
	}
	else
	{	CControlledBeam::SecondaryAttack();
	}
}