/*  
* The original Half-Life version of the Gauss
* Converted to SC by Nero
*/
namespace HLGAUSS
{

const int HLGAUSS_PRIMARY_CHARGE_VOLUME	= 256;// how loud gauss is while charging
const int HLGAUSS_PRIMARY_FIRE_VOLUME	= 450;// how loud gauss is when discharged
const int URANIUM_MAX_CARRY				= 100;
const int HLGAUSS_DEFAULT_GIVE			= 100;//20
const float HLGAUSS_DELAY				= 0.20f;
const string HLGAUSS_SPRITE_BALLS		= "sprites/hotglow.spr";
const string HLGAUSS_SPRITE_BEAM		= "sprites/smoke.spr";
const string HLGAUSS_SPRITE_GLOW		= "sprites/hotglow.spr";

enum hlgauss_e
{
	HLGAUSS_IDLE = 0,
	HLGAUSS_IDLE2,
	HLGAUSS_FIDGET,
	HLGAUSS_SPINUP,
	HLGAUSS_SPIN,
	HLGAUSS_FIRE,
	HLGAUSS_FIRE2,
	HLGAUSS_HOLSTER,
	HLGAUSS_DRAW
};

class CHLGauss : ScriptBasePlayerWeaponEntity
{
	protected CBasePlayer@ m_pPlayer
	{
		get const { return cast<CBasePlayer@>(self.m_hPlayer.GetEntity()); }
		set { self.m_hPlayer = EHandle(@value); }
	}

	int HLGAUSS_WEIGHT				= 20;
	int SK_PLR_GAUSS				= 19;
	int m_iBalls, m_iBeam;
	int iGlowBr;
	CSprite@ m_pGlow; 
	float m_flPlayAftershock, m_flNextAmmoBurn, m_flStartCharge, m_flAmmoStartCharge;
	int m_fInAttack, m_iSoundState;
	bool m_fPrimaryFire;

	void Spawn()
	{
		Precache();
		g_EntityFuncs.SetModel( self, "models/w_gauss.mdl" );
		self.m_iDefaultAmmo = HLGAUSS_DEFAULT_GIVE;
		self.FallInit();
	}


	void Precache()
	{
		self.PrecacheCustomModels();
		g_Game.PrecacheModel( "models/w_gauss.mdl" );
		g_Game.PrecacheModel( "models/v_gauss.mdl" );
		g_Game.PrecacheModel( "models/p_gauss.mdl" );

		g_SoundSystem.PrecacheSound( "items/9mmclip1.wav" );
		g_SoundSystem.PrecacheSound( "weapons/357_cock1.wav" );

		g_SoundSystem.PrecacheSound( "weapons/gauss2.wav" );
		g_SoundSystem.PrecacheSound( "weapons/electro4.wav" );
		g_SoundSystem.PrecacheSound( "weapons/electro5.wav" );
		g_SoundSystem.PrecacheSound( "weapons/electro6.wav" );
		g_SoundSystem.PrecacheSound( "ambience/pulsemachine.wav" );

		m_iBalls = g_Game.PrecacheModel( "sprites/hotglow.spr" );
		m_iBeam = g_Game.PrecacheModel( "sprites/smoke.spr" );
	}

	bool GetItemInfo( ItemInfo& out info )
	{
		info.iMaxAmmo1 	= URANIUM_MAX_CARRY;
		info.iMaxAmmo2 	= -1;
		info.iMaxClip 	= WEAPON_NOCLIP;
		info.iSlot 		= 3;
		info.iPosition 	= 9;
		info.iFlags 	= 0;
		info.iWeight 	= HLGAUSS_WEIGHT;

		return true;
	}

	bool AddToPlayer( CBasePlayer@ pPlayer )
	{
		if( BaseClass.AddToPlayer( pPlayer ) )
		{
			NetworkMessage hlgauss( MSG_ONE, NetworkMessages::WeapPickup, pPlayer.edict() );
				hlgauss.WriteLong( self.m_iId );
			hlgauss.End();
			return true;
		}
		
		return false;
	}

	bool Deploy()
	{
		m_flPlayAftershock = 0.0;

		return self.DefaultDeploy( self.GetV_Model( "models/v_gauss.mdl" ), self.GetP_Model( "models/p_gauss.mdl" ), HLGAUSS_DRAW, "gauss" );
	}

	void Holster( int skiplocal /* = 0 */ )
	{
		g_SoundSystem.StopSound( m_pPlayer.edict(), CHAN_WEAPON, "ambience/pulsemachine.wav" );
		self.SendWeaponAnim( HLGAUSS_HOLSTER );
		m_fInAttack = 0;
	}

	float GetFullChargeTime()
	{
		//1.5 in HL DM
		return 4;
	}

	bool bIsMultiplayer()
	{
		return false;
	}

	void PrimaryAttack()
	{
		int ammo = m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType );

		// don't fire underwater
		if( m_pPlayer.pev.waterlevel == WATERLEVEL_HEAD )
		{
			self.PlayEmptySound();
			self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + 0.15f;
			return;
		}

		if( ammo < 2 )
		{
			self.PlayEmptySound();
			self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + 0.15f;
			return;
		}

		m_pPlayer.m_iWeaponVolume = HLGAUSS_PRIMARY_FIRE_VOLUME;
		m_fPrimaryFire = true;

		ammo -= 2;
		m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType, ammo );

		StartFire();
		m_fInAttack = 0;
		self.m_flTimeWeaponIdle = g_Engine.time + 1.0f;
		self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + HLGAUSS_DELAY;
	}

	void SecondaryAttack()
	{
		int ammo = m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType );

		// don't fire underwater
		if( m_pPlayer.pev.waterlevel == WATERLEVEL_HEAD )
		{
			if( m_fInAttack != 0 )
			{
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "weapons/electro4.wav", 1.0f, ATTN_NORM, 0, 80 + Math.RandomLong(0,0x3f) );
				self.SendWeaponAnim( HLGAUSS_IDLE );
				m_fInAttack = 0;
			}
			else
			{
				self.PlayEmptySound();
			}

			self.m_flNextSecondaryAttack = self.m_flNextPrimaryAttack = g_Engine.time + 0.5f;
			return;
		}

		if( m_fInAttack == 0 )
		{
			if( ammo <= 0 )
			{
				g_SoundSystem.EmitSound( m_pPlayer.edict(), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8f, ATTN_NORM );
				self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + 0.5f;
				return;
			}

			m_fPrimaryFire = false;

			--ammo;
			m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType, ammo );// take one ammo just to start the spin
			m_flNextAmmoBurn = g_Engine.time;

			// spin up
			m_pPlayer.m_iWeaponVolume = HLGAUSS_PRIMARY_CHARGE_VOLUME;
			
			self.SendWeaponAnim( HLGAUSS_SPINUP );
			m_fInAttack = 1;
			self.m_flTimeWeaponIdle = g_Engine.time + 0.5f;
			m_flStartCharge = g_Engine.time;
			m_flAmmoStartCharge = g_Engine.time + GetFullChargeTime();

			g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0f, ATTN_NORM, 0, 110 );
			m_iSoundState = SND_CHANGE_PITCH;
		}
		else if( m_fInAttack == 1 )
		{
			if( self.m_flTimeWeaponIdle < g_Engine.time )
			{
				self.SendWeaponAnim( HLGAUSS_SPIN );
				m_fInAttack = 2;
			}
		}
		else
		{
			// during the charging process, eat one bit of ammo every once in a while
			if( g_Engine.time >= m_flNextAmmoBurn && m_flNextAmmoBurn != 1000 )
			{
				if( bIsMultiplayer() )
				{
					--ammo;
					m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType, ammo );
					m_flNextAmmoBurn = g_Engine.time + 0.1f;
				}
				else
				{
					--ammo;
					m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType, ammo );
					m_flNextAmmoBurn = g_Engine.time + 0.3f;
				}
			}

			if( ammo <= 0 )
			{
				// out of ammo! force the gun to fire
				StartFire();
				m_fInAttack = 0;
				self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = self.m_flTimeWeaponIdle = g_Engine.time + 1.0f;
				return;
			}
			
			if( g_Engine.time >= m_flAmmoStartCharge )
			{
				// don't eat any more ammo after gun is fully charged.
				m_flNextAmmoBurn = 1000;
			}

			float pitch = (g_Engine.time - m_flStartCharge ) * ( 150 / GetFullChargeTime()) + 100;

			if( pitch > 250 ) 
				 pitch = 250;
			
			//g_Game.AlertMessage( at_console, "%1 %2 %3\n", m_fInAttack, m_iSoundState, pitch );

			//if( m_iSoundState == 0 )
			//{
				//g_Game.AlertMessage( at_console, "sound state %1\n", m_iSoundState );
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "ambience/pulsemachine.wav", 1.0f, ATTN_NORM, m_iSoundState, int(pitch) );
			//}

			m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions

			m_pPlayer.m_iWeaponVolume = HLGAUSS_PRIMARY_CHARGE_VOLUME;
			
			// self.m_flTimeWeaponIdle = g_Engine.time + 0.1f;
			if( m_flStartCharge < g_Engine.time - 10 )
			{
				// Player charged up too long. Zap him.
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "weapons/electro4.wav", 1.0f, ATTN_NORM, 0, 80 + Math.RandomLong(0, 0x3f) );
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_ITEM, "weapons/electro6.wav", 1.0f, ATTN_NORM, 0, 75 + Math.RandomLong(0, 0x3f) );
				
				m_fInAttack = 0;
				self.m_flTimeWeaponIdle = g_Engine.time + 1.0f;
				self.m_flNextSecondaryAttack = self.m_flNextPrimaryAttack = g_Engine.time + 1.0f;
					
				m_pPlayer.TakeDamage( g_EntityFuncs.Instance(0).pev, g_EntityFuncs.Instance(0).pev, 50, DMG_SHOCK );
				g_PlayerFuncs.ScreenFade( m_pPlayer, Vector(255, 128, 0), 2, 0.5f, 128, FFADE_IN );

				self.SendWeaponAnim( HLGAUSS_IDLE );
				
				// Player may have been killed and this weapon dropped, don't execute any more code after this!
				return;
			}
		}
	}

	//=========================================================
	// StartFire- since all of this code has to run and then 
	// call Fire(), it was easier at this point to rip it out 
	// of weaponidle() and make its own function then to try to
	// merge this into Fire(), which has some identical variable names 
	//=========================================================
	void StartFire()
	{
		float flDamage;
		
		Math.MakeVectors( m_pPlayer.pev.v_angle + m_pPlayer.pev.punchangle );
		Vector vecAiming = g_Engine.v_forward;
		Vector vecSrc = m_pPlayer.GetGunPosition(); // + g_Engine.v_up * -8 + g_Engine.v_right * 8;
		
		if( g_Engine.time - m_flStartCharge > GetFullChargeTime() )
			flDamage = 200;
		else
			flDamage = 200 * (( g_Engine.time - m_flStartCharge) / GetFullChargeTime() );

		if( m_fPrimaryFire )
		{
			// fixed damage on primary attack
			flDamage = SK_PLR_GAUSS;
		}

		if( m_fInAttack != 3 )
		{
			//g_Game.AlertMessage( at_console, "Time:%1 Damage:%2\n", g_Engine.time - m_flStartCharge, flDamage );

			float flZVel = m_pPlayer.pev.velocity.z;

			if( !m_fPrimaryFire )
			{
				m_pPlayer.pev.velocity = m_pPlayer.pev.velocity - g_Engine.v_forward * flDamage * 5;
			}

			if( !bIsMultiplayer() )
			{
				// in deathmatch, gauss can pop you up into the air. Not in single play.
				m_pPlayer.pev.velocity.z = flZVel;
			}

			// player "shoot" animation
			m_pPlayer.SetAnimation( PLAYER_ATTACK1 );
		}

		// time until aftershock 'static discharge' sound
		m_flPlayAftershock = g_Engine.time + g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 0.3f, 0.8f );

		Fire( vecSrc, vecAiming, flDamage );
	}

	void Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
	{
		m_pPlayer.m_iWeaponVolume = HLGAUSS_PRIMARY_FIRE_VOLUME;

		Vector vecSrc = vecOrigSrc;
		Vector vecDest = vecSrc + vecDir * 8192;
		edict_t@ pentIgnore;
		TraceResult tr, beam_tr;
		float flMaxFrac = 1.0f;
		int	nTotal = 0;
		int fHasPunched = 0;
		int fFirstBeam = 1;
		int	nMaxHits = 10;

		@pentIgnore = m_pPlayer.edict();

		g_SoundSystem.StopSound( m_pPlayer.edict(), CHAN_WEAPON, "ambience/pulsemachine.wav" );

		/*g_Game.AlertMessage( at_console, "%1 %2 %3\n%4 %5 %6\n", 
			vecSrc.x, vecSrc.y, vecSrc.z, 
			vecDest.x, vecDest.y, vecDest.z );*/
		

	//	g_Game.AlertMessage( at_console, "%1 &2\n", tr.flFraction, flMaxFrac );
		m_pPlayer.pev.punchangle.x = -2.0f;
		self.SendWeaponAnim( HLGAUSS_FIRE2 );
		g_SoundSystem.PlaySound( m_pPlayer.edict(), CHAN_WEAPON, "weapons/gauss2.wav", 0.5f + flDamage * (1.0 / 400.0f), ATTN_NORM, 0, 85 - Math.RandomLong( 0, 0x1f ) );

		while( flDamage > 10 && nMaxHits > 0 )
		{
			nMaxHits--;

			//g_Game.AlertMessage( at_console, "." );
			g_Utility.TraceLine( vecSrc, vecDest, dont_ignore_monsters, pentIgnore, tr );

			if( tr.fAllSolid != 0 )
				break;

			if( fFirstBeam != 0 )
			{
				m_pPlayer.pev.effects |= EF_MUZZLEFLASH;
				fFirstBeam = 0;

				NetworkMessage gaussbeam( MSG_BROADCAST, NetworkMessages::SVC_TEMPENTITY, tr.vecEndPos );
					gaussbeam.WriteByte( TE_BEAMENTPOINT );
					gaussbeam.WriteShort( m_pPlayer.entindex() + 0x1000 );//start entity
					gaussbeam.WriteCoord( tr.vecEndPos.x );//end position
					gaussbeam.WriteCoord( tr.vecEndPos.y );
					gaussbeam.WriteCoord( tr.vecEndPos.z );
					gaussbeam.WriteShort( g_EngineFuncs.ModelIndex(HLGAUSS_SPRITE_BEAM) );//sprite index
					gaussbeam.WriteByte( 0 );//starting frame
					gaussbeam.WriteByte( 0 );//frame rate
					gaussbeam.WriteByte( 1 );//life in 0.1's
					gaussbeam.WriteByte( m_fPrimaryFire ? 10 : 25 );//line width in 0.1's
					gaussbeam.WriteByte( 0 );//noise amplitude in 0.1's
					gaussbeam.WriteByte( 255 );//red
					gaussbeam.WriteByte( m_fPrimaryFire ? 128 : 255 );//green
					gaussbeam.WriteByte( m_fPrimaryFire ? 0 : 255 );//blue
					gaussbeam.WriteByte( m_fPrimaryFire ? 128 : int(flDamage) );//brightness
					gaussbeam.WriteByte( 0 );//scroll speed
				gaussbeam.End();

				nTotal += 26;
			}
			else
			{
				NetworkMessage gaussbeam( MSG_BROADCAST, NetworkMessages::SVC_TEMPENTITY, null );
					gaussbeam.WriteByte( TE_BEAMPOINTS );
					gaussbeam.WriteCoord( vecSrc.x );//start position
					gaussbeam.WriteCoord( vecSrc.y );
					gaussbeam.WriteCoord( vecSrc.z );
					gaussbeam.WriteCoord( tr.vecEndPos.x );//end position
					gaussbeam.WriteCoord( tr.vecEndPos.y );
					gaussbeam.WriteCoord( tr.vecEndPos.z );
					gaussbeam.WriteShort( g_EngineFuncs.ModelIndex(HLGAUSS_SPRITE_BEAM) );//sprite index
					gaussbeam.WriteByte( 0 );//starting frame
					gaussbeam.WriteByte( 0 );//framerate in 0.1's
					gaussbeam.WriteByte( 1 );//life in 0.1's
					gaussbeam.WriteByte( m_fPrimaryFire ? 10 : 25 );//width in 0.1's
					gaussbeam.WriteByte( 0 );//noise amplitude in 0.1's
					gaussbeam.WriteByte( 255 );//red
					gaussbeam.WriteByte( m_fPrimaryFire ? 128 : 255 );//green
					gaussbeam.WriteByte( m_fPrimaryFire ? 0 : 255 );//blue
					gaussbeam.WriteByte( m_fPrimaryFire ? 128 : int(flDamage) );//brightness
					gaussbeam.WriteByte( 0 );//scroll speed in 0.1's
				gaussbeam.End();
			}

			CBaseEntity@ pEntity = g_EntityFuncs.Instance( tr.pHit );

			if( pEntity is null )
				break;

			if( pEntity.pev.takedamage != DAMAGE_NO )
			{
				g_WeaponFuncs.ClearMultiDamage();
				pEntity.TraceAttack( m_pPlayer.pev, flDamage, vecDir, tr, DMG_BULLET );
				g_WeaponFuncs.ApplyMultiDamage( m_pPlayer.pev, m_pPlayer.pev );
			}

			if( pEntity.ReflectGauss() || pEntity.pev.solid == SOLID_BSP )
			{
				float n;

				@pentIgnore = null;

				n = -DotProduct( tr.vecPlaneNormal, vecDir );

				if( n < 0.5f ) // 60 degrees
				{
					//g_Game.AlertMessage( at_console, "reflect %1\n", n );
					// reflect
					Vector r;

					r = 2.0f * tr.vecPlaneNormal * n + vecDir;
					flMaxFrac = flMaxFrac - tr.flFraction;
					vecDir = r;
					vecSrc = tr.vecEndPos + vecDir * 8;
					vecDest = vecSrc + vecDir * 8192;

					// explode a bit
					iGlowBr = 255;//int( flDamage * n / 255 );

					@m_pGlow = g_EntityFuncs.CreateSprite( "sprites/hotglow.spr", tr.vecEndPos, false ); 
					m_pGlow.SetTransparency( kRenderGlow, 0, 255, 0, int(flDamage * n / 255), kRenderFxNoDissipation ); 
					m_pGlow.SetScale( 0.2f );
					g_Scheduler.SetTimeout( @this, "KillGlow", flDamage * n * 0.5f * 0.1f );

					g_WeaponFuncs.RadiusDamage( tr.vecEndPos, self.pev, m_pPlayer.pev, flDamage * n, (flDamage * n) * 2.5f, CLASS_NONE, DMG_BLAST );

					GaussBalls( tr, (tr.vecEndPos+tr.vecPlaneNormal), 3, 100, 100 );

					nTotal += 34;

					// lose energy
					if( n == 0 ) n = 0.1f;

					flDamage = flDamage * (1 - n);
				}
				else
				{
					// tunnel
					g_WeaponFuncs.DecalGunshot( tr, BULLET_MONSTER_12MM );

					iGlowBr = 255;//int( flDamage / 255 );
					@m_pGlow = g_EntityFuncs.CreateSprite( HLGAUSS_SPRITE_GLOW, tr.vecEndPos, false ); 
					m_pGlow.SetTransparency( kRenderGlow, 0, 255, 0, int(flDamage / 255.0f), kRenderFxNoDissipation ); 
					m_pGlow.SetScale( 1.0f );
					g_Scheduler.SetTimeout( @this, "KillGlow", 6.0f );

					nTotal += 13;

					// limit it to one hole punch
					if( fHasPunched != 0 )
						break;

					fHasPunched = 1;

					// try punching through wall if secondary attack (primary is incapable of breaking through)
					if( !m_fPrimaryFire )
					{
						g_Utility.TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, beam_tr );

						if( beam_tr.fAllSolid == 0 )
						{
							// trace backwards to find exit point
							g_Utility.TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, beam_tr );

							n = (beam_tr.vecEndPos - tr.vecEndPos).Length();

							if( n < flDamage )
							{
								if( n == 0 ) n = 1;

								flDamage -= n;

								// absorption balls
								GaussBalls( tr, (tr.vecEndPos-vecDir), 3, 100, 100 );

								//g_Game.AlertMessage( at_console, "punch %1\n", n );
								nTotal += 21;

								// exit blast damage
								//g_WeaponFuncs.RadiusDamage( beam_tr.vecEndPos + vecDir * 8, self.pev, m_pPlayer.pev, flDamage, CLASS_NONE, DMG_BLAST );
								float damage_radius;
								

								if( bIsMultiplayer() )
								{
									damage_radius = flDamage * 1.75f;  // Old code == 2.5
								}
								else
								{
									damage_radius = flDamage * 2.5f;
								}

								g_WeaponFuncs.RadiusDamage( beam_tr.vecEndPos + vecDir * 8, self.pev, m_pPlayer.pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST );

								//g_SoundSystem.InsertSound( bits_SOUND_COMBAT, self.pev.origin, NORMAL_EXPLOSION_VOLUME, 3.0f, m_pPlayer );

								g_WeaponFuncs.DecalGunshot( beam_tr, BULLET_MONSTER_12MM );

								iGlowBr = 255;//int( flDamage / 255 );
								@m_pGlow = g_EntityFuncs.CreateSprite( HLGAUSS_SPRITE_GLOW, beam_tr.vecEndPos, false ); 
								m_pGlow.SetTransparency( kRenderGlow, 0, 255, 0, int(flDamage / 255.0f), kRenderFxNoDissipation ); 
								m_pGlow.SetScale( 1.0f );
								g_Scheduler.SetTimeout( @this, "KillGlow", 6.0f );

								GaussBalls( beam_tr, (beam_tr.vecEndPos-vecDir), int(flDamage * 0.3f), 200, 40 );

								nTotal += 53;

								vecSrc = beam_tr.vecEndPos + vecDir;
							}
						}
						else
						{
							//g_Game.AlertMessage( at_console, "blocked %1\n", n );
							flDamage = 0;
						}
					}
					else
					{
						//g_Game.AlertMessage( at_console, "blocked solid\n" );

						if( m_fPrimaryFire )
						{
							// slug doesn't punch through ever with primary 
							// fire, so leave a little glowy bit and make some balls
							iGlowBr = 255;//int( 200 / 255 );
							@m_pGlow = g_EntityFuncs.CreateSprite( HLGAUSS_SPRITE_GLOW, beam_tr.vecEndPos, false ); 
							m_pGlow.SetTransparency( kRenderGlow, 0, 255, 0, int(200.0f / 255.0f), kRenderFxNoDissipation ); 
							m_pGlow.SetScale( 0.2f );
							g_Scheduler.SetTimeout( @this, "KillGlow", 0.3f );

							GaussBalls( tr, (tr.vecEndPos+tr.vecPlaneNormal), 8, 100, 200 );
						}

						flDamage = 0;
					}

				}
			}
			else
			{
				vecSrc = tr.vecEndPos + vecDir;
				@pentIgnore = pEntity.edict();
			}
		}

		//g_Game.AlertMessage( at_console, "%1 bytes\n", nTotal );
	}

	void GlowFadeout()
	{
		if( m_pGlow is null ) return;

		m_pGlow.SetBrightness( iGlowBr );

		if( iGlowBr > 0 )
			iGlowBr -= 1;
	}

	void KillGlow()
	{
		if( m_pGlow is null ) return;

		g_EntityFuncs.Remove( m_pGlow );
		@m_pGlow = null;
		
	}

	void GaussBalls( TraceResult &in tr, Vector vecEnd, int count, int amplitude, int velocity )
	{
		NetworkMessage gaussballs( MSG_BROADCAST, NetworkMessages::SVC_TEMPENTITY );
			gaussballs.WriteByte( TE_SPRITETRAIL );
			gaussballs.WriteCoord( tr.vecEndPos.x );//start position
			gaussballs.WriteCoord( tr.vecEndPos.y );
			gaussballs.WriteCoord( tr.vecEndPos.z );
			gaussballs.WriteCoord( vecEnd.x );//end position
			gaussballs.WriteCoord( vecEnd.y );
			gaussballs.WriteCoord( vecEnd.z );
			gaussballs.WriteShort( g_EngineFuncs.ModelIndex(HLGAUSS_SPRITE_BALLS) );//sprite index
			gaussballs.WriteByte( count );//count
			gaussballs.WriteByte( 1 );//life in 0.1's
			gaussballs.WriteByte( Math.RandomLong(1, 2) );//scale in 0.1's
			gaussballs.WriteByte( velocity/25 );//velocity along vector in 10's
			gaussballs.WriteByte( amplitude/25 );//randomness of velocity in 10's
		gaussballs.End();
	}

	void ItemPreFrame()
	{
		if( m_pGlow !is null ) GlowFadeout();
		
		BaseClass.ItemPreFrame();
	}

	void WeaponIdle()
	{
		self.ResetEmptySound();

		// play aftershock static discharge
		if( m_flPlayAftershock > 0 && m_flPlayAftershock < g_Engine.time )
		{
			switch( Math.RandomLong(0, 3) )
			{
				case 0:	g_SoundSystem.EmitSound( m_pPlayer.edict(), CHAN_WEAPON, "weapons/electro4.wav", Math.RandomFloat(0.7f, 0.8f), ATTN_NORM ); break;
				case 1:	g_SoundSystem.EmitSound( m_pPlayer.edict(), CHAN_WEAPON, "weapons/electro5.wav", Math.RandomFloat(0.7f, 0.8f), ATTN_NORM ); break;
				case 2:	g_SoundSystem.EmitSound( m_pPlayer.edict(), CHAN_WEAPON, "weapons/electro6.wav", Math.RandomFloat(0.7f, 0.8f), ATTN_NORM ); break;
				case 3:	break; // no sound
			}

			m_flPlayAftershock = 0.0f;
		}

		if( self.m_flTimeWeaponIdle > g_Engine.time )
			return;

		if( m_fInAttack != 0 )
		{
			StartFire();
			m_fInAttack = 0;
			self.m_flTimeWeaponIdle = g_Engine.time + 2.0f;
		}
		else
		{
			int iAnim;
			float flRand = Math.RandomFloat(0, 1);

			if( flRand <= 0.5f )
			{
				iAnim = HLGAUSS_IDLE;
				self.m_flTimeWeaponIdle = g_Engine.time + g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 10, 15 );
			}
			else if( flRand <= 0.75f )
			{
				iAnim = HLGAUSS_IDLE2;
				self.m_flTimeWeaponIdle = g_Engine.time + g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 10, 15 );
			}
			else
			{
				iAnim = HLGAUSS_FIDGET;
				self.m_flTimeWeaponIdle = g_Engine.time + 3;
			}

			self.SendWeaponAnim( iAnim );
			return;
		}
	}
}

class CGaussAmmo : ScriptBasePlayerAmmoEntity
{
	void Spawn()
	{ 
		Precache();
		g_EntityFuncs.SetModel( self, "models/w_gaussammo.mdl" );
		BaseClass.Spawn();
	}
	
	void Precache()
	{
		g_Game.PrecacheModel( "models/w_gaussammo.mdl" );
		g_SoundSystem.PrecacheSound( "items/9mmclip1.wav" );
	}
	
	bool AddAmmo( CBaseEntity@ pOther ) 
	{ 
		if( pOther.GiveAmmo( HLGAUSS_DEFAULT_GIVE, "hluranium", URANIUM_MAX_CARRY ) != -1)
		{
			g_SoundSystem.EmitSound( self.edict(), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM );
			return true;
		}
		return false;
	}
}

void Register()
{
	g_CustomEntityFuncs.RegisterCustomEntity( "HLGAUSS::CGaussAmmo", "ammo_hlgaussclip" );
	g_CustomEntityFuncs.RegisterCustomEntity( "HLGAUSS::CHLGauss", "weapon_hlgauss" );
	g_ItemRegistry.RegisterWeapon( "weapon_hlgauss", "hl_weapons", "hluranium" );
}

} //namespace HLGAUSS end