/***
*
*	Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*	
*	This product contains software technology licensed from Id 
*	Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*	All Rights Reserved.
*
*   Use, distribution, and modification of this source code and/or resulting
*   object code is restricted to non-commercial enhancements to products from
*   Valve LLC.  All other use, distribution, or modification is prohibited
*   without written permission from Valve LLC.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )

#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "hornet.h"
#include "gamerules.h"
#include "effects.h"
#include "BMOD_messaging.h"
#include "decals.h"
#include "BMOD_zapgunrift.h"
#include "shake.h"
#include "squeakgrenade.h"

short iBSquidSpitSprite;

extern cvar_t bm_freezetime;
extern cvar_t bm_hornet_mod;

enum hgun_e
{
	HGUN_IDLE1 = 0,
	HGUN_FIDGETSWAY,
	HGUN_FIDGETSHAKE,
	HGUN_DOWN,
	HGUN_UP,
	HGUN_SHOOT
};

enum hgun_phase
{
	HGUN_IDLE = 0,
	HGUN_CHARGE,
	HGUN_ZAP,
	HGUN_ZAP_DONE,
	HGUN_SPIT
};

enum firemode_e
{
	FIREMODE_TRACK = 0,
	FIREMODE_FAST
};

//=========================================================
// Bullsquid's spit projectile
//=========================================================
class BMODSquidSpit : public CBaseEntity
{
public:
        void Spawn( void );

        static void Shoot( entvars_t *Owner, Vector vecStart, Vector vecVelocity );
        void Touch( CBaseEntity *pOther );
        void EXPORT Animate( void );

        static  TYPEDESCRIPTION m_SaveData[];

        int  m_maxFrame;
	entvars_t *pevOwner;

};

LINK_ENTITY_TO_CLASS( squidspit, BMODSquidSpit );

void BMODSquidSpit:: Spawn( void )
{
        pev->movetype = MOVETYPE_FLY;
        pev->classname = MAKE_STRING( "squidspit" );

        pev->solid = SOLID_BBOX;
        pev->rendermode = kRenderTransAlpha;
        pev->renderamt = 255;

        SET_MODEL( ENT( pev ), "sprites/bigspit.spr" );
        pev->frame = 0;
        pev->scale = 0.5;

        UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) );

        m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1;

	MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
        	WRITE_BYTE( TE_BEAMFOLLOW );
	        WRITE_SHORT( entindex() ); // entity
	        WRITE_SHORT( g_sModelIndexLightning ); // model
	        WRITE_BYTE( 2 ); // life
	        WRITE_BYTE( 4 ); // width
	        WRITE_BYTE( 128 ); // r, g, b
	        WRITE_BYTE( 200 ); // r, g, b
	        WRITE_BYTE( 0 ); // r, g, b
	        WRITE_BYTE( 255 ); // brightness
        MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS)
}

void BMODSquidSpit::Animate( void )
{
        pev->nextthink = gpGlobals->time + 0.1;

        if( pev->frame++ )
        {
		if( pev->frame > m_maxFrame )
		{
			pev->frame = 0;
		}
	}
}

void BMODSquidSpit::Shoot( entvars_t *Owner, Vector vecStart, Vector vecVelocity )
{
	BMODSquidSpit *pSpit = GetClassPtr( (BMODSquidSpit *)NULL );
	pSpit->Spawn();

	UTIL_SetOrigin( pSpit->pev, vecStart );
	pSpit->pev->velocity = vecVelocity;
	pSpit->pev->owner = ENT( Owner );
	pSpit->pevOwner = Owner;

	pSpit->SetThink( &BMODSquidSpit::Animate );
	pSpit->pev->nextthink = gpGlobals->time + 0.1;
}

void BMODSquidSpit::Touch( CBaseEntity *pOther )
{
	TraceResult tr;
	int iPitch;

	// splat sound
	iPitch = RANDOM_FLOAT( 90, 110 );

	EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch );

	switch( RANDOM_LONG( 0, 1 ) )
	{
	case 0:
		EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch );
                break;
        case 1:
		EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch );
		break;
	}
        
        // make a splat on the wall
        UTIL_TraceLine( pev->origin, pev->origin + pev->velocity, dont_ignore_monsters, ENT( pev ), &tr );
        UTIL_DecalTrace( &tr, DECAL_SPIT1 + RANDOM_LONG( 0, 1 ) );
	
        // make some flecks
        MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos );
        	WRITE_BYTE( TE_SPRITE_SPRAY );
                WRITE_COORD( tr.vecEndPos.x );	// pos
                WRITE_COORD( tr.vecEndPos.y );
                WRITE_COORD( tr.vecEndPos.z );
                WRITE_COORD( tr.vecPlaneNormal.x );	// dir
                WRITE_COORD( tr.vecPlaneNormal.y );
                WRITE_COORD( tr.vecPlaneNormal.z );
                WRITE_SHORT( iBSquidSpitSprite );	// model
                WRITE_BYTE( 5 );			// count
                WRITE_BYTE( 30 );			// speed
                WRITE_BYTE( 80 );			// noise ( client will divide by 100 )
        MESSAGE_END();

        if( pOther->IsPlayer() )
	{
		ClearMultiDamage();
       	       	pOther->TraceAttack( pevOwner, 30, pev->origin + pev->velocity, &tr, DMG_GENERIC );
		ApplyMultiDamage( pev, pevOwner );
	}

	SetThink( &CBaseEntity::SUB_Remove );
	pev->nextthink = gpGlobals->time;
}

#include "BMOD_hornetgun.h"

LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun )

//=========================================================
// ClearBeams - remove all beams
//=========================================================
void CHgun::ClearBeams()
{
	for( int i = 0; i < HGUN_MAX_BEAMS; i++ )
	{
                if( m_pBeam[i] )
                {
                        UTIL_Remove( m_pBeam[i] );
                        m_pBeam[i] = NULL;
                }
        }
        m_iBeams = 0;

        STOP_SOUND( ENT(m_pPlayer->pev), CHAN_WEAPON, "debris/zap4.wav" );
}

//=========================================================
// ArmBeam - small beam from arm to nearby geometry
//=========================================================

void CHgun::ArmBeam( Vector color )
{
        TraceResult tr;
        float flDist = 1.0;

	if( m_iBeams >= HGUN_MAX_BEAMS )
		return;

        // UTIL_MakeAimVectors( pev->angles );
        Vector vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;

	for( int i = 0; i < 3; i++ )
	{
                Vector vecAim = gpGlobals->v_right * RANDOM_FLOAT( -1, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 );
                TraceResult tr1;
                UTIL_TraceLine( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr1 );
                if( flDist > tr1.flFraction )
                {
                        tr = tr1;
                        flDist = tr.flFraction;
                }
        }

        // Couldn't find anything close enough
        if( flDist == 1.0 )
                return;

        // DecalGunshot( &tr, BULLET_PLAYER_CROWBAR );

        m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
        if( !m_pBeam[m_iBeams] )
                return;

        m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, m_pPlayer->entindex() );
        m_pBeam[m_iBeams]->SetEndAttachment( 1 );
        // m_pBeam[m_iBeams]->SetColor( 96, 128, 16 );
        m_pBeam[m_iBeams]->SetColor( color.x, color.y, color.z );
        m_pBeam[m_iBeams]->SetBrightness( 64 );
        m_pBeam[m_iBeams]->SetNoise( 80 );
        m_pBeam[m_iBeams]->pev->spawnflags |= SF_BEAM_TEMPORARY;
        m_iBeams++;
}

//=========================================================
// ZapBeam - heavy damage directly forward
//=========================================================
void CHgun::ZapBeam( void )
{
        Vector vecSrc, vecAim, vecOrig;
        TraceResult tr;
        CBaseEntity *pEntity;

	/*
        if (m_iBeams >= HGUN_MAX_BEAMS)
                return;
	*/

	// UTIL_MakeVectors( m_pPlayer->pev->v_angle );
        vecOrig = m_pPlayer->GetGunPosition();
        vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;
        vecAim = gpGlobals->v_forward;

        UTIL_TraceLine( vecOrig, vecOrig + vecAim * 2048, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );

		for( int i = 0; i < 2; i++ )
		{
			MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
					WRITE_BYTE( TE_BEAMPOINTS );
					WRITE_COORD( vecSrc.x );
					WRITE_COORD( vecSrc.y );
					WRITE_COORD( vecSrc.z );
					WRITE_COORD( tr.vecEndPos.x );
					WRITE_COORD( tr.vecEndPos.y );
					WRITE_COORD( tr.vecEndPos.z );
					WRITE_SHORT( iZapBeamSpr );
					WRITE_BYTE( 0 ); // Starting frame
					WRITE_BYTE( 0  ); // framerate * 0.1
					WRITE_BYTE( 2 ); // life * 0.1
					WRITE_BYTE( 50 ); // width
					WRITE_BYTE( 20 ); // noise
					WRITE_BYTE( 180 ); // color r,g,b
					WRITE_BYTE( 255 ); // color r,g,b
					WRITE_BYTE( 96 ); // color r,g,b
					WRITE_BYTE( 255 ); // brightness
					WRITE_BYTE( 0 ); // scroll speed
			MESSAGE_END();
		}

        UTIL_DecalTrace( &tr, DECAL_SMALLSCORCH1 + RANDOM_LONG( 0, 2 ) );

	/*
        m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 );
        if( !m_pBeam[m_iBeams] )
                return;
        m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, m_pPlayer->entindex() );
        m_pBeam[m_iBeams]->SetEndAttachment( 1 );
        m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
        m_pBeam[m_iBeams]->SetBrightness( 255 );
        m_pBeam[m_iBeams]->SetNoise( 20 );
        m_pBeam[m_iBeams]->pev->spawnflags |= SF_BEAM_TEMPORARY;
        m_iBeams++;
	*/

        pEntity = CBaseEntity::Instance(tr.pHit);
        if( pEntity != NULL && pEntity->pev->takedamage )
        {
			// pEntity->TakeDamage( pev, VARS (pev->owner), 45, DMG_SHOCK );
		ClearMultiDamage();
		entvars_t *Owner;
		Owner = VARS( pev->owner );
		pEntity->TraceAttack( Owner, 90, vecAim, &tr, DMG_SHOCK | DMG_ALWAYSGIB );
		ApplyMultiDamage( pev, Owner );
	        UTIL_ScreenFade( pEntity, Vector(180,255,96), 2, 0.5, 128, FFADE_IN ); 
        }

        UTIL_EmitAmbientSound( ENT( m_pPlayer->pev ), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );

	if( UTIL_PointContents( tr.vecEndPos ) == CONTENTS_WATER )
	{
		CBaseEntity *pRift = CBaseEntity::Create( "zaprift", tr.vecEndPos, UTIL_VecToAngles( tr.vecPlaneNormal ), m_pPlayer->edict() );
		// UTIL_EmitAmbientSound( ENT(m_pPlayer->pev), tr.vecEndPos, "weapons/electro4.wav", 50, ATTN_NORM, 0, 300 );
	}
}

//=========================================================
// Freeze Ray - 
//=========================================================
void CHgun::FreezeRay( void )
{
	Vector vecSrc, vecAim, vecOrig;
	TraceResult tr;
	CBaseEntity *pEntity;

	if( ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 12 ) || m_pPlayer->pev->waterlevel == 3 )
	{
		return;
	}

	vecOrig = m_pPlayer->GetGunPosition();
	vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;
	vecAim = gpGlobals->v_forward;
	UTIL_TraceLine( vecOrig, vecOrig + vecAim * 2048, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );

	MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
		WRITE_BYTE( TE_BEAMPOINTS );
		WRITE_COORD( vecSrc.x );
		WRITE_COORD( vecSrc.y );
		WRITE_COORD( vecSrc.z );
		WRITE_COORD( tr.vecEndPos.x );
		WRITE_COORD( tr.vecEndPos.y );
		WRITE_COORD( tr.vecEndPos.z );
		WRITE_SHORT( iZapBeamSpr );
		WRITE_BYTE( 0 ); // Starting frame
		WRITE_BYTE( 0 ); // framerate * 0.1
		WRITE_BYTE( 3 ); // life * 0.1
		WRITE_BYTE( 200 ); // width
		WRITE_BYTE( 2 ); // noise
		WRITE_BYTE( 220 ); // color r,g,b
		WRITE_BYTE( 220 ); // color r,g,b
		WRITE_BYTE( 255 ); // color r,g,b
		WRITE_BYTE( 255 ); // brightness
		WRITE_BYTE( 0 ); // scroll speed
	MESSAGE_END();

	UTIL_DecalTrace( &tr, DECAL_MOMMASPLAT );

	MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
		WRITE_BYTE( TE_SPRITETRAIL );// TE_RAILTRAIL);
		WRITE_COORD( vecSrc.x );
		WRITE_COORD( vecSrc.y );
		WRITE_COORD( vecSrc.z );
		WRITE_COORD( tr.vecEndPos.x );
		WRITE_COORD( tr.vecEndPos.y );
		WRITE_COORD( tr.vecEndPos.z );
		WRITE_SHORT( m_sGlowSpr );		// model
		WRITE_BYTE( 20 );				// count
		WRITE_BYTE( 10 );				// life * 10
		WRITE_BYTE( RANDOM_LONG( 1, 2 ) );				// size * 10
		WRITE_BYTE( 10 );				// amplitude * 0.1
		WRITE_BYTE( 0 );				// speed * 100
	MESSAGE_END();

	pEntity = CBaseEntity::Instance( tr.pHit );
	if( pEntity != NULL && pEntity->pev->takedamage && pEntity->IsPlayer() )
	{
		CBasePlayer *pPlayer = (CBasePlayer *)pEntity;
		
		UTIL_ScreenFade( pPlayer, Vector( 0, 0, 255 ), 2.0, 1.0, 128, FFADE_IN ); 

		pPlayer->pev->rendermode = kRenderNormal;
		pPlayer->pev->renderfx = kRenderFxGlowShell;

		pPlayer->pev->rendercolor.x = 240;  // red
		pPlayer->pev->rendercolor.y = 240;  // green
		pPlayer->pev->rendercolor.z = 255; // blue

		pPlayer->pev->renderamt = 60;  // glow shell distance from entity

		float freezetime = Q_max (.6, bm_freezetime.value);

		// freeze the player and set the "unfreeze" time...
		pPlayer->EnableControl(FALSE);
		pPlayer->m_vFreezeAngle = pPlayer->pev->v_angle;
		// pPlayer->pev->movetype = MOVETYPE_TOSS;

		pPlayer->m_flFreezeTime = gpGlobals->time + freezetime;
		//RuneMsg( pPlayer, "YOU ARE FROZEN!!!", Vector(100,100,255), freezetime - .5);
		PrintMessage( pPlayer, BMOD_CHAN_RUNE, Vector(100,100,255), Vector (.1, freezetime - .5, .1), "YOU ARE FROZEN!!!");

	}

	UTIL_EmitAmbientSound( ENT(m_pPlayer->pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ));

	m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0;
	m_flNextPrimaryAttack = gpGlobals->time + .25;

	m_flRechargeTime = gpGlobals->time + 0.5;

	m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
	m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;

	SendWeaponAnim( HGUN_SHOOT );

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT( 10, 15 );
	m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
}


//=========================================================
// BeamGlow - brighten all beams
//=========================================================
void CHgun::BeamGlow()
{
        int b = m_iBeams * 32;
        if( b > 255 )
                b = 255;

        for( int i = 0; i < m_iBeams; i++ )
        {
                if( m_pBeam[i]->GetBrightness() != 255 )
                {
                        m_pBeam[i]->SetBrightness( b );
                }
        }
}

BOOL CHgun::IsUseable( void )
{
	return TRUE;
}

void CHgun::Spawn()
{
	Precache();
	m_iId = WEAPON_HORNETGUN;
	SET_MODEL( ENT( pev ), "models/w_hgun.mdl" );

	m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE;
	m_iFirePhase = 0;
	m_iFireMode = 0;

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

void CHgun::Precache( void )
{
	PRECACHE_MODEL( "models/v_hgun.mdl" );
	PRECACHE_MODEL( "models/w_hgun.mdl" );
	PRECACHE_MODEL( "models/p_hgun.mdl" );

	m_usHornetFire = PRECACHE_EVENT( 1, "events/firehornet.sc" );

	UTIL_PrecacheOther( "hornet" );
	UTIL_PrecacheOther( "zaprift" );
	UTIL_PrecacheOther( "zapbounce" );
	PRECACHE_SOUND( "debris/zap4.wav" );
	PRECACHE_SOUND( "weapons/electro4.wav" );
	PRECACHE_SOUND( "hassault/hw_shoot1.wav" );
	iZapBeamSpr = PRECACHE_MODEL( "sprites/lgtning.spr" );

	PRECACHE_MODEL( "sprites/bigspit.spr" );
	iBSquidSpitSprite = PRECACHE_MODEL( "sprites/tinyspit.spr" );// client side spittle.
	PRECACHE_SOUND( "bullchicken/bc_acid1.wav" );
	PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" );
	PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" );
	PRECACHE_SOUND( "bullchicken/bc_attack2.wav" );
	PRECACHE_SOUND( "bullchicken/bc_attack3.wav" );
	PRECACHE_SOUND( "leech/leech_bite1.wav" );

	m_sGlowSpr = PRECACHE_MODEL( "sprites/glow04.spr" );
}

int CHgun::AddToPlayer( CBasePlayer *pPlayer )
{
	if( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
	{
#ifndef CLIENT_DLL
		if( g_pGameRules->IsMultiplayer() )
		{
			// in multiplayer, all hivehands come full. 
			pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = 12;
		}
#endif
		MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
			WRITE_BYTE( m_iId );
		MESSAGE_END();
		return TRUE;
	}
	return FALSE;
}

int CHgun::GetItemInfo( ItemInfo *p )
{
	p->pszName = STRING( pev->classname );
	p->pszAmmo1 = "Hornets";
	p->iMaxAmmo1 = m_iMaxammo;
	p->pszAmmo2 = NULL;
	p->iMaxAmmo2 = -1;
	p->iMaxClip = WEAPON_NOCLIP;
	p->iSlot = 3;
	p->iPosition = 3;
	p->iId = m_iId = WEAPON_HORNETGUN;
	p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD;
	p->iWeight = HORNETGUN_WEIGHT;

	return 1;
}

BOOL CHgun::Deploy()
{
	// BMOD Edit - Modified hornet message
	if( bm_hornet_mod.value )
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "HORNET GUN\nACID SPIT - LIGHTNING - FREEZE RAY - SNARKS\nSECONDARY FIRE: Switches modes." );

	return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" );
}

void CHgun::Holster( int skiplocal /* = 0 */ )
{
	ClearBeams();
	m_iFirePhase = HGUN_IDLE;

	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
	SendWeaponAnim( HGUN_DOWN );

	//!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either.
	if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] )
	{
		m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] = 1;
	}
}

void CHgun::SecondaryAttack()
{
	if( !bm_hornet_mod.value )
	{
		OldSecondaryAttack();
		return;
	}

	m_iFireMode = ( m_iFireMode + 1 ) % 5;

	switch( m_iFireMode )
	{
	case 0:
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "\n\nAcid Spit  Mode - 3 per shot");
		break;
	case 1:
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "\n\nLightning  Mode - 4 per shot");
		break;
	case 2:
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "\n\nMultizap  Mode - 12 per shot");
		break;
	case 3:
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "\n\nFreeze Ray Mode - 12 per shot");
		break;
	case 4:
		PrintMessage( m_pPlayer, BMOD_CHAN_WEAPON, Vector( 20, 250, 20 ), Vector( 1, 4, 2 ), "\n\nSnark Launcher Mode - 1 Snark per shot");
		break;
	}

	EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "leech/leech_bite1.wav", 1, ATTN_NORM );
	m_flNextSecondaryAttack = gpGlobals->time + .5;
}

void CHgun::ZapGun()
{
	if( m_iFirePhase == HGUN_IDLE )
		Reload();

	if( ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 4 ) || ( m_fNextPhaseTime > gpGlobals->time ) )
	{
		return;
	}

	if( m_pPlayer->pev->waterlevel > 0 )
	{

		// m_pPlayer->TakeDamage( VARS( eoNullEntity ), VARS( eoNullEntity ), 50, DMG_SHOCK );
		UTIL_ScreenFade( this, Vector( 180, 255, 96 ), 2, 0.5, 128, FFADE_IN ); 

		CBaseEntity *pRift = CBaseEntity::Create( "zaprift", pev->origin, pev->angles, ENT( pev ) );

		m_pPlayer->TakeDamage( m_pPlayer->pev, m_pPlayer->pev, 100, DMG_SHOCK );
		EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 );
		m_flNextPrimaryAttack = m_flNextPrimaryAttack + 1.5;
		return;
	}

	switch( m_iFirePhase )
        {
                case HGUN_IDLE:
                        m_flTimeWeaponIdle = gpGlobals->time;
			m_iFirePhase = HGUN_CHARGE;
			m_fNextPhaseTime = 0;
			m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
			m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
                case HGUN_CHARGE:
                        if( m_fNextPhaseTime < gpGlobals->time )
                        {
                                if( m_iBeams < HGUN_MAX_BEAMS )
                                {
                                        ArmBeam( Vector( 96, 128, 16 ) );
                                        BeamGlow();
                                        m_fNextPhaseTime = gpGlobals->time + HGUN_CHARGE_TIME;
                                        EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0,100 + m_iBeams * 10 );
                                }
                                else
				{
                                        m_iFirePhase = HGUN_ZAP;
                                        m_fNextPhaseTime = gpGlobals->time + .1;
				}
			}
			break;
		case HGUN_ZAP:
			ClearBeams();
			ZapBeam();
			m_iFirePhase = HGUN_ZAP_DONE;
			m_fNextPhaseTime = gpGlobals->time + HGUN_ZAP_TIME;
			EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
			SendWeaponAnim( HGUN_SHOOT );

			// player "shoot" animation
			m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

			m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 4;
			m_flRechargeTime = gpGlobals->time + 0.5;
			m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
			break;
                case HGUN_ZAP_DONE:
			ClearBeams();
			m_flNextPrimaryAttack = gpGlobals->time + .25;
			m_flTimeWeaponIdle = gpGlobals->time + .1;
			break;
	}
}

void CHgun::MultiZapGun()
{
	CZapBounce *pRift = NULL;

	if( m_iFirePhase == HGUN_IDLE )
		Reload();

	if( ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 12 ) || ( m_fNextPhaseTime > gpGlobals->time ) )
	{
		return;
	}

	if( m_pPlayer->pev->waterlevel > 0 )
	{
		UTIL_ScreenFade( this, Vector( 180, 255, 96 ), 2, 0.5, 128, FFADE_IN ); 
		m_pPlayer->TakeDamage( m_pPlayer->pev, m_pPlayer->pev, 100, DMG_SHOCK );
		EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 );
		m_flNextPrimaryAttack = m_flNextPrimaryAttack + 1.5;
		return;
	}

	switch( m_iFirePhase )
        {
                case HGUN_IDLE:
                        m_flTimeWeaponIdle = gpGlobals->time;
			m_iFirePhase = HGUN_CHARGE;
			m_fNextPhaseTime = 0;
			m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
			m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
                case HGUN_CHARGE:
                        if( m_fNextPhaseTime < gpGlobals->time )
                        {
				if( m_iBeams < HGUN_MAX_BEAMS / 2 )
				{
					ArmBeam( Vector( 16, 96, 128 ) );
					BeamGlow();
					m_fNextPhaseTime = gpGlobals->time + HGUN_CHARGE_TIME;
					EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0,100 + m_iBeams * 10 );
				}
				else
					m_iFirePhase = HGUN_ZAP;
					m_fNextPhaseTime = gpGlobals->time + .1;
			}
			break;
                case HGUN_ZAP:
                        ClearBeams();
			pRift = (CZapBounce*)CBaseEntity::Create( "zapbounce", 
							m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, 
							gpGlobals->v_forward, 
							m_pPlayer->edict() );
			if( pRift )
			{
				pRift->m_fDamage = 90;
				pRift->m_iBounce = 5;
				pRift->pentIgnore = ENT( m_pPlayer->pev );
				pRift->m_bFirstZap = TRUE;
				pRift->BounceThink();
			}
                        m_iFirePhase = HGUN_ZAP_DONE;
                        m_fNextPhaseTime = gpGlobals->time + HGUN_ZAP_TIME;
                        EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
                        SendWeaponAnim( HGUN_SHOOT );
                        // player "shoot" animation
                        m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

                        m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 12;
                        m_flRechargeTime = gpGlobals->time + 0.5;
			m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
                        break;
                case HGUN_ZAP_DONE:
                        ClearBeams();
                        m_flNextPrimaryAttack = gpGlobals->time + .25;
                        m_flTimeWeaponIdle = gpGlobals->time + .1;
                        break;
        }
}

void CHgun::PrimaryAttack( void )
{
	if( !bm_hornet_mod.value )
	{
		OldPrimaryAttack();
		return;
	}

	Reload();

	switch( m_iFireMode )
	{
	case 0:
		SquidSpit();
		break;
	case 1:
		ZapGun();
		break;
	case 2:
		MultiZapGun();
		break;
	case 3:
		FreezeRay();
		break;
	case 4:
		LaunchSnark();
		break;
	}
}

void CHgun::SquidSpit( void )
{
	if( ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < 3 ) || ( m_iFirePhase != HGUN_IDLE ) )
	{
		return;
	}

	Vector  vecSrc, vecDir, vecOrig;
	int iSpittle, iSpitSpeed;
	TraceResult tr;

	// UTIL_MakeVectors( m_pPlayer->pev->v_angle );

        // Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
        // UTIL_MakeVectors( anglesAim );

	vecOrig = m_pPlayer->GetGunPosition();
	vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;
	// vecDir = m_pPlayer->pev->v_angle;
	// vecDir = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
	vecDir = gpGlobals->v_forward;
        UTIL_TraceLine( vecOrig, vecOrig + vecDir * 2048, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
	vecDir = ( tr.vecEndPos - vecSrc ).Normalize();

	if( m_pPlayer->pev->waterlevel == 3 )
	{
		iSpittle = 15;	
		iSpitSpeed = 120;
	}
	else
	{
		// CSquidSpit::Shoot( m_pPlayer->edict(), vecSrc, vecDir * 900 );
		// CBaseEntity *pSpit = CBaseEntity::Create( "squidspit", vecSrc, vecDir , pev->owner );
		BMODSquidSpit::Shoot( m_pPlayer->pev, vecSrc, vecDir * 1100 );
		iSpittle = 5;
		iSpitSpeed = 80;
	}

	m_flNextPrimaryAttack = gpGlobals->time + .25;

	// spew the spittle temporary ents.
	MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
		WRITE_BYTE( TE_SPRITE_SPRAY );
		WRITE_COORD( vecSrc.x );	// pos
		WRITE_COORD( vecSrc.y );
		WRITE_COORD( vecSrc.z );
		WRITE_COORD( vecDir.x );	// dir
		WRITE_COORD( vecDir.y );
		WRITE_COORD( vecDir.z );
		WRITE_SHORT( iBSquidSpitSprite );	// model
		WRITE_BYTE( iSpittle );			// count
		WRITE_BYTE( iSpitSpeed );		// speed
		WRITE_BYTE( 25 );		// noise ( client will divide by 100 )
	MESSAGE_END();

        switch( RANDOM_LONG( 0, 1 ) )
        {
        case 0:
                EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM );
                break;
        case 1:
                EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM );
                break;
        }

	m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 3;	
	m_flRechargeTime = gpGlobals->time + 0.5;

	m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
	m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;

	SendWeaponAnim( HGUN_SHOOT );

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );
	m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
}

void CHgun::LaunchSnark( void )
{
	if( ( m_pPlayer->m_rgAmmo[m_pPlayer->GetAmmoIndex( "Snarks" )] < 1 ) || ( m_iFirePhase != HGUN_IDLE ) )
	{
		return;
	}

	Vector  vecSrc, vecDir, vecOrig;
	int iSpittle, iSpitSpeed;
	TraceResult tr;

	vecOrig = m_pPlayer->GetGunPosition();
	vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;
	// vecDir = m_pPlayer->pev->v_angle;
	// vecDir = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
	vecDir = gpGlobals->v_forward;
	UTIL_TraceLine( vecSrc + gpGlobals->v_forward * 20, vecSrc + gpGlobals->v_forward * 40, dont_ignore_monsters, NULL, &tr );
	vecDir = ( tr.vecEndPos - vecSrc ).Normalize();

	if( m_pPlayer->pev->waterlevel == 3 )
	{
		iSpittle = 15;	
		iSpitSpeed = 120;
	}
	else
	{
		CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
		pSqueak->pev->velocity = gpGlobals->v_forward * 1500 + m_pPlayer->pev->velocity;
		( (CSqueakGrenade*)pSqueak )->m_bWasLaunched = TRUE;
		EMIT_SOUND_DYN( ENT( pSqueak->pev ), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 105 );

		iSpittle = 5;
		iSpitSpeed = 80;
	}

	m_flNextPrimaryAttack = gpGlobals->time + .4;

	// spew the spittle temporary ents.
	MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
		WRITE_BYTE( TE_SPRITE_SPRAY );
		WRITE_COORD( vecSrc.x );		// pos
		WRITE_COORD( vecSrc.y );
		WRITE_COORD( vecSrc.z );
		WRITE_COORD( vecDir.x );     // dir
		WRITE_COORD( vecDir.y );
		WRITE_COORD( vecDir.z );
		WRITE_SHORT( iBSquidSpitSprite );	// model
		WRITE_BYTE( iSpittle );		// count
		WRITE_BYTE( iSpitSpeed );	// speed
		WRITE_BYTE( 25 );		// noise ( client will divide by 100 )
	MESSAGE_END();

	switch( RANDOM_LONG( 0, 1 ) )
	{
	case 0:
		EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM );
        	break;
	case 1:
        	EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM );
        	break;
	}

	m_pPlayer->m_rgAmmo[m_pPlayer->GetAmmoIndex( "Snarks" )] -= 1;	
	m_flRechargeTime = gpGlobals->time + 0.5;

	m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
	m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;

	SendWeaponAnim( HGUN_SHOOT );

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT( 10, 15 );
	m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
}

void CHgun::OldPrimaryAttack()
{
	Reload();

	if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
	{
		return;
	}
#ifndef CLIENT_DLL
	UTIL_MakeVectors( m_pPlayer->pev->v_angle );

	CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
	pHornet->pev->velocity = gpGlobals->v_forward * 300;

	m_flRechargeTime = gpGlobals->time + 0.5;
#endif
	m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
	
	m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
	m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;

	int flags;
#if defined( CLIENT_WEAPONS )
	flags = FEV_NOTHOST;
#else
	flags = 0;
#endif
	PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 );

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25;

	if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() )
	{
		m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25;
	}

	m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}

void CHgun::OldSecondaryAttack( void )
{
	Reload();

	if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
	{
		return;
	}

	//Wouldn't be a bad idea to completely predict these, since they fly so fast...
#ifndef CLIENT_DLL
	CBaseEntity *pHornet;
	Vector vecSrc;

	UTIL_MakeVectors( m_pPlayer->pev->v_angle );

	vecSrc = m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12;

	m_iFirePhase++;
	switch( m_iFirePhase )
	{
	case 1:
		vecSrc = vecSrc + gpGlobals->v_up * 8;
		break;
	case 2:
		vecSrc = vecSrc + gpGlobals->v_up * 8;
		vecSrc = vecSrc + gpGlobals->v_right * 8;
		break;
	case 3:
		vecSrc = vecSrc + gpGlobals->v_right * 8;
		break;
	case 4:
		vecSrc = vecSrc + gpGlobals->v_up * -8;
		vecSrc = vecSrc + gpGlobals->v_right * 8;
		break;
	case 5:
		vecSrc = vecSrc + gpGlobals->v_up * -8;
		break;
	case 6:
		vecSrc = vecSrc + gpGlobals->v_up * -8;
		vecSrc = vecSrc + gpGlobals->v_right * -8;
		break;
	case 7:
		vecSrc = vecSrc + gpGlobals->v_right * -8;
		break;
	case 8:
		vecSrc = vecSrc + gpGlobals->v_up * 8;
		vecSrc = vecSrc + gpGlobals->v_right * -8;
		m_iFirePhase = 0;
		break;
	}

	pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
	pHornet->pev->velocity = gpGlobals->v_forward * 1200;
	pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity );

	pHornet->SetThink( &CHornet::StartDart );

	m_flRechargeTime = gpGlobals->time + 0.5;
#endif
	int flags;
#if defined( CLIENT_WEAPONS )
	flags = FEV_NOTHOST;
#else
	flags = 0;
#endif
	PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 );

	m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
	m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
	m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;

	// player "shoot" animation
	m_pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1;
	m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}

void CHgun::Reload( void )
{
	m_iMaxammo = (bm_hornet_mod.value) ? 12 : 8;
	if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= m_iMaxammo )
		return;

	while( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < m_iMaxammo && m_flRechargeTime < gpGlobals->time )
	{
		m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++;
		m_flRechargeTime += 0.5;
	}
}

void CHgun::WeaponIdle( void )
{
	Reload();
	m_iFirePhase = HGUN_IDLE;
	if( m_iBeams )
		ClearBeams();

	if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
		return;

	int iAnim;
	float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 );
	if( flRand <= 0.75 )
	{
		iAnim = HGUN_IDLE1;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * ( 2 );
	}
	else if( flRand <= 0.875 )
	{
		iAnim = HGUN_FIDGETSWAY;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0;
	}
	else
	{
		iAnim = HGUN_FIDGETSHAKE;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0;
	}
	SendWeaponAnim( iAnim );
}
#endif