text:
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements a grab bag of visual effects entities.
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "effects.h"
#include "gib.h"
#include "beam_shared.h"
#include "decals.h"
#include "func_break.h"
#include "EntityFlame.h"
#include "entitylist.h"
#include "basecombatweapon.h"
#include "model_types.h"
#include "player.h"
#include "physics.h"
#include "baseparticleentity.h"
#include "ndebugoverlay.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "env_wind_shared.h"
#include "filesystem.h"
#include "engine/IEngineSound.h"
#include "fire.h"
#include "te_effect_dispatch.h"
#include "Sprite.h"
#include "precipitation_shared.h"
#include "shot_manipulator.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

#define SF_FUNNEL_REVERSE			1 // funnel effect repels particles instead of attracting them.

#define	SF_GIBSHOOTER_REPEATABLE	(1<<0)	// allows a gibshooter to be refired
#define	SF_SHOOTER_FLAMING			(1<<1)	// gib is on fire
#define SF_SHOOTER_STRICT_REMOVE	(1<<2)	// remove this gib even if it is in the player's view

// UNDONE: This should be client-side and not use TempEnts
class CBubbling : public CBaseEntity
{
public:
	DECLARE_CLASS( CBubbling, CBaseEntity );

	virtual  void	Spawn( void );
	virtual void	Precache( void );

	void	FizzThink( void );

	// Input handlers.
	void	InputActivate( inputdata_t &inputdata );
	void	InputDeactivate( inputdata_t &inputdata );
	void	InputToggle( inputdata_t &inputdata );

	void	InputSetCurrent( inputdata_t &inputdata );
	void	InputSetDensity( inputdata_t &inputdata );
	void	InputSetFrequency( inputdata_t &inputdata );

	DECLARE_DATADESC();

private:

	void TurnOn();
	void TurnOff();
	void Toggle();

	int		m_density;
	int		m_frequency;
	int		m_bubbleModel;
	int		m_state;
};

LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling );

BEGIN_DATADESC( CBubbling )

	DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "current" ),
	DEFINE_KEYFIELD( m_density, FIELD_INTEGER, "density" ),
	DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),

	DEFINE_FIELD( m_state, FIELD_INTEGER ),
	// Let spawn restore this!
	//	DEFINE_FIELD( m_bubbleModel, FIELD_INTEGER ),

	// Function Pointers
	DEFINE_FUNCTION( FizzThink ),

	DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
	DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
	DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
	DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCurrent", InputSetCurrent ),
	DEFINE_INPUTFUNC( FIELD_INTEGER, "SetDensity", InputSetDensity ),
	DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFrequency", InputSetFrequency ),

END_DATADESC()

#define SF_BUBBLES_STARTOFF		0x0001

void CBubbling::Spawn( void )
{
	Precache( );
	SetModel( STRING( GetModelName() ) );		// Set size

	// Make it invisible to client
	SetRenderColorA( 0 );

	SetSolid( SOLID_NONE );						// Remove model & collisions

	if ( !HasSpawnFlags(SF_BUBBLES_STARTOFF) )
	{
		SetThink( &CBubbling::FizzThink );
		SetNextThink( gpGlobals->curtime + 2.0 );
		m_state = 1;
	}
	else
	{
		m_state = 0;
	}
}

void CBubbling::Precache( void )
{
	m_bubbleModel = PrecacheModel("sprites/bubble.vmt");			// Precache bubble sprite
}

void CBubbling::Toggle()
{
	if (!m_state)
	{
		TurnOn();
	}
	else
	{
		TurnOff();
	}
}

void CBubbling::TurnOn()
{
	m_state = 1;
	SetThink( &CBubbling::FizzThink );
	SetNextThink( gpGlobals->curtime + 0.1f );
}

void CBubbling::TurnOff()
{
	m_state = 0;
	SetThink( NULL );
	SetNextThink( TICK_NEVER_THINK );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBubbling::InputActivate( inputdata_t &inputdata )
{
	TurnOn();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBubbling::InputDeactivate( inputdata_t &inputdata )
{
	TurnOff();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBubbling::InputToggle( inputdata_t &inputdata )
{
	Toggle();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
void CBubbling::InputSetCurrent( inputdata_t &inputdata )
{
	m_flSpeed = (float)inputdata.value.Int();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
void CBubbling::InputSetDensity( inputdata_t &inputdata )
{
	m_density = inputdata.value.Int();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
void CBubbling::InputSetFrequency( inputdata_t &inputdata )
{
	m_frequency = inputdata.value.Int();

	// Reset think time
	if ( m_state )
	{
		if ( m_frequency > 19 )
		{
			SetNextThink( gpGlobals->curtime + 0.5f );
		}
		else
		{
			SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
		}
	}
}

void CBubbling::FizzThink( void )
{
	Vector center = WorldSpaceCenter();
	CPASFilter filter( center );
	te->Fizz( filter, 0.0, this, m_bubbleModel, m_density, (int)m_flSpeed );

	if ( m_frequency > 19 )
	{
		SetNextThink( gpGlobals->curtime + 0.5f );
	}
	else
	{
		SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
	}
}

// ENV_TRACER
// Fakes a tracer
class CEnvTracer : public CPointEntity
{
public:
	DECLARE_CLASS( CEnvTracer, CPointEntity );

	void Spawn( void );
	void TracerThink( void );
	void Activate( void );

	DECLARE_DATADESC();

	Vector m_vecEnd;
	float  m_flDelay;
};

LINK_ENTITY_TO_CLASS( env_tracer, CEnvTracer );

BEGIN_DATADESC( CEnvTracer )

	DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),

	DEFINE_FIELD( m_vecEnd, FIELD_POSITION_VECTOR ),

	// Function Pointers
	DEFINE_FUNCTION( TracerThink ),

END_DATADESC()

//-----------------------------------------------------------------------------
// Purpose: Called after keyvalues are parsed.
//-----------------------------------------------------------------------------
void CEnvTracer::Spawn( void )
{
	SetSolid( SOLID_NONE );
	SetMoveType( MOVETYPE_NONE );

	if (!m_flDelay)
		m_flDelay = 1;
}

//-----------------------------------------------------------------------------
// Purpose: Called after all the entities have been loaded.
//-----------------------------------------------------------------------------
void CEnvTracer::Activate( void )
{
	BaseClass::Activate();

	CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_target );
	if (pEnd != NULL)
	{
		m_vecEnd = pEnd->GetLocalOrigin();
		SetThink( &CEnvTracer::TracerThink );
		SetNextThink( gpGlobals->curtime + m_flDelay );
	}
	else
	{
		Msg( "env_tracer: unknown entity \"%s\"\n", STRING(m_target) );
	}
}

// Think
void CEnvTracer::TracerThink( void )
{
	UTIL_Tracer( GetAbsOrigin(), m_vecEnd );

	SetNextThink( gpGlobals->curtime + m_flDelay );
}

//#################################################################################
//  >> CGibShooter
//#################################################################################
enum GibSimulation_t
{
	GIB_SIMULATE_POINT,
	GIB_SIMULATE_PHYSICS,
	GIB_SIMULATE_RAGDOLL,
};

class CGibShooter : public CBaseEntity
{
public:
	DECLARE_CLASS( CGibShooter, CBaseEntity );

	void Spawn( void );
	void Precache( void );
	void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

	virtual CGib *CreateGib( void );

protected:
	// Purpose:
	CBaseEntity *SpawnGib( const Vector &vecShootDir, float flSpeed );

	DECLARE_DATADESC();
private:
	void InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed );
	void ShootThink( void );

protected:
	int		m_iGibs;
	int		m_iGibCapacity;
	int		m_iGibMaterial;
	int		m_iGibModelIndex;
	float	m_flGibVelocity;
	QAngle	m_angGibRotation;
	float	m_flGibAngVelocity;
	float	m_flVariance;
	float	m_flGibLife;
	int		m_nSimulationType;
	int		m_nMaxGibModelFrame;
	float	m_flDelay;

	bool	m_bNoGibShadows;

	bool	m_bIsSprite;
	string_t m_iszLightingOrigin;

	// ----------------
	//	Inputs
	// ----------------
	void InputShoot( inputdata_t &inputdata );
};

BEGIN_DATADESC( CGibShooter )

	DEFINE_KEYFIELD( m_iGibs, FIELD_INTEGER, "m_iGibs" ),
	DEFINE_KEYFIELD( m_flGibVelocity, FIELD_FLOAT, "m_flVelocity" ),
	DEFINE_KEYFIELD( m_flVariance, FIELD_FLOAT, "m_flVariance" ),
	DEFINE_KEYFIELD( m_flGibLife, FIELD_FLOAT, "m_flGibLife" ),
	DEFINE_KEYFIELD( m_nSimulationType, FIELD_INTEGER, "Simulation" ),
	DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),
	DEFINE_KEYFIELD( m_angGibRotation, FIELD_VECTOR, "gibangles" ),
	DEFINE_KEYFIELD( m_flGibAngVelocity, FIELD_FLOAT, "gibanglevelocity"),
	DEFINE_FIELD( m_bIsSprite, FIELD_BOOLEAN ),

	DEFINE_FIELD( m_iGibCapacity, FIELD_INTEGER ),
	DEFINE_FIELD( m_iGibMaterial, FIELD_INTEGER ),
	DEFINE_FIELD( m_iGibModelIndex, FIELD_INTEGER ),
	DEFINE_FIELD( m_nMaxGibModelFrame, FIELD_INTEGER ),

	DEFINE_KEYFIELD( m_iszLightingOrigin, FIELD_STRING, "LightingOrigin" ),
	DEFINE_KEYFIELD( m_bNoGibShadows, FIELD_BOOLEAN, "nogibshadows" ),

	// Inputs
	DEFINE_INPUTFUNC( FIELD_VOID,	"Shoot", InputShoot ),

	// Function Pointers
	DEFINE_FUNCTION( ShootThink ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter );

void CGibShooter::Precache ( void )
{
	if ( g_Language.GetInt() == LANGUAGE_GERMAN )
	{
		m_iGibModelIndex = PrecacheModel ("models/germanygibs.mdl");
	}
	else
	{
		m_iGibModelIndex = PrecacheModel ("models/gibs/hgibs.mdl");
	}
}

void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	SetThink( &CGibShooter::ShootThink );
	SetNextThink( gpGlobals->curtime );
}

//-----------------------------------------------------------------------------
// Purpose: Input handler for shooting gibs.
//-----------------------------------------------------------------------------
void CGibShooter::InputShoot( inputdata_t &inputdata )
{
	SetThink( &CGibShooter::ShootThink );
	SetNextThink( gpGlobals->curtime );
}

void CGibShooter::Spawn( void )
{
	Precache();

	SetSolid( SOLID_NONE );
	AddEffects( EF_NODRAW );

	if ( m_flDelay < 0 )
	{
		m_flDelay = 0.0;
	}

	if ( m_flGibLife == 0 )
	{
		m_flGibLife = 25;
	}

	m_iGibCapacity = m_iGibs;

	m_nMaxGibModelFrame = modelinfo->GetModelFrameCount( modelinfo->GetModel( m_iGibModelIndex ) );
}

CGib *CGibShooter::CreateGib ( void )
{
	ConVarRef violence_hgibs( "violence_hgibs" );
	if ( violence_hgibs.IsValid() && !violence_hgibs.GetInt() )
		return NULL;

	CGib *pGib = CREATE_ENTITY( CGib, "gib" );
	pGib->Spawn( "models/gibs/hgibs.mdl" );
	pGib->SetBloodColor( BLOOD_COLOR_RED );

	if ( m_nMaxGibModelFrame <= 1 )
	{
		DevWarning( 2, "GibShooter Body is <= 1!\n" );
	}

	pGib->m_nBody = random->RandomInt ( 1, m_nMaxGibModelFrame - 1 );// avoid throwing random amounts of the 0th gib. (skull).

	if ( m_iszLightingOrigin != NULL_STRING )
	{
		// Make the gibs use the lighting origin
		pGib->SetLightingOrigin( m_iszLightingOrigin );
	}

	return pGib;
}

void CGibShooter::InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed )
{
	if ( pGib )
	{
		pGib->SetLocalOrigin( GetAbsOrigin() );
		pGib->SetAbsVelocity( vecShootDir * flSpeed );

		QAngle angVel( random->RandomFloat ( 100, 200 ), random->RandomFloat ( 100, 300 ), 0 );
		pGib->SetLocalAngularVelocity( angVel );

		float thinkTime = ( pGib->GetNextThink() - gpGlobals->curtime );

		pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 ));	// +/- 5%

		// HL1 gibs always die after a certain time, other games have to opt-in
#ifndef HL1_DLL
		if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
#endif
		{
			pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
			pGib->SetThink ( &CGib::DieThink );
		}

		if ( pGib->m_lifeTime < thinkTime )
		{
			pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
			pGib->m_lifeTime = 0;
		}

		if ( m_bIsSprite == true )
		{
			pGib->SetSprite( CSprite::SpriteCreate( STRING( GetModelName() ), pGib->GetAbsOrigin(), false ) );

			CSprite *pSprite = (CSprite*)pGib->GetSprite();

			if ( pSprite )
			{
				pSprite->SetAttachment( pGib, 0 );
				pSprite->SetOwnerEntity( pGib );

				pSprite->SetScale( 1 );
				pSprite->SetTransparency( m_nRenderMode, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
				pSprite->AnimateForTime( 5, m_flGibLife + 1 ); //This framerate is totally wrong
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseEntity *CGibShooter::SpawnGib( const Vector &vecShootDir, float flSpeed )
{
	switch (m_nSimulationType)
	{
		case GIB_SIMULATE_RAGDOLL:
		{
			// UNDONE: Assume a mass of 200 for now
			Vector force = vecShootDir * flSpeed * 200;
			return CreateRagGib( STRING( GetModelName() ), GetAbsOrigin(), GetAbsAngles(), force, m_flGibLife );
		}

		case GIB_SIMULATE_PHYSICS:
		{
			CGib *pGib = CreateGib();

			if ( pGib )
			{
				pGib->SetAbsOrigin( GetAbsOrigin() );
				pGib->SetAbsAngles( m_angGibRotation );

				pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 ));	// +/- 5%

				pGib->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
				IPhysicsObject *pPhysicsObject = pGib->VPhysicsInitNormal( SOLID_VPHYSICS, pGib->GetSolidFlags(), false );
				pGib->SetMoveType( MOVETYPE_VPHYSICS );

				if ( pPhysicsObject )
				{
					// Set gib velocity
					Vector vVel		= vecShootDir * flSpeed;
					pPhysicsObject->AddVelocity(&vVel, NULL);

					AngularImpulse torque;
					torque.x = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
					torque.y = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
					torque.z = 0.0f;
					torque *= pPhysicsObject->GetMass();

					pPhysicsObject->ApplyTorqueCenter( torque );

#ifndef HL1_DLL
					if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
#endif
					{
						pGib->m_bForceRemove = true;
						pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
						pGib->SetThink ( &CGib::DieThink );
					}

				}
				else
				{
					InitPointGib( pGib, vecShootDir, flSpeed );
				}
			}
			return pGib;
		}

		case GIB_SIMULATE_POINT:
		{
			CGib *pGib = CreateGib();

			if ( pGib )
			{
				pGib->SetAbsAngles( m_angGibRotation );

				InitPointGib( pGib, vecShootDir, flSpeed );
				return pGib;
			}
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGibShooter::ShootThink ( void )
{
	SetNextThink( gpGlobals->curtime + m_flDelay );

	Vector vecShootDir, vForward,vRight,vUp;
	AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
	vecShootDir = vForward;
	vecShootDir = vecShootDir + vRight * random->RandomFloat( -1, 1) * m_flVariance;
	vecShootDir = vecShootDir + vForward * random->RandomFloat( -1, 1) * m_flVariance;
	vecShootDir = vecShootDir + vUp * random->RandomFloat( -1, 1) * m_flVariance;

	VectorNormalize( vecShootDir );

	SpawnGib( vecShootDir, m_flGibVelocity );

	if ( --m_iGibs <= 0 )
	{
		if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
		{
			m_iGibs = m_iGibCapacity;
			SetThink ( NULL );
			SetNextThink( gpGlobals->curtime );
		}
		else
		{
			SetThink ( &CGibShooter::SUB_Remove );
			SetNextThink( gpGlobals->curtime );
		}
	}
}

class CEnvShooter : public CGibShooter
{
public:
	DECLARE_CLASS( CEnvShooter, CGibShooter );

	CEnvShooter() { m_flGibGravityScale = 1.0f; }
	void		Precache( void );
	bool		KeyValue( const char *szKeyName, const char *szValue );

	CGib		*CreateGib( void );

	DECLARE_DATADESC();

public:

	int m_nSkin;
	float m_flGibScale;
	float m_flGibGravityScale;

#if HL2_EPISODIC
	float m_flMassOverride;	// allow designer to force a mass for gibs in some cases
#endif
};

BEGIN_DATADESC( CEnvShooter )

	DEFINE_KEYFIELD( m_nSkin, FIELD_INTEGER, "skin" ),
	DEFINE_KEYFIELD( m_flGibScale, FIELD_FLOAT ,"scale" ),
	DEFINE_KEYFIELD( m_flGibGravityScale, FIELD_FLOAT, "gibgravityscale" ),

#if HL2_EPISODIC
	DEFINE_KEYFIELD( m_flMassOverride, FIELD_FLOAT, "massoverride" ),
#endif

END_DATADESC()

LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter );

bool CEnvShooter::KeyValue( const char *szKeyName, const char *szValue )
{
	if (FStrEq(szKeyName, "shootmodel"))
	{
		m_bIsSprite = false;
		SetModelName( AllocPooledString(szValue) );

		//Adrian - not pretty...
		if ( Q_stristr( szValue, ".vmt" ) )
			 m_bIsSprite = true;
	}

	else if (FStrEq(szKeyName, "shootsounds"))
	{
		int iNoise = atoi(szValue);
		switch( iNoise )
		{
		case 0:
			m_iGibMaterial = matGlass;
			break;
		case 1:
			m_iGibMaterial = matWood;
			break;
		case 2:
			m_iGibMaterial = matMetal;
			break;
		case 3:
			m_iGibMaterial = matFlesh;
			break;
		case 4:
			m_iGibMaterial = matRocks;
			break;

		default:
		case -1:
			m_iGibMaterial = matNone;
			break;
		}
	}
	else
	{
		return BaseClass::KeyValue( szKeyName, szValue );
	}

	return true;
}

void CEnvShooter::Precache ( void )
{
	m_iGibModelIndex = PrecacheModel( STRING( GetModelName() ) );
}

CGib *CEnvShooter::CreateGib ( void )
{
	CGib *pGib = CREATE_ENTITY( CGib, "gib" );

	if ( m_bIsSprite == true )
	{
		//HACK HACK
		pGib->Spawn( "" );
	}
	else
	{
		pGib->Spawn( STRING( GetModelName() ) );
	}

	int bodyPart = 0;

	if ( m_nMaxGibModelFrame > 1 )
	{
		bodyPart = random->RandomInt( 0, m_nMaxGibModelFrame-1 );
	}

	pGib->m_nBody = bodyPart;
	pGib->SetBloodColor( DONT_BLEED );
	pGib->m_material = m_iGibMaterial;

	pGib->m_nRenderMode = m_nRenderMode;
	pGib->m_clrRender = m_clrRender;
	pGib->m_nRenderFX = m_nRenderFX;
	pGib->m_nSkin = m_nSkin;
	pGib->m_lifeTime = gpGlobals->curtime + m_flGibLife;

	pGib->SetGravity( m_flGibGravityScale );

	// Spawn a flaming gib
	if ( HasSpawnFlags( SF_SHOOTER_FLAMING ) )
	{
		// Tag an entity flame along with us
		CEntityFlame *pFlame = CEntityFlame::Create( pGib, false );
		if ( pFlame != NULL )
		{
			pFlame->SetLifetime( pGib->m_lifeTime );
			pGib->SetFlame( pFlame );
		}
	}

	if ( m_iszLightingOrigin != NULL_STRING )
	{
		// Make the gibs use the lighting origin
		pGib->SetLightingOrigin( m_iszLightingOrigin );
	}

	if( m_bNoGibShadows )
	{
		pGib->AddEffects( EF_NOSHADOW );
	}

#if HL2_EPISODIC
	// if a mass override is set, apply it to the gib
	if (m_flMassOverride != 0)
	{
		IPhysicsObject *pPhys = pGib->VPhysicsGetObject();
		if (pPhys)
		{
			pPhys->SetMass( m_flMassOverride );
		}
	}
#endif

	return pGib;
}

//-----------------------------------------------------------------------------
// An entity that shoots out junk when hit by a rotor wash
//-----------------------------------------------------------------------------
class CRotorWashShooter : public CEnvShooter, public IRotorWashShooter
{
public:
	DECLARE_CLASS( CRotorWashShooter, CEnvShooter );
	DECLARE_DATADESC();

	virtual void Spawn();

public:
	// Inherited from IRotorWashShooter
	virtual CBaseEntity *DoWashPush( float flTimeSincePushStarted, const Vector &vecForce );

private:
	// Amount of time we need to spend under the rotor before we shoot
	float m_flTimeUnderRotor;
	float m_flTimeUnderRotorVariance;

	// Last time we were hit with a wash...
	float m_flLastWashStartTime;
	float m_flNextGibTime;
};

LINK_ENTITY_TO_CLASS( env_rotorshooter, CRotorWashShooter );

//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CRotorWashShooter )

	DEFINE_KEYFIELD( m_flTimeUnderRotor,	FIELD_FLOAT ,"rotortime" ),
	DEFINE_KEYFIELD( m_flTimeUnderRotorVariance,	FIELD_FLOAT ,"rotortimevariance" ),
	DEFINE_FIELD( m_flLastWashStartTime,	FIELD_TIME ),
	DEFINE_FIELD( m_flNextGibTime, FIELD_TIME ),

END_DATADESC()

//-----------------------------------------------------------------------------
// Gets at the interface if the entity supports it
//-----------------------------------------------------------------------------
IRotorWashShooter *GetRotorWashShooter( CBaseEntity *pEntity )
{
	CRotorWashShooter *pShooter = dynamic_cast<CRotorWashShooter*>(pEntity);
	return pShooter;
}

//-----------------------------------------------------------------------------
// Inherited from IRotorWashShooter
//-----------------------------------------------------------------------------
void CRotorWashShooter::Spawn()
{
	BaseClass::Spawn();
	m_flLastWashStartTime = -1;
}

//-----------------------------------------------------------------------------
// Inherited from IRotorWashShooter
//-----------------------------------------------------------------------------
CBaseEntity *CRotorWashShooter::DoWashPush( float flWashStartTime, const Vector &vecForce )
{
	if ( flWashStartTime == m_flLastWashStartTime )
	{
		if ( m_flNextGibTime > gpGlobals->curtime )
			return NULL;
	}

	m_flLastWashStartTime = flWashStartTime;
	m_flNextGibTime	= gpGlobals->curtime + m_flTimeUnderRotor + random->RandomFloat( -1, 1) * m_flTimeUnderRotorVariance;
	if ( m_flNextGibTime <= gpGlobals->curtime )
	{
		m_flNextGibTime = gpGlobals->curtime + 0.01f;
	}

	// Set the velocity to be what the force would cause it to accelerate to
	// after one tick
	Vector vecShootDir = vecForce;
	VectorNormalize( vecShootDir );

	vecShootDir.x += random->RandomFloat( -1, 1 ) * m_flVariance;
	vecShootDir.y += random->RandomFloat( -1, 1 ) * m_flVariance;
	vecShootDir.z += random->RandomFloat( -1, 1 ) * m_flVariance;

	VectorNormalize( vecShootDir );

	CBaseEntity *pGib = SpawnGib( vecShootDir, m_flGibVelocity /*flLength*/ );

	if ( --m_iGibs <= 0 )
	{
		if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
		{
			m_iGibs = m_iGibCapacity;
		}
		else
		{
			SetThink ( &CGibShooter::SUB_Remove );
			SetNextThink( gpGlobals->curtime );
		}
	}

	return pGib;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTestEffect : public CBaseEntity
{
public:
	DECLARE_CLASS( CTestEffect, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );
	// bool	KeyValue( const char *szKeyName, const char *szValue );
	void Think( void );
	void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

	int		m_iLoop;
	int		m_iBeam;
	CBeam	*m_pBeam[24];
	float	m_flBeamTime[24];
	float	m_flStartTime;
};

LINK_ENTITY_TO_CLASS( test_effect, CTestEffect );

void CTestEffect::Spawn( void )
{
	Precache( );
}

void CTestEffect::Precache( void )
{
	PrecacheModel( "sprites/lgtning.vmt" );
}

void CTestEffect::Think( void )
{
	int i;
	float t = (gpGlobals->curtime - m_flStartTime);

	if (m_iBeam < 24)
	{
		CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 10 );

		trace_t	tr;

		Vector vecSrc = GetAbsOrigin();
		Vector vecDir = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
		VectorNormalize( vecDir );
		UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);

		pbeam->PointsInit( vecSrc, tr.endpos );
		// pbeam->SetColor( 80, 100, 255 );
		pbeam->SetColor( 255, 180, 100 );
		pbeam->SetWidth( 10.0 );
		pbeam->SetScrollRate( 12 );

		m_flBeamTime[m_iBeam] = gpGlobals->curtime;
		m_pBeam[m_iBeam] = pbeam;
		m_iBeam++;

#if 0
		Vector vecMid = (vecSrc + tr.endpos) * 0.5;
		CBroadcastRecipientFilter filter;
		TE_DynamicLight( filter, 0.0,
			vecMid, 255, 180, 100, 3, 2.0, 0.0 );
#endif
	}

	if (t < 3.0)
	{
		for (i = 0; i < m_iBeam; i++)
		{
			t = (gpGlobals->curtime - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]);
			m_pBeam[i]->SetBrightness( 255 * t );
			// m_pBeam[i]->SetScrollRate( 20 * t );
		}
		SetNextThink( gpGlobals->curtime + 0.1f );
	}
	else
	{
		for (i = 0; i < m_iBeam; i++)
		{
			UTIL_Remove( m_pBeam[i] );
		}
		m_flStartTime = gpGlobals->curtime;
		m_iBeam = 0;
		SetNextThink( TICK_NEVER_THINK );
	}
}

void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	SetNextThink( gpGlobals->curtime + 0.1f );
	m_flStartTime = gpGlobals->curtime;
}

// Blood effects
class CBlood : public CPointEntity
{
public:
	DECLARE_CLASS( CBlood, CPointEntity );

	void	Spawn( void );
	bool	KeyValue( const char *szKeyName, const char *szValue );

	inline	int		Color( void ) { return m_Color; }
	inline	float 	BloodAmount( void ) { return m_flAmount; }

	inline	void SetColor( int color ) { m_Color = color; }

	// Input handlers
	void InputEmitBlood( inputdata_t &inputdata );

	Vector	Direction( void );
	Vector	BloodPosition( CBaseEntity *pActivator );

	DECLARE_DATADESC();

	Vector m_vecSprayDir;
	float m_flAmount;
	int m_Color;

private:
};

LINK_ENTITY_TO_CLASS( env_blood, CBlood );

BEGIN_DATADESC( CBlood )

	DEFINE_KEYFIELD( m_vecSprayDir, FIELD_VECTOR, "spraydir" ),
	DEFINE_KEYFIELD( m_flAmount, FIELD_FLOAT, "amount" ),
	DEFINE_FIELD( m_Color, FIELD_INTEGER ),

	DEFINE_INPUTFUNC( FIELD_VOID, "EmitBlood", InputEmitBlood ),

END_DATADESC()

#define SF_BLOOD_RANDOM		0x0001
#define SF_BLOOD_STREAM		0x0002
#define SF_BLOOD_PLAYER		0x0004
#define SF_BLOOD_DECAL		0x0008
#define SF_BLOOD_CLOUD		0x0010
#define SF_BLOOD_DROPS		0x0020
#define SF_BLOOD_GORE		0x0040

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBlood::Spawn( void )
{
	// Convert spraydir from angles to a vector
	QAngle angSprayDir = QAngle( m_vecSprayDir.x, m_vecSprayDir.y, m_vecSprayDir.z );
	AngleVectors( angSprayDir, &m_vecSprayDir );

	SetSolid( SOLID_NONE );
	SetMoveType( MOVETYPE_NONE );
	SetColor( BLOOD_COLOR_RED );
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : szKeyName -
//			szValue -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBlood::KeyValue( const char *szKeyName, const char *szValue )
{
	if (FStrEq(szKeyName, "color"))
	{
		int color = atoi(szValue);
		switch ( color )
		{
			case 1:
			{
				SetColor( BLOOD_COLOR_YELLOW );
				break;
			}
		}
	}
	else
	{
		return BaseClass::KeyValue( szKeyName, szValue );
	}

	return true;
}

Vector CBlood::Direction( void )
{
	if ( HasSpawnFlags( SF_BLOOD_RANDOM ) )
		return UTIL_RandomBloodVector();

	return m_vecSprayDir;
}

Vector CBlood::BloodPosition( CBaseEntity *pActivator )
{
	if ( HasSpawnFlags( SF_BLOOD_PLAYER ) )
	{
		CBasePlayer *player;

		if ( pActivator && pActivator->IsPlayer() )
		{
			player = ToBasePlayer( pActivator );
		}
		else
		{
			player = UTIL_GetLocalPlayer();
		}

		if ( player )
		{
			return (player->EyePosition()) + Vector( random->RandomFloat(-10,10), random->RandomFloat(-10,10), random->RandomFloat(-10,10) );
		}
	}

	return GetLocalOrigin();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void UTIL_BloodSpray( const Vector &pos, const Vector &dir, int color, int amount, int flags )
{
	if( color == DONT_BLEED )
		return;

	CEffectData	data;

	data.m_vOrigin = pos;
	data.m_vNormal = dir;
	data.m_flScale = (float)amount;
	data.m_fFlags = flags;
	data.m_nColor = color;

	DispatchEffect( "bloodspray", data );
}

//-----------------------------------------------------------------------------
// Purpose: Input handler for triggering the blood effect.
//-----------------------------------------------------------------------------
void CBlood::InputEmitBlood( inputdata_t &inputdata )
{
	if ( HasSpawnFlags( SF_BLOOD_STREAM ) )
	{
		UTIL_BloodStream( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
	}
	else
	{
		UTIL_BloodDrips( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
	}

	if ( HasSpawnFlags( SF_BLOOD_DECAL ) )
	{
		Vector forward = Direction();
		Vector start = BloodPosition( inputdata.pActivator );
		trace_t tr;

		UTIL_TraceLine( start, start + forward * BloodAmount() * 2, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
		if ( tr.fraction != 1.0 )
		{
			UTIL_BloodDecalTrace( &tr, Color() );
		}
	}

	//
	// New-fangled blood effects.
	//
	if ( HasSpawnFlags( SF_BLOOD_CLOUD | SF_BLOOD_DROPS | SF_BLOOD_GORE ) )
	{
		int nFlags = 0;
		if (HasSpawnFlags(SF_BLOOD_CLOUD))
		{
			nFlags |= FX_BLOODSPRAY_CLOUD;
		}

		if (HasSpawnFlags(SF_BLOOD_DROPS))
		{
			nFlags |= FX_BLOODSPRAY_DROPS;
		}

		if (HasSpawnFlags(SF_BLOOD_GORE))
		{
			nFlags |= FX_BLOODSPRAY_GORE;
		}

		UTIL_BloodSpray(GetAbsOrigin(), Direction(), Color(), BloodAmount(), nFlags);
	}
}

//-----------------------------------------------------------------------------
// Purpose: Console command for emitting the blood spray effect from an NPC.
//-----------------------------------------------------------------------------
void CC_BloodSpray( const CCommand &args )
{
	CBaseEntity *pEnt = NULL;
	while ( ( pEnt = gEntList.FindEntityGeneric( pEnt, args[1] ) ) != NULL )
	{
		Vector forward;
		pEnt->GetVectors(&forward, NULL, NULL);
		UTIL_BloodSpray( (forward * 4 ) + ( pEnt->EyePosition() + pEnt->WorldSpaceCenter() ) * 0.5f, forward, BLOOD_COLOR_RED, 4, FX_BLOODSPRAY_ALL );
	}
}

static ConCommand bloodspray( "bloodspray", CC_BloodSpray, "blood", FCVAR_CHEAT );

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CEnvFunnel : public CBaseEntity
{
	DECLARE_DATADESC();
public:
	DECLARE_CLASS( CEnvFunnel, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );
	void	Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

	int		m_iSprite;	// Don't save, precache
};

LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel );

//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CEnvFunnel )

//	DEFINE_FIELD( m_iSprite,	FIELD_INTEGER ),

END_DATADESC()

void CEnvFunnel::Precache ( void )
{
	m_iSprite = PrecacheModel ( "sprites/flare6.vmt" );
}

void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	CBroadcastRecipientFilter filter;
	te->LargeFunnel( filter, 0.0,
		&GetAbsOrigin(), m_iSprite, HasSpawnFlags( SF_FUNNEL_REVERSE ) ? 1 : 0 );

	SetThink( &CEnvFunnel::SUB_Remove );
	SetNextThink( gpGlobals->curtime );
}

void CEnvFunnel::Spawn( void )
{
	Precache();
	SetSolid( SOLID_NONE );
	AddEffects( EF_NODRAW );
}

//=========================================================
// Beverage Dispenser
// overloaded m_iHealth, is now how many cans remain in the machine.
//=========================================================
class CEnvBeverage : public CBaseEntity
{
public:
	DECLARE_CLASS( CEnvBeverage, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );
	void	Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
	bool	KeyValue( const char *szKeyName, const char *szValue );

	// Input handlers.
	void	InputActivate( inputdata_t &inputdata );

	DECLARE_DATADESC();

public:
	bool	m_CanInDispenser;
	int		m_nBeverageType;
};

void CEnvBeverage::Precache ( void )
{
	PrecacheModel( "models/can.mdl" );
}

BEGIN_DATADESC( CEnvBeverage )
	DEFINE_FIELD( m_CanInDispenser, FIELD_BOOLEAN ),
	DEFINE_FIELD( m_nBeverageType, FIELD_INTEGER ),

	DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
END_DATADESC()

LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage );

bool CEnvBeverage::KeyValue( const char *szKeyName, const char *szValue )
{
	if (FStrEq(szKeyName, "beveragetype"))
	{
		m_nBeverageType = atoi(szValue);
	}
	else
	{
		return BaseClass::KeyValue( szKeyName, szValue );
	}

	return true;
}

void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	if ( m_CanInDispenser || m_iHealth <= 0 )
	{
		// no more cans while one is waiting in the dispenser, or if I'm out of cans.
		return;
	}

	CBaseAnimating *pCan = (CBaseAnimating *)CBaseEntity::Create( "item_sodacan", GetLocalOrigin(), GetLocalAngles(), this );

	if ( m_nBeverageType == 6 )
	{
		// random
		pCan->m_nSkin = random->RandomInt( 0, 5 );
	}
	else
	{
		pCan->m_nSkin = m_nBeverageType;
	}

	m_CanInDispenser = true;
	m_iHealth -= 1;

	//SetThink (SUB_Remove);
	//SetNextThink( gpGlobals->curtime );
}

void CEnvBeverage::InputActivate( inputdata_t &inputdata )
{
	Use( inputdata.pActivator, inputdata.pCaller, USE_ON, 0 );
}

void CEnvBeverage::Spawn( void )
{
	Precache();
	SetSolid( SOLID_NONE );
	AddEffects( EF_NODRAW );
	m_CanInDispenser = false;

	if ( m_iHealth == 0 )
	{
		m_iHealth = 10;
	}
}

//=========================================================
// Soda can
//=========================================================
class CItemSoda : public CBaseAnimating
{
public:
	DECLARE_CLASS( CItemSoda, CBaseAnimating );

	void	Spawn( void );
	void	Precache( void );
	void	CanThink ( void );
	void	CanTouch ( CBaseEntity *pOther );

	DECLARE_DATADESC();
};

BEGIN_DATADESC( CItemSoda )

	// Function Pointers
	DEFINE_FUNCTION( CanThink ),
	DEFINE_FUNCTION( CanTouch ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda );

void CItemSoda::Precache ( void )
{
	PrecacheModel( "models/can.mdl" );

	PrecacheScriptSound( "ItemSoda.Bounce" );
}

void CItemSoda::Spawn( void )
{
	Precache();
	SetSolid( SOLID_NONE );
	SetMoveType( MOVETYPE_FLYGRAVITY );

	SetModel ( "models/can.mdl" );
	UTIL_SetSize ( this, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) );

	SetThink (&CItemSoda::CanThink);
	SetNextThink( gpGlobals->curtime + 0.5f );
}

void CItemSoda::CanThink ( void )
{
	EmitSound( "ItemSoda.Bounce" );

	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_TRIGGER );
	UTIL_SetSize ( this, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) );

	SetThink ( NULL );
	SetTouch ( &CItemSoda::CanTouch );
}

void CItemSoda::CanTouch ( CBaseEntity *pOther )
{
	if ( !pOther->IsPlayer() )
	{
		return;
	}

	// spoit sound here

	pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health.

	if ( GetOwnerEntity() )
	{
		// tell the machine the can was taken
		CEnvBeverage *bev = (CEnvBeverage *)GetOwnerEntity();
		bev->m_CanInDispenser = false;
	}

	AddSolidFlags( FSOLID_NOT_SOLID );
	SetMoveType( MOVETYPE_NONE );
	AddEffects( EF_NODRAW );
	SetTouch ( NULL );
	SetThink ( &CItemSoda::SUB_Remove );
	SetNextThink( gpGlobals->curtime );
}

#ifndef _XBOX
//=========================================================
// func_precipitation - temporary snow solution for first HL2
// technology demo
//=========================================================

LINK_ENTITY_TO_CLASS( func_precipitation, CPrecipitation );

BEGIN_DATADESC( CPrecipitation )
	DEFINE_KEYFIELD( m_nPrecipType, FIELD_INTEGER, "preciptype" ),
END_DATADESC()

// Just send the normal entity crap
IMPLEMENT_SERVERCLASS_ST( CPrecipitation, DT_Precipitation)
	SendPropInt( SENDINFO( m_nPrecipType ), Q_log2( NUM_PRECIPITATION_TYPES ) + 1, SPROP_UNSIGNED )
END_SEND_TABLE()

CPrecipitation::CPrecipitation()
{
	m_nPrecipType = PRECIPITATION_TYPE_RAIN; // default to rain.
}

void CPrecipitation::Spawn( void )
{
	PrecacheMaterial( "effects/fleck_ash1" );
	PrecacheMaterial( "effects/fleck_ash2" );
	PrecacheMaterial( "effects/fleck_ash3" );
	PrecacheMaterial( "effects/ember_swirling001" );

	Precache();
	SetSolid( SOLID_NONE );							// Remove model & collisions
	SetMoveType( MOVETYPE_NONE );
	//SetModel( STRING( GetModelName() ) );		// Set size
	SetModel( STRING( gEntList.FindEntityByClassname(NULL, "trigger_PenaltyBox")->GetModelName() ) );		// Set size

	// Default to rain.
	if ( m_nPrecipType < 0 || m_nPrecipType > NUM_PRECIPITATION_TYPES )
		m_nPrecipType = PRECIPITATION_TYPE_RAIN;

	m_nRenderMode = kRenderEnvironmental;
}

void CPrecipitation::SetType(PrecipitationType_t type)
{
	m_nPrecipType = type;
}

#endif

//-----------------------------------------------------------------------------
// EnvWind - global wind info
//-----------------------------------------------------------------------------
class CEnvWind : public CBaseEntity
{
public:
	DECLARE_CLASS( CEnvWind, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );
	void	WindThink( void );
	int		UpdateTransmitState( void );

	DECLARE_DATADESC();
	DECLARE_SERVERCLASS();

private:
#ifdef _LINUX
	CEnvWindShared m_EnvWindShared; // FIXME - fails to compile as networked var due to operator= problem
#else
	CNetworkVarEmbedded( CEnvWindShared, m_EnvWindShared );
#endif
};

LINK_ENTITY_TO_CLASS( env_wind, CEnvWind );

BEGIN_DATADESC( CEnvWind )

	DEFINE_KEYFIELD( m_EnvWindShared.m_iMinWind, FIELD_INTEGER, "minwind" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxWind, FIELD_INTEGER, "maxwind" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_iMinGust, FIELD_INTEGER, "mingust" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxGust, FIELD_INTEGER, "maxgust" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_flMinGustDelay, FIELD_FLOAT, "mingustdelay" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_flMaxGustDelay, FIELD_FLOAT, "maxgustdelay" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_iGustDirChange, FIELD_INTEGER, "gustdirchange" ),
	DEFINE_KEYFIELD( m_EnvWindShared.m_flGustDuration, FIELD_FLOAT, "gustduration" ),
//	DEFINE_KEYFIELD( m_EnvWindShared.m_iszGustSound, FIELD_STRING, "gustsound" ),

// Just here to quiet down classcheck
	// DEFINE_FIELD( m_EnvWindShared, CEnvWindShared ),

	DEFINE_FIELD( m_EnvWindShared.m_iWindDir, FIELD_INTEGER ),
	DEFINE_FIELD( m_EnvWindShared.m_flWindSpeed, FIELD_FLOAT ),

	DEFINE_OUTPUT( m_EnvWindShared.m_OnGustStart, "OnGustStart" ),
	DEFINE_OUTPUT( m_EnvWindShared.m_OnGustEnd,	"OnGustEnd" ),

	// Function Pointers
	DEFINE_FUNCTION( WindThink ),

END_DATADESC()

BEGIN_SEND_TABLE_NOBASE(CEnvWindShared, DT_EnvWindShared)
	// These are parameters that are used to generate the entire motion
	SendPropInt		(SENDINFO(m_iMinWind),		10, SPROP_UNSIGNED ),
	SendPropInt		(SENDINFO(m_iMaxWind),		10, SPROP_UNSIGNED ),
	SendPropInt		(SENDINFO(m_iMinGust),		10, SPROP_UNSIGNED ),
	SendPropInt		(SENDINFO(m_iMaxGust),		10, SPROP_UNSIGNED ),
	SendPropFloat	(SENDINFO(m_flMinGustDelay), 0, SPROP_NOSCALE),		// NOTE: Have to do this, so it's *exactly* the same on client
	SendPropFloat	(SENDINFO(m_flMaxGustDelay), 0, SPROP_NOSCALE),
	SendPropInt		(SENDINFO(m_iGustDirChange), 9, SPROP_UNSIGNED ),
	SendPropInt		(SENDINFO(m_iWindSeed),		32, SPROP_UNSIGNED ),

	// These are related to initial state
	SendPropInt		(SENDINFO(m_iInitialWindDir),9, SPROP_UNSIGNED ),
	SendPropFloat	(SENDINFO(m_flInitialWindSpeed),0, SPROP_NOSCALE ),
	SendPropFloat	(SENDINFO(m_flStartTime),	 0, SPROP_NOSCALE ),

	SendPropFloat	(SENDINFO(m_flGustDuration), 0, SPROP_NOSCALE),
	// Sound related
//	SendPropInt		(SENDINFO(m_iszGustSound),	10, SPROP_UNSIGNED ),
END_SEND_TABLE()

// This table encodes the CBaseEntity data.
IMPLEMENT_SERVERCLASS_ST_NOBASE(CEnvWind, DT_EnvWind)
	SendPropDataTable(SENDINFO_DT(m_EnvWindShared), &REFERENCE_SEND_TABLE(DT_EnvWindShared)),
END_SEND_TABLE()

void CEnvWind::Precache ( void )
{
//	if (m_iszGustSound)
//	{
//		PrecacheScriptSound( STRING( m_iszGustSound ) );
//	}
}

void CEnvWind::Spawn( void )
{
	Precache();
	SetSolid( SOLID_NONE );
	AddEffects( EF_NODRAW );

	m_EnvWindShared.Init( entindex(), 0, gpGlobals->frametime, GetLocalAngles().y, 0 );

	SetThink( &CEnvWind::WindThink );
	SetNextThink( gpGlobals->curtime );
}

int CEnvWind::UpdateTransmitState()
{
	return SetTransmitState( FL_EDICT_ALWAYS );
}

void CEnvWind::WindThink( void )
{
	SetNextThink( m_EnvWindShared.WindThink( gpGlobals->curtime ) );
}

//==================================================
// CEmbers
//==================================================

#define	bitsSF_EMBERS_START_ON	0x00000001
#define	bitsSF_EMBERS_TOGGLE	0x00000002

// UNDONE: This is a brush effect-in-volume entity, move client side.
class CEmbers : public CBaseEntity
{
public:
	DECLARE_CLASS( CEmbers, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );

	void	EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

	CNetworkVar( int, m_nDensity );
	CNetworkVar( int, m_nLifetime );
	CNetworkVar( int, m_nSpeed );

	CNetworkVar( bool, m_bEmit );

	DECLARE_DATADESC();
	DECLARE_SERVERCLASS();
};

LINK_ENTITY_TO_CLASS( env_embers, CEmbers );

//Data description
BEGIN_DATADESC( CEmbers )

	DEFINE_KEYFIELD( m_nDensity,	FIELD_INTEGER, "density" ),
	DEFINE_KEYFIELD( m_nLifetime,	FIELD_INTEGER, "lifetime" ),
	DEFINE_KEYFIELD( m_nSpeed,		FIELD_INTEGER, "speed" ),

	DEFINE_FIELD( m_bEmit,	FIELD_BOOLEAN ),

	//Function pointers
	DEFINE_FUNCTION( EmberUse ),

END_DATADESC()

//Data table
IMPLEMENT_SERVERCLASS_ST( CEmbers, DT_Embers )
	SendPropInt(	SENDINFO( m_nDensity ),		32,	SPROP_UNSIGNED ),
	SendPropInt(	SENDINFO( m_nLifetime ),	32,	SPROP_UNSIGNED ),
	SendPropInt(	SENDINFO( m_nSpeed ),		32,	SPROP_UNSIGNED ),
	SendPropInt(	SENDINFO( m_bEmit ),		2,	SPROP_UNSIGNED ),
END_SEND_TABLE()

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEmbers::Spawn( void )
{
	Precache();
	SetModel( STRING( GetModelName() ) );

	SetSolid( SOLID_NONE );
	SetRenderColorA( 0 );
	m_nRenderMode	= kRenderTransTexture;

	SetUse( &CEmbers::EmberUse );

	//Start off if we're targetted (unless flagged)
	m_bEmit = ( HasSpawnFlags( bitsSF_EMBERS_START_ON ) || ( !GetEntityName() ) );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEmbers::Precache( void )
{
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : *pActivator -
//			*pCaller -
//			useType -
//			value -
//-----------------------------------------------------------------------------
void CEmbers::EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	//If we're not toggable, only allow one use
	if ( !HasSpawnFlags( bitsSF_EMBERS_TOGGLE ) )
	{
		SetUse( NULL );
	}

	//Handle it
	switch ( useType )
	{
	case USE_OFF:
		m_bEmit = false;
		break;

	case USE_ON:
		m_bEmit = true;
		break;

	case USE_SET:
		m_bEmit = !!(int)value;
		break;

	default:
	case USE_TOGGLE:
		m_bEmit = !m_bEmit;
		break;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CPhysicsWire : public CBaseEntity
{
public:
	DECLARE_CLASS( CPhysicsWire, CBaseEntity );

	void	Spawn( void );
	void	Precache( void );

	DECLARE_DATADESC();

protected:

	bool SetupPhysics( void );

	int		m_nDensity;
};

LINK_ENTITY_TO_CLASS( env_physwire, CPhysicsWire );

BEGIN_DATADESC( CPhysicsWire )

	DEFINE_KEYFIELD( m_nDensity,	FIELD_INTEGER, "Density" ),
//	DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),

//	DEFINE_FIELD( m_flFoo, FIELD_FLOAT ),

	// Function Pointers
//	DEFINE_FUNCTION( WireThink ),

END_DATADESC()

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPhysicsWire::Spawn( void )
{
	BaseClass::Spawn();

	Precache();

//	if ( SetupPhysics() == false )
//		return;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPhysicsWire::Precache( void )
{
	BaseClass::Precache();
}

class CPhysBallSocket;

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CPhysicsWire::SetupPhysics( void )
{
/*
	CPointEntity	*anchorEnt, *freeEnt;
	CPhysBallSocket *socket;

	char	anchorName[256];
	char	freeName[256];

	int		iAnchorName, iFreeName;

	anchorEnt = (CPointEntity *) CreateEntityByName( "info_target" );

	if ( anchorEnt == NULL )
		return false;

	//Create and connect all segments
	for ( int i = 0; i < m_nDensity; i++ )
	{
		// Create other end of our link
		freeEnt = (CPointEntity *) CreateEntityByName( "info_target" );

		// Create a ballsocket and attach the two
		//socket = (CPhysBallSocket *) CreateEntityByName( "phys_ballsocket" );

		Q_snprintf( anchorName,sizeof(anchorName), "__PWIREANCHOR%d", i );
		Q_snprintf( freeName,sizeof(freeName), "__PWIREFREE%d", i+1 );

		iAnchorName = MAKE_STRING( anchorName );
		iFreeName	= MAKE_STRING( freeName );

		//Fake the names
		//socket->m_nameAttach1 = anchorEnt->m_iGlobalname	= iAnchorName;
		//socket->m_nameAttach2 = freeEnt->m_iGlobalname	= iFreeName

		//socket->Activate();

		//The free ent is now the anchor for the next link
		anchorEnt = freeEnt;
	}
*/

	return true;
}

//
// Muzzle flash
//

class CEnvMuzzleFlash : public CPointEntity
{
	DECLARE_CLASS( CEnvMuzzleFlash, CPointEntity );

public:
	virtual void Spawn();

	// Input handlers
	void	InputFire( inputdata_t &inputdata );

	DECLARE_DATADESC();

	float	m_flScale;
	string_t m_iszParentAttachment;
};

BEGIN_DATADESC( CEnvMuzzleFlash )

	DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
	DEFINE_KEYFIELD( m_iszParentAttachment, FIELD_STRING, "parentattachment" ),

	DEFINE_INPUTFUNC( FIELD_VOID, "Fire", InputFire ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( env_muzzleflash, CEnvMuzzleFlash );

//-----------------------------------------------------------------------------
// Spawn!
//-----------------------------------------------------------------------------
void CEnvMuzzleFlash::Spawn()
{
	if ( (m_iszParentAttachment != NULL_STRING) && GetParent() && GetParent()->GetBaseAnimating() )
	{
		CBaseAnimating *pAnim = GetParent()->GetBaseAnimating();
		int nParentAttachment = pAnim->LookupAttachment( STRING(m_iszParentAttachment) );
		if ( nParentAttachment != 0 )
		{
			SetParent( GetParent(), nParentAttachment );
			SetLocalOrigin( vec3_origin );
			SetLocalAngles( vec3_angle );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMuzzleFlash::InputFire( inputdata_t &inputdata )
{
	g_pEffects->MuzzleFlash( GetAbsOrigin(), GetAbsAngles(), m_flScale, MUZZLEFLASH_TYPE_DEFAULT );
}

//=========================================================
// Splash!
//=========================================================
#define SF_ENVSPLASH_FINDWATERSURFACE	0x00000001
#define SF_ENVSPLASH_DIMINISH			0x00000002
class CEnvSplash : public CPointEntity
{
	DECLARE_CLASS( CEnvSplash, CPointEntity );

public:
	// Input handlers
	void	InputSplash( inputdata_t &inputdata );

protected:

	float	m_flScale;

	DECLARE_DATADESC();
};

BEGIN_DATADESC( CEnvSplash )
	DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),

	DEFINE_INPUTFUNC( FIELD_VOID, "Splash", InputSplash ),
END_DATADESC()

LINK_ENTITY_TO_CLASS( env_splash, CEnvSplash );

//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
#define SPLASH_MAX_DEPTH	120.0f
void CEnvSplash::InputSplash( inputdata_t &inputdata )
{
	CEffectData	data;

	data.m_fFlags = 0;

	float scale = m_flScale;

	if( HasSpawnFlags( SF_ENVSPLASH_FINDWATERSURFACE ) )
	{
		if( UTIL_PointContents(GetAbsOrigin()) & MASK_WATER )
		{
			// No splash if I'm supposed to find the surface of the water, but I'm underwater.
			return;
		}

		// Trace down and find the water's surface. This is designed for making
		// splashes on the surface of water that can change water level.
		trace_t tr;
		UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 4096 ), (MASK_WATER|MASK_SOLID_BRUSHONLY), this, COLLISION_GROUP_NONE, &tr );
		data.m_vOrigin = tr.endpos;

		if ( tr.contents & CONTENTS_SLIME )
		{
			data.m_fFlags |= FX_WATER_IN_SLIME;
		}
	}
	else
	{
		data.m_vOrigin = GetAbsOrigin();
	}

	if( HasSpawnFlags( SF_ENVSPLASH_DIMINISH ) )
	{
		// Get smaller if I'm in deeper water.
		float depth = 0.0f;

		trace_t tr;
		UTIL_TraceLine( data.m_vOrigin, data.m_vOrigin - Vector( 0, 0, 4096 ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );

		depth = fabs( tr.startpos.z - tr.endpos.z );

		float factor = 1.0f - (depth / SPLASH_MAX_DEPTH);

		if( factor < 0.1 )
		{
			// Don't bother making one this small.
			return;
		}

		scale *= factor;
	}

	data.m_vNormal = Vector( 0, 0, 1 );
	data.m_flScale = scale;

	DispatchEffect( "watersplash", data );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class CEnvGunfire : public CPointEntity
{
public:
	DECLARE_CLASS( CEnvGunfire, CPointEntity );

	CEnvGunfire()
	{
		// !!!HACKHACK
		// These fields came along kind of late, so they get
		// initialized in the constructor for now. (sjb)
		m_flBias = 1.0f;
		m_bCollide = false;
	}

	void Precache();
	void Spawn();
	void Activate();
	void StartShooting();
	void StopShooting();
	void ShootThink();
	void UpdateTarget();

	void InputEnable( inputdata_t &inputdata );
	void InputDisable( inputdata_t &inputdata );

	int	m_iMinBurstSize;
	int m_iMaxBurstSize;

	float m_flMinBurstDelay;
	float m_flMaxBurstDelay;

	float m_flRateOfFire;

	string_t	m_iszShootSound;
	string_t	m_iszTracerType;

	bool m_bDisabled;

	int	m_iShotsRemaining;

	int		m_iSpread;
	Vector	m_vecSpread;
	Vector	m_vecTargetPosition;
	float	m_flTargetDist;

	float	m_flBias;
	bool	m_bCollide;

	EHANDLE m_hTarget;

	DECLARE_DATADESC();
};

BEGIN_DATADESC( CEnvGunfire )
	DEFINE_KEYFIELD( m_iMinBurstSize, FIELD_INTEGER, "minburstsize" ),
	DEFINE_KEYFIELD( m_iMaxBurstSize, FIELD_INTEGER, "maxburstsize" ),
	DEFINE_KEYFIELD( m_flMinBurstDelay, FIELD_TIME, "minburstdelay" ),
	DEFINE_KEYFIELD( m_flMaxBurstDelay, FIELD_TIME, "maxburstdelay" ),
	DEFINE_KEYFIELD( m_flRateOfFire, FIELD_FLOAT, "rateoffire" ),
	DEFINE_KEYFIELD( m_iszShootSound, FIELD_STRING, "shootsound" ),
	DEFINE_KEYFIELD( m_iszTracerType, FIELD_STRING, "tracertype" ),
	DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "startdisabled" ),
	DEFINE_KEYFIELD( m_iSpread, FIELD_INTEGER, "spread" ),
	DEFINE_KEYFIELD( m_flBias, FIELD_FLOAT, "bias" ),
	DEFINE_KEYFIELD( m_bCollide, FIELD_BOOLEAN, "collisions" ),

	DEFINE_FIELD( m_iShotsRemaining, FIELD_INTEGER ),
	DEFINE_FIELD( m_vecSpread, FIELD_VECTOR ),
	DEFINE_FIELD( m_vecTargetPosition, FIELD_VECTOR ),
	DEFINE_FIELD( m_flTargetDist, FIELD_FLOAT ),

	DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),

	DEFINE_THINKFUNC( ShootThink ),

	DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
	DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_gunfire, CEnvGunfire );

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::Precache()
{
	PrecacheScriptSound( STRING( m_iszShootSound ) );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::Spawn()
{
	Precache();

	m_iShotsRemaining = 0;
	m_flRateOfFire = 1.0f / m_flRateOfFire;

	switch( m_iSpread )
	{
	case 1:
		m_vecSpread = VECTOR_CONE_1DEGREES;
		break;
	case 5:
		m_vecSpread = VECTOR_CONE_5DEGREES;
		break;
	case 10:
		m_vecSpread = VECTOR_CONE_10DEGREES;
		break;
	case 15:
		m_vecSpread = VECTOR_CONE_15DEGREES;
		break;

	default:
		m_vecSpread = vec3_origin;
		break;
	}

	if( !m_bDisabled )
	{
		StartShooting();
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::Activate( void )
{
	// Find my target
	if (m_target != NULL_STRING)
	{
		m_hTarget = gEntList.FindEntityByName( NULL, m_target );
	}

	BaseClass::Activate();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::StartShooting()
{
	m_iShotsRemaining = random->RandomInt( m_iMinBurstSize, m_iMaxBurstSize );

	SetThink( &CEnvGunfire::ShootThink );
	SetNextThink( gpGlobals->curtime );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::UpdateTarget()
{
	if( m_hTarget )
	{
		if( m_hTarget->WorldSpaceCenter() != m_vecTargetPosition )
		{
			// Target has moved.
			// Locate my target and cache the position and distance.
			m_vecTargetPosition = m_hTarget->WorldSpaceCenter();
			m_flTargetDist = (GetAbsOrigin() - m_vecTargetPosition).Length();
		}
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::StopShooting()
{
	SetThink( NULL );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::ShootThink()
{
	if( !m_hTarget )
	{
		StopShooting();
	}

	SetNextThink( gpGlobals->curtime + m_flRateOfFire );

	UpdateTarget();

	Vector vecDir = m_vecTargetPosition - GetAbsOrigin();
	VectorNormalize( vecDir );

	CShotManipulator manipulator( vecDir );

	vecDir = manipulator.ApplySpread( m_vecSpread, m_flBias );

	Vector vecEnd;

	if( m_bCollide )
	{
		trace_t tr;

		UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecDir * 8192, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );

		if( tr.fraction != 1.0 )
		{
			DoImpactEffect( tr, DMG_BULLET );
		}

		vecEnd = tr.endpos;
	}
	else
	{
		vecEnd = GetAbsOrigin() + vecDir * m_flTargetDist;
	}

	if( m_iszTracerType != NULL_STRING )
	{
		UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true, STRING(m_iszTracerType) );
	}
	else
	{
		UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true );
	}

	EmitSound( STRING(m_iszShootSound) );

	m_iShotsRemaining--;

	if( m_iShotsRemaining == 0 )
	{
		StartShooting();
		SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinBurstDelay, m_flMaxBurstDelay ) );
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::InputEnable( inputdata_t &inputdata )
{
	m_bDisabled = false;
	StartShooting();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvGunfire::InputDisable( inputdata_t &inputdata )
{
	m_bDisabled = true;
	SetThink( NULL );
}

//-----------------------------------------------------------------------------
// Quadratic spline beam effect
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEnvQuadraticBeam )
	DEFINE_FIELD( m_targetPosition, FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( m_controlPosition, FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( m_scrollRate, FIELD_FLOAT ),
	DEFINE_FIELD( m_flWidth, FIELD_FLOAT ),
END_DATADESC()

LINK_ENTITY_TO_CLASS( env_quadraticbeam, CEnvQuadraticBeam );

IMPLEMENT_SERVERCLASS_ST( CEnvQuadraticBeam, DT_QuadraticBeam )
	SendPropVector(SENDINFO(m_targetPosition), -1, SPROP_COORD),
	SendPropVector(SENDINFO(m_controlPosition), -1, SPROP_COORD),
	SendPropFloat(SENDINFO(m_scrollRate), 8, 0, -4, 4),
	SendPropFloat(SENDINFO(m_flWidth), -1, SPROP_NOSCALE),
END_SEND_TABLE()

void CEnvQuadraticBeam::Spawn()
{
	BaseClass::Spawn();
	m_nRenderMode = kRenderTransAdd;
	SetRenderColor( 255, 255, 255 );
}

CEnvQuadraticBeam *CreateQuadraticBeam( const char *pSpriteName, const Vector &start, const Vector &control, const Vector &end, float width, CBaseEntity *pOwner )
{
	CEnvQuadraticBeam *pBeam = (CEnvQuadraticBeam *)CBaseEntity::Create( "env_quadraticbeam", start, vec3_angle, pOwner );
	UTIL_SetModel( pBeam, pSpriteName );
	pBeam->SetSpline( control, end );
	pBeam->SetScrollRate( 0.0 );
	pBeam->SetWidth(width);
	return pBeam;
}

void EffectsPrecache( void *pUser )
{
	CBaseEntity::PrecacheScriptSound( "Underwater.BulletImpact" );

	CBaseEntity::PrecacheScriptSound( "FX_RicochetSound.Ricochet" );

	CBaseEntity::PrecacheScriptSound( "Physics.WaterSplash" );
	CBaseEntity::PrecacheScriptSound( "BaseExplosionEffect.Sound" );
	CBaseEntity::PrecacheScriptSound( "Splash.SplashSound" );

	if ( gpGlobals->maxClients > 1 )
	{
		CBaseEntity::PrecacheScriptSound( "HudChat.Message" );
	}
}

PRECACHE_REGISTER_FN( EffectsPrecache );

class CEnvViewPunch : public CPointEntity
{
public:

	DECLARE_CLASS( CEnvViewPunch, CPointEntity );

	virtual void Spawn();

	// Input handlers
	void InputViewPunch( inputdata_t &inputdata );

private:

	float m_flRadius;
	QAngle m_angViewPunch;

	void DoViewPunch();

	DECLARE_DATADESC();
};

LINK_ENTITY_TO_CLASS( env_viewpunch, CEnvViewPunch );

BEGIN_DATADESC( CEnvViewPunch )

	DEFINE_KEYFIELD( m_angViewPunch, FIELD_VECTOR, "punchangle" ),
	DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),

	DEFINE_INPUTFUNC( FIELD_VOID, "ViewPunch", InputViewPunch ),

END_DATADESC()

#define SF_PUNCH_EVERYONE	0x0001		// Don't check radius
#define SF_PUNCH_IN_AIR		0x0002		// Punch players in air

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvViewPunch::Spawn( void )
{
	SetSolid( SOLID_NONE );
	SetMoveType( MOVETYPE_NONE );

	if ( GetSpawnFlags() & SF_PUNCH_EVERYONE )
	{
		m_flRadius = 0;
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvViewPunch::DoViewPunch()
{
	bool bAir = (GetSpawnFlags() & SF_PUNCH_IN_AIR) ? true : false;
	UTIL_ViewPunch( GetAbsOrigin(), m_angViewPunch, m_flRadius, bAir );
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvViewPunch::InputViewPunch( inputdata_t &inputdata )
{
	DoViewPunch();
}


text:
Home » Culture/Society, Women's Issues » Gender Bias In Manipuri Society —A Reappraisal—
Gender Bias In Manipuri Society —A Reappraisal—
Posted by Editor on Friday, May 13, 2011 9:47 am // No Comment
The lofty height of idealism on "Equality" as enshrined in the Preamble to the Constitution of India is a manifestation of anti-climax of inequality which has been in existence in the traditional Indian society. Equality being the cardinal value of the Constitution of India as against the background of elaborate values and clearly perceived inequalities to secure justice, social, economic, and political to all its citizens has to be the premise wherefrom the same could be achieved. Despite equality in economic, political, religious, social and cultural institutions, these are by and large controlled by men.
We already know that before the low status accorded to women in traditional Indian society which was relatively reflected in its laws the Constitution guarantees "equality before the law and equal protection of laws" and prohibition of discrimination on the ground of sex in their favor. But these provisions by themselves can hardly be expected to usher in the desired social change said Shivaramyya (B Shivaramayya, "Inequalities And The Law, Eastern Book Company, Lucknow, 1984, p.64). Thus notwithstanding considerable body of legislation enacted to prevent women's exploitation, and to remove discrimination against them, women suffer disabilities in many spheres, and continue to be victims of exploitation.
Mira (Mira Seth: Women And Development, Sage Publications, Thousand Oaks, London, N. Delhi, 2001, p.17) was emphatic in saying that it is an interesting reflection on women's status in the Vedic age that women would remain unmarried and remain Brahma vadini devoted to the pursuit of knowledge and self-realization or marry young men. Normally, women married after brahmacharya (a life of celibacy till the age of 25). Young men and even not so young men could convert their romantic friendships into marriage. Marriage, according to the Rigveda was based on truth and duty. It had a spiritual connotation which meant to strengthen the social aspect, the mind, life-breath and body of the couple. Bible also defines the same in the like manner (i) Corinthian 7:1-16; (ii) Hebrew 13:4). In society, marriage is regarded as a noble institution – it creates its bonding and is a strong social commitment. A woman was to be considered as a symbol of good fortune in the husband's home.
It is vital for a woman's health and life that she has access to medical and health care needs for preventive, as well as curative health, so as to be able to play her full part in the development of her family, society and country.
In our society, particularly that of Manipur, there has always been recognized the need for special consideration for women in its traditional health sciences. In ancient times it was Maiba or maibi, puithem, rishis or sages who composed the medical treatises. Among one of such treatises is Charak Samhita, believed to have been composed in the 5th Century BC (Mira Seth: Ibid, p.157). It contains special sections on women's health and how to treat their medical problems. The Susruta Samhita supposed to have been composed in the 4th Century BC and the Kashyap Samhita of 2nd and 3rd Century BC (Ibid) also contain remedies for the treatment-specific ailments. The Unani system of medicine came to India along with the Muslims after the first millennium (Ibid). These systems of medicine have been available for centuries in most villages of India through hereditary vaidyas and hakims that were generally a family. The social, economic and political status of the Indian women apart from other factors set up is also governed by her past resulting justice for female to remain a dream and a far cry all these years of our democratic even an honest young man striving for a job finds that bribery plays a far more decisive role than merit in competition for recruitment to public services (Rising Corruption, Low Convictions by U.C. Agrawal – South Asia Politics, edited by Dr. Subash C. Kashyap Vol.I, Issue-4, K-316/4, IInd Floor, Lado Sarai, N. Delhi – 30, August, 2002, p.13).
Generally women constitute the marginalized section in our society. Within them tribal women are more exploited and remain further marginalized notwithstanding the community-based affirmative action provided by the action and the rhetoric of empowerment for women on a more general plane, tribal women constitute to remain at the margins and denied of effective participation in different domains of society. Within the traditional system, they do not have representation or voice in village or clan councils. While the subjugation is rooted in patriarchy it is sanctified by custom and reinforced by the state, says 'Tiplut Nongbri' (The Marginalization of Women in Tradition and Policy presented by Tiplut Nongbri, Director, NEISP, JNU, New Delhi, at the National Seminar on Women in Traditional Institution and Worldviews, organized by NEISP, JNU, New Delhi, CMS, MU, Imphal and CSSEIP, MU, Imphal sponsored by ICSSR (NERC), Shillong at Manipur University, Canchipur on March 13-15, 2009). This is reflected in the manner in which issues that affect their interest rarely receive adequate attention to address the problems faced by them in the community (ibid).
The development of a Nation cannot only be measured through the technological and materialistic advances but through the quality of life the people live. The growth of a nation lies in its capacity to elevate the lot of the weakest section of its society. Pandit Jawaharlal Nehru had rightly said:
"The status of women indicates the character of country".
Again a famous Chinese saying goes like this:
"If you want to plan for a year, plant wheat, if you wish to plan for ten years grow trees but if you want to plan for 100 years educate young women".
Indian Women's status has seen many ups and downs since the ancient Vedic times to the present day. During the early Vedic period, girls were welcome in a family; they were given education; their age of marriage was after maturation and they could select the male of their own choice for marriage through the tradition of "Swayamvar". They had independence for taking part in decision making, enjoyed power and participated in social, economic and political, cultural and literacy activities. They had control over finances, agriculture and general activities, (Mira Seth: Ibid, p.17). This Vedic and past Vedic periods in history, can also be called a golden era (Laxmi Devi (ed) Women And Development Institute For Sustainable Development, Lucknow, Anmol Publications Pvt. Ltd., New Delhi-92; p.172). However, in the later Vedic Brahmanic period status of women started declining slowly, varied by the code, as given by Manu. According to P.N. Tikoo "In Manu Samhita, ideas about womanhood are laid down and morality is assigned in authoritarian codes which bring down to the level of sub-species" (Indian Women: A Brief Socio-cultural Survey (1985), B.R. Publication Corp, Delhi).
However, now, there are several number of international human rights instruments which provide protection to women and girls and require States to take effective measures to prevent and eradicate gender based violence. At the international level:
(i) the International Covenant on Civil and Political Rights;
(ii) the International Covenant on Economic, Social and Cultural Rights;
(iii) the Convention on the Elimination of All Former of Discrimination Against Women;
(iv) the Convention on the Rights of the Child;
(v) the Convention against Torture and the Declaration on the Elimination of Violence Against Women.
To go in detail, say, for the Committee on Elimination of All Forms of Discrimination Against Women (CEDAW) had already adopted general recommendation no. 10 on different types of violence against women. Therein, the Committee suggested to State parties that, in reviewing their laws and politics, and in reporting under the convention, they should have regard to a number of recommendations related to violence against women. To cite a few of such as by the 172nd report of the Law Commission of India made not only a few recommendations including, substitution of the word "rape" by "sexual assault to make law more comprehensive; making the law gender-neutral by substitution of "woman" with "person".
The Government of India and Manipur have brought-forth many amendments in law to give women an equal right and status—a full ministry of social and women's welfare has been formed in 1985 and now followed by the inception of the National and State Women Human Rights Commissions, yet women are still facing some of the most heinous crimes committed against them, such as rape, flesh trade, feticide, female infanticide, child abuse, wife beating, dowry death, sati, financial exploitation, sexual exploitation of working women and female students. Law is there to prevent all this, yet we find women oppressed, exploited, cheated, uneducated, financially dependent, mentally hoisted, morally run down and physically violated. A country where socio-economic growth cannot take place if half of its population is downtrodden it becomes rather difficult for women to participate effectively and make an indelible mark upon the society, yet they make every effort to better their social condition and contribute in whatever little big or small way in their respective societies.
According to Rahul Rai (Human Rights and Fundamental Freedoms, Athorspress, Laxmi Nagar, Delhi-92, 2004; p.41) other concerns include, inter alia the exploitation of woman and girl in prostitution and interstate and cross-border trafficking and their exposure to HIV/AIDs and health risks; the very high maternal and infant mortality rates, the adverse sex ratio and the incidence of sex-selective abortions despite the law banning that practice, the sex selective targeting of family planning only at women, the law participation of qualified women in the administration and the judiciary, including family courts and Lok Adalats or conciliation tribunals the practice of debt bondage and the denial of inheritance right in land. He (Ibid; p.49) has further maintained that gender relations framework is a useful conceptual approach to the structural inequalities that characterize the relationship between men and women in their day-to-day activities and expressions. Rather than dwelling purely on the male/female sexual differences, the gender relations approach here refers to the substantive issues arising from structurally perceived and socially constructed role expectations and differences in diverse social setting.
EDUCATION OF WOMEN:
To bring a change in the mindset of masses, certainly, education is the only weapon by which social trend is made to a twist steadily or suddenly. We cannot depend solely on women, male participation is considerably essential, without male's support, not much can be achieved. Moreover, the specific constraints and restraints that prevent women's access to education and reduce the possibility of their completing it have to be connected to enable them to those who have been traditionally excluded from contended Bhattacharya (P. Krishnaprasad (ed), Women And Society, Student Struggle, Vol.31, Issue 2 February, 2002, SFI-II, Windsor Place N. Delhi-1; p.5). Also, we need to register the presence of women in our society and also to break feminine stereotypes through texts so as to start from the grass-root levels.
Accessing women to education Black Shield (A.R. Blackshield's Paper "Secularism and Social Control" in the Indian Law Institute, Delhi's Seminar, 1989) has also affirmatively asserted that education, for its part must continue to be processed of thoroughgoing objectivity and realism. The idea of wholehearted objective devotion to a job, the need for thoroughness and precision and depth of understanding in basic and advanced skills; an ever-ready willingness to experiment and explore the constant drive to "make good" rather than "make do" but the ability to measure success in terms of quality rather than quantity, whether of handicrafts, agricultural and industrial products, books, or academic degrees, an absolute respect for truth even (when need be) at the cost of courtesy; a fundamental appreciation of the importance of every human individual, and of the seriousness and worthwhileness and intrinsic interest of A "thing-techniques" from handloom weaving to atom-splitting, and of objective factual knowledge generally—all of these must be instilled in the pupils above all the manifest and not stumble example of the teacher. It is an empirical fact that he or she is a human engineer.
Thus, law, religion and education are the best social controls prevalent in any society (Ibid). It is distinctly seen how the educated women in a very conservative society for instance Saudi Arabia have brought a tremendous change especially in the course of women's lives (Jean P. Sasson : Princess, Doubleday Transworld Publishing Ltd., Berks, U.K., 1992; p.163). As a matter of fact, women, now, in Saudi have held the post of Education Director and portfolio of Education Minister.
Inadequate educational opportunities given to girls due to preference for boys doing better is leading to poorer income-generation opportunities for girls and women. Many women are in the informal small-scale sector where credit facilities are more difficult to procure, while the economic risks are higher, with poor potential for expansion. There are many cultural and social hurdles for girls and women to overcome mainly due to gender biases, with girls and women being under-represented in educational institutions.
Sustainable development must meet the needs of both female and male gender to ensure visibility and equity of both genders. This is realizable through a development process untried with an ideology that ensures participation, ownership and distribution of resources between women and men. (Rahul Rai: Ibid; p.48).
It is also relevant to observe what Amar was emphatic and very clearly perceived that earlier, sustainability used to be confined only to environmental related issues but today, the term has acquired broader meanings. It has to be practiced not only in case of environment but in the case of social, economic and political variables as well (Development Sustained, But What Does That Mean : Amar Yumnam—Imphal Free Press, 6.3.2011).
A sustainable society is one where individuals have the opportunity to grow without discrimination and there is possibility of collective glory. With the rise of democracy the necessity of enlarging the scope for individual advancement is being increasingly appreciated (Ibid). Indeed, economic status is very important which can be earned due to control over economic access and power, it is examined through the distribution of economic power i.e. whether the female household head is an earner or dependant, their holding of tangible asserts, nature of inheritance of ancestral property and nature of job opportunities in which women are involved as against their male counterpart (P.M. Gangte: Women of North East in Present Context, Maxford Books, Delhi – 2011; p.184). Considering the tribal women, they are primary gatherer of forest resources to meet household needs; they collect vegetables of different varieties from the wild, non-timber forest products and wood for fuel. Depletion of these resources, therefore, has a direct impact on woman likely increasing them workload and drudgery. It also has a direct impact on the overall livelihood of the people who depend on forest resources not only for their own use but also as a crucial source of family income (Ibid, p.234). We know that (90-95) % of vendors in tribal set ups are women. Women look after the management, cultivation, harvesting and processing of the crops, although men sometimes help bring the produce to the local market. It will be interesting to observe as is maintained by Sujata (Sujata D. Hazarika : Democracy And Leadership : The Gendered Voice in Politics, Vol.57, Number 3, Sept-Dec, 2008, Indian Sociological Society, Delhi; p.362) that traditional institutions and customary laws prevalent among women though portrayed an egalitarian socio economic structure, is discriminatory when it comes to women's rights in traditional governance. Women folk in this society have yet a long way of struggle to go to achieve the desired goal of upliftment and empowerment. Moreover, when we deeply look at the status of Meitei women we feel that though liberated and omnipotent, they still need social security and more human treatments at the hands of male partners (P.M. Gangte : Customary Laws of Meitei And Mizo Societies, Akansha Publishing House, New Delhi-2, 2008; p.337).
Women's lower rates of literacy, school attendance, access to education and participation in trainings as well as innovative gender stereotype programs marginalize them in the public sphere and affect their awareness of their legal rights, such as the equal right to own and inherit land. Women from some advantaged or disadvantaged ethnic groups are also likely to drop out of school earlier because of pregnancy, child-bearing, marriage and domestic responsibilities. Lack of education on reproductive health, health and medical care, drinking water, electricity, food safety sanitation, balanced diet mass awareness and environmental and bio-diversity and its consequences keeps them captured to illiteracy and poverty.
According to Gangte, (Dispensation of Justice and Conceptualization of the Ethics of Equality to the Empowerment of Women—Priyadarshni M Gangte—The Sangai Express, dt.23.1.2011) in Meitei society, women can be categorized into three groups—(i) educated and employed; (ii) educated and unemployed; and (iii) uneducated i.e. illiterate. The last group comprises the largest number which comes out openly fighting against social issue apart from their usual income and activities of earning even bread-earnings.
We know that literacy has been identified as an important factor in women's emancipation. The impacts of educational expansion as well as Constitutional and legal provisions have made a great impact mostly in the urban centers. Presently, a greater number of women are entering high school, university and professional colleges. They believe that an educated woman is an asset to her home and family. Women who are educated and socialized in school and college develop individuation and autonomy in values and ideologies of the total number of educated women an infinitely small percentage are employed. Employment of educated to middle class women of rural areas who belong to the lower economic classes. Lack of work for the male member, drunkenness among them and economic constraints drive the Manipuri women to seek remunerative work outside their homes. On the other hand, educated women seek and secure employment in white collar jobs. A working woman's role as bread-earner, however, cannot be considered in isolation. Her income gives the family a higher status. The role of the educated earning women is a little different from that of the educated unemployed woman. She has to perform dual duties and face a crisis of adjustment. She has multifaceted commitments. It is, however, accepted that a woman's earning mean an economic gain. Thus, a woman is a wife, friend, companion and consultant to her husband, not merely a daughter, daughter-in-law, mother, mother-n-law. She takes upon herself the task of educating, instructing and guiding her children. The task and the impact are immense.
Gender Bias and Poverty
Gender bias in its various forms prevents hundreds of millions of women from obtaining education, health services, child care and legal status needed to escape from poverty. Most of the women's activity takes place in the non-wage economy for household consumption, producing food crops, gathering firewood and collecting fodder. Although women toil longer, and contribute more to the family income than male family members they are viewed as "unproductive in government statistics, Jodi Jacobson (a researcher at the World watch Institute) asserts that gender bias is also the single most important cause of rapid population growth. Relating to it, Laxmi (Laxmi Devi: Women And Development: Anmol Publications Pvt. Ltd., New Delhi-2; p.329) has maintained that where women have little access to productive resources and little control over family income, they depend on children for social status and security. Chinglen (Chinglen Maisnam, Assistant Professor, Department of Economics, Manipur University, Canchipur—Interviewed on 7.3.2011). has firmly believed in the policy of male oriented Government of India by uttering:
"Though India follows the high growth trajectories, India's growth has remained dividend and inequitable. The current model of growth leads to widening gender gap".
In the transitional phase, the position of woman is slowly changing. If a daughter is educated, the father is more prepared to counsel with her than with his illiterate wife. Education alone will enhance the position of women in India. They have the advantage of an infrastructure of a legal executive machinery working for their equality. Education faster autonomy, individuation and rationality in women. These make them companion for their husbands (Laxmi: Ibid; p.147).
Employed women also increased the class mobility of the family. However, a word of caution is necessary. A majority of our women are illiterate. The benefits that are limited to a group of highly educated women society is then in a transitory phase since a majority of rural and urban women are still bound by the shackles of a tradition which gives them a lower status than men. The male psyche is such that they cannot visualize their wives being more educated or earning more money. I am inclined like Laxmi to propagate the idea that unless an attitudinal change occurs, the position of women is bound to be inferior. (Ibid.)
Thus, education is the major factor in enhancing the position of women in any society.
And, to cite an instance, of course, during illness fewer women than men seek and receive treatment.
There is a gender asymmetry in utilization of health services. Early and forced marriages, young motherhood continue and malnutrition anemia and higher morbidity persists. As a result young adolescent girls who discontinue their education and vocational training are denied to information about their bodies, thereby constituting a life cycle of deprivation and discrimination resulting in a continuous of health related vulnerabilities for women and young girls (Tingneichong G, Kipgen: Women's Role in the 20th Century, Manipur, Kalpaz Publication, Delhi-52, 2010, p.157). This ill conceived mechanism must undergo a drastic change.
Media is very important tool in the hand of upper class, upper caste men to propagate class and gender ideology. From films and television to magazines, newspaper, radio, and even internet, the portrayal of women is stereotypical and distorted. Messages about male superiority and female inferiority are repeated and insisted constantly; violence against women is rampant, especially in films. As with other sectors, women are highly under-represented in the media, professionally and biases in reporting, coverage, advertising and messaging are generally very sexist (Kamla Bhasin: What is Patriarchy? Kali for Women, A-36 Gulmohar Park, N. Delhi-49, 1993; p.11) and one sided.
It is empirical fact that print and mass media need to show the presence of women at par with men because masses of even rural areas have some access to the same in raising awareness in all spheres for upliftment among women. Needless to say, media is torch bearer and mirror of any civilized society.
Abducting a woman to marry
As I am a person belonging to weaker section of society, I would like to highlight about the unexposed social deprivation which is one of the social institutions of marriages, i.e. abduction or kidnapping of woman to marry her which is an age old practice which is still prevalent in some parts of the state. It refers to the non-consensual kidnapping, which involves a young man and accomplices taking a girls or woman by deception or force, often kept overnight and sometimes raped, to extract consent to marriage. The victim is threatened not only physically but also mentally by the shame of no longer being a virgin or pure woman.
As per Touthang's version (Sholun Touthang, 40 years Chief of Berea Village, Churachandpur District, Manipur, interviewed on 23.10.2010) forms of non-consensual kidnapping will raise ethical concerns among the people such audacious and violent practice of non consensual kidnapping and coercing woman to submit and accept the marriage cannot be a 'tradition' of our society. Any act of outraging the modesty of woman is tantamount to violation of human rights and is of course, illegal too.
Christianity, Islam and Hinduism do not condone a forced marriage (abducted without valid consent of both people). In other words, freely given consent of both parties is a prerequisite of Christian, Hindu and Muslim marriages. Such marriage should be rejected by societies that uphold human rights and legal marriage on the fact that forced marriage negates freedom of matrimonial consent.
It is pertinent to note positively that love is one of the foundations of marriage. (in some religion) "Marriage shall be entered into only with the free and full consent of the intending spouses". (Universal Declaration of Human Rights, Article 16(2). Secondly, "A woman's right to choose a spouse and enter freely into marriage is central to her life and her dignity and equality as a human being" (UN Convention on the Elimination of All Forms of Discrimination Against Women).
A holistic perspective to the development of women
Poverty is a consequence, as well as a cause of several factors that limit life. In order to overcome such acute social problem, it is imperative to take up certain strategies that will respond to yield decisive social benefits such as the life cycle, the girls' education, food, security, safer environment in the home and neighborhood, vocational training, support services to save time and energy, income and employment opportunity, safe motherhood, breast feeding and proper weaning, immunity against childhood diseases, management of common illness like diarrhea and respiratory infection, growth promotion and early childhood stimulation as educational foundation leading to full and equal participation in socio-economic life (Laxmi : Ibid, p.110). These may not cover women in specifically difficult circumstances such refugees and migrants, prostitutes and victims of atrocities, the mentally and physically handicapped etc. however, for the majority of women, especially the rural poor, including tribals, an integrated and decentralized approach to planning is envisaged. The plan ultimately perceives maintaining as a long-term goal, thus, it is need of the hour to recognize holistic approach.
Voluntary Organization and Others
The scope of functions of the voluntary organization in uplifting the status of women is very wide. But unfortunately they have not realized the potentialities that they have as pressure groups. The public has also become so dependent on the government for the solution of even those problems which can be tackled by the people themselves. It is high time that the people should realize the development of society mainly depends on the efforts of its people and merely government. (Ibid: p.340).
The voluntarily organizations have to make sincere efforts to re-establish themselves as powerful agencies to fight the deep rooted social ills of the society for which they need commuted and dedicated workers. The message has to be taken door to door. The change has to come from within and not without (ibid) which will be more lasting and meaningful.
It is firm conviction that unless the voluntary organizations take an active part in the movement of liberation of women, merely governmental agencies cannot achieve the desired results. It is the women themselves who have to liberate themselves from the clutches of the old, orthodox, traditions and customs of the society. This social revolution should be led by the voluntary organization (Ibid). It is said that education liberates and so education must be exploited to gain wisdom and live a better life – a quality life rather than a deceptive and low graded life style benefit of education and skills which may demean one's life. Women's role needs to be redefined again and again.
We have known from the preceding paragraphs how females have had sufferings due to the compelling situations arising from the social, economic, cultural religious and political conditions or ideologies of the past. Insecurities of all sorts arose for females particularly from that of economic activities are resorted in this prevailing environment. Thus, it is high time to think and materialize ones share's due to others. If all the fallout continue what will be the future?
It is, therefore, civil societies, NGO's, Intellectual groups, and all the States should take remedial measure to abolish and of course, the Government's role to introduce certain parameter relating to kidnapping of girls/women so that the youths (boys) should learn to respect girls which will be the only way that people be socially enlightened. Thus a deeply oriented additional policy is the need of the hour especially in Manipur – the Jewel of India.
*The article is written by Priyadarshni M Gangte, PhD
*The writer is a Lecturer, Damdei Christian College, Taloulong, Senapati District, Manipur.
Tags: gender bias, manipuri society, Vedic period

redpajama_set_name: RedPajamaCommonCrawl


text:
Alternate History Discussion: Before 1900
Best pod for a independent Ireland 1500-1800
Thread starter cjc
cjc
As it says on the tin what would be the best pod for a independent irland from 1500-1800.
Analytical Engine
Define "independent".
Von Tyrconnell
An Irish victory at the Battle of Kinsale. Prior to the battle much of Ireland was under the control of the rebels and England's coffers were nearing bankruptcy, however the Irish defeat saw the decline of Hugh O'Neill's prestige among the lords of Ireland (leading to their pulling out of the war or defection to the English) and the end of Spanish efforts to land troops in Ireland. Even at the beginning of the battle the English general Mountjoy despaired, exclaiming that "this kingdom is lost today."
An Irish victory would see the influx of Spanish troops into Ireland and the advances the English had made in Munster over the prior year reversed as the majority of the minor lords of Ireland would shift their alliegances to Hugh O'Neill and his confederation in order to back the winning side.
Lalli
Only way I can see is much stronger French support for Ireland at some point. Otherwise not any chances.
Send Napoleon to Ireland during the Irish Revolution.
Raferty
An independent Ireland as in ruled by a family member of the King of England, sure. Make the pre-1798 Kingdom of Ireland more formally independent, even if it remains an English satrapy. That is all very doable.
If you want some kind of native Celtic elite to govern and for any English presence to be gone, that's not happening.
Raferty said:
The Nine Years' War (the 1593-1603 one) was an opportunity for exactly that though with some better luck for the Irish side. Any TL which brings about a stronger Spanish or French navy could also see a naval invasion of Ireland, OTL in 1627 the Spanish proposed an invasion of Ireland to establish an Irish republic under Spanish protection, but the plan was scrapped after a full-scale Anglo-Spanish war failed to arise.
Von Tyrconnell said:
Do you have any more details on this pod, was there any point in the battle that with a little luck could have turned it to a Irish victory?
cjc said:
The English army besieging Kinsale was in bad shape by the time O'Neill and O'Donnell's armies arrived (whose position to the north of the English effectively besieged the besiegers), having lost about half of their men to cold, disease and desertion, but due to fear the Spanish force holding Kinsale would surrender, the Irish launched an attempted attack on the English at night in order to link up with the Spanish.
This went horrifically wrong due to the Irish armies becoming lost in the dark and lightning giving away their position, allowing Mountjoy's army to ambush and pick off the tired Irish armies one by one. The celebrations of the English were then mistaken for the Irish arriving by the Spanish who rode out of Kinsale only to realise the Irish had already been defeated after suffering casualties, surrendering ten days later.
Basically better luck and/or discipline on the part of the Irish, choosing a less stormy night to launch an attack, or opting to wait for nature to either starve the English out or force them to launch a breakout offensive could dramatically change Irish history.
Atterdag
Could the high kings of Ireland, like the Kings of Scotland, have invited Normans to settle there so that even if the Kingdom becomes Norman-dominated it remains independent of England?
Mechadogzilla
Strongly agree with this, and I'm surprised to see people dismiss the idea Ireland could attain independence pre-Flight of the Earls.
I think you might be projecting English rule in the 1800s onto English rule in the 1500s. Despite the best efforts of the Tudors, before the Nine Years War and start of the Plantation System the vast majority of the island was ruled by native Gaelic Lords. The English only held direct control over the Loyal Provinces (more or less the land around Dublin). Most of the native lords payed lip service to the English throne while privately rebuking them. The Excommunication of Elizabeth I meant any religious obligations of her Catholic subjects to respect her rule were nullified.
Rebellions and plots were common in this period, and they were often funded by the Papacy or Spanish crown. All you need for an Independent Ireland is for a rebellion to succeed, and for someone else to be offered the crown of Ireland (And Phillip II and III were both offered the crown more than once).
As posited by Von Tyrconnell, a good PoD here is the battle of Kinsale.
What would be the effects of an independent Ireland after a victory at Kinsale, and what would said country look like? I imagine the Spanish would be delighted, to say the least.
Could the English colonization of North America be delayed?
I would've been surprised if they genuinely wanted a Republic rather than either a native raised to Kingship or a Spanish Royal Family member, or maybe some kind of English Catholic pretender (not sure if one existed at this point, the Plantagenets were gone). Republics were not in vogue at the time outside of Italy, after all.
As for the 9 Years War, it did put a challenge to English rule but to my knowledge their issues were more about projecting power out from their fortified areas and not the risk of being driven from Ireland. They also had enough naval power to make more attempts if need be. The plantation being done in wartime would have been tough, but I'm not sure it couldn't be done. England had the manpower to keep trying again and again
The reason a Republic was proposed was to prevent fighting between the O'Neill and O'Donnell families over whose lineage would be King.
The Nine Years' War saw England's control thoroughout most of Ireland rolled back (and Mountjoy's comment suggests that for the English, Ireland as a kingdom was at sake), though as you suggest the Pale would be trickier to take, O'Neill had attempted to appeal to the Palesmen on the grounds of their common Catholicism but most remained loyal to England. One of the reasons the Irish sought Spanish troops was the need for artillery in order to take walled towns.
Given the troubles the English had during the Nine Years' War despite their advantages, a consolidated Irish kingdom with Spanish backing would be much trickier to subjugate, and would also mean that England would be forced to invest more resources into its army and less on their navy than they did OTL. At a certain point England would likely be forced to accept Irish independence as a fait accompli as the Spanish had Portugal and the Netherlands and find it more worthwhile to try to pry the Irish out of the Spanish sphere via diplomatic means over the more costly task of trying to annex the island.
A Spanish armada successful landing in Britain.
Spanish Armada - Wikipedia
or a successful French landing in Ireland in 1796
French expedition to Ireland (1796) - Wikipedia