The Ghastleybriar Zoo Incident - A.I. Header
#ifndef NPC_ZOO_ANIMAL_H
#define NPC_ZOO_ANIMAL_H

#include "cbase.h"
#include "AI_BaseNPC.h"
#include "ai_baseactor.h"
#include "props.h" // DELETE ME
#include "Sprite.h"

// This class need NOT be removed immediately. It may have a use later if the 
// the NPC needs to check distances against other entities other than the Player

const int ZOO_ANIMAL_BOX_COLLISION		= 0;
const int ZOO_ANIMAL_SPHERICAL_COLLISION        = 1;
const int ZOO_ANIMAL_CYLINDERICAL_COLLISION     = 2;

class CZooAnimal_ProxTester
{
public:
	CZooAnimal_ProxTester()
		: m_distSq( 0 ),
		m_fInside( false )
	{
	}

	void Init( float dist )
	{
		m_fInside = ( dist > 0 );
		m_distSq = dist * dist;
	}

	bool Check( CBaseEntity *pEntity1, CBaseEntity *pEntity2 )
	{
		if ( m_distSq != 0 )
		{
			float distSq = ( pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin() ).LengthSqr();
			bool fInside = ( distSq < m_distSq );

			return ( m_fInside == fInside );
		}
		return true;
	}

	bool Check( CBaseEntity *pEntity1, CBaseEntity *pEntity2, float dist )
	{
		m_fInside = ( dist > 0 );
		m_distSq = dist * dist;

		if ( m_distSq != 0 )
		{
			float distSq = ( pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin() ).LengthSqr();
			bool fInside = ( distSq < m_distSq );

			return ( m_fInside == fInside );
		}
		return true;
	}

	bool Check( CBaseEntity *pEntity1, float offset1, Vector v1, 
							CBaseEntity *pEntity2, float offset2, Vector v2, float dist )
	{
		m_fInside = ( dist > 0 );
		m_distSq = dist * dist;

		if ( m_distSq != 0 )
		{
			const Vector &offsetV1 = pEntity1->GetAbsOrigin() + ( offset1 * v1 );
			const Vector &offsetV2 = pEntity2->GetAbsOrigin() + ( offset2 * v2 );

			float distSq = ( offsetV1 - offsetV2 ).LengthSqr();
			bool fInside = ( distSq < m_distSq );

			return ( m_fInside == fInside );
		}
		return true;
	}

	bool Check( CBaseEntity *pEntity1, Vector offset1, Vector dirV1, 
							CBaseEntity *pEntity2, Vector offset2, Vector dirV2, 
							Vector dist, int collisionType )
	{
		if ( dist.x >= 0 && dist.y >= 0 && dist.z >=0 )
		{
			// Offset the direction vector by a given amount in x,y,z

			dirV1 *= offset1.x;
			dirV1 *= offset1.y;
			dirV1 *= offset1.z;

			dirV2 *= offset2.x;
			dirV2 *= offset2.y;
			dirV2 *= offset2.z;

			const Vector &offsetV1 = pEntity1->GetAbsOrigin() + dirV1;
			const Vector &offsetV2 = pEntity2->GetAbsOrigin() + dirV2;

			switch ( collisionType )
			{
				case ZOO_ANIMAL_BOX_COLLISION:
					bool xCheck, yCheck, zCheck;

					xCheck = ( ( offsetV1.x - offsetV2.x )*( offsetV1.x - offsetV2.x ) <= ( dist.x * dist.x ) ) ? true : false;
					yCheck = ( ( offsetV1.y - offsetV2.y )*( offsetV1.y - offsetV2.y ) <= ( dist.y * dist.y ) ) ? true : false;
					zCheck = ( ( offsetV1.z - offsetV2.z )*( offsetV1.z - offsetV2.z ) <= ( dist.z * dist.z ) ) ? true : false;

					return ( xCheck && yCheck && zCheck );
				case ZOO_ANIMAL_SPHERICAL_COLLISION:
					float xComp, yComp, zComp;

					xComp = 1;
					yComp = 1;
					zComp = 1;

					xComp = ( ( offsetV1.x - offsetV2.x )*( offsetV1.x - offsetV2.x ) ) / ( dist.x * dist.x );
					yComp = ( ( offsetV1.y - offsetV2.y )*( offsetV1.y - offsetV2.y ) ) / ( dist.y * dist.y );
					zComp = ( ( offsetV1.z - offsetV2.z )*( offsetV1.z - offsetV2.z ) ) / ( dist.z * dist.z );

					return ( ( xComp + yComp + zComp ) <= 1 );
				case ZOO_ANIMAL_CYLINDERICAL_COLLISION:
					return false;
			}
		}
		return false;
	}
	DECLARE_SIMPLE_DATADESC();

private:

	float m_distSq;
	bool  m_fInside;
};

const int ZOO_ANIMAL_MAX_AI_PATH_TYPES			= 4;
const int ZOO_ANIMAL_MAX_AI_PATHS			= 4;
const int ZOO_ANIMAL_MAX_ICONS				= 6;
const int ZOO_ANIMAL_MAX_AI_TIMERS			= 15;
const int ZOO_ANIMAL_MAX_AI_RANGES			= 11;
const int ZOO_ANIMAL_MAX_AI_DAMAGES			= 2;
const int ZOO_ANIMAL_MAX_AI_SOUNDS			= 5;
const int ZOO_ANINAL_MAX_AI_MELEE_ATTACK_ACTIVITY	= 2;
const int ZOO_ANIMAL_MAX_PLAYER_DAMAGES			= 4;
const int ZOO_ANIMAL_MAX_TOUCH_FORCE_ON_PLAYER		= 3;
const int ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER	= 2;
const int ZOO_ANIMAL_MAX_AI_STATES			= 4;
const int ZOO_ANIMAL_MAX_AI_ACTS			= 4;
const int ZOO_ANIMAL_MAX_AI_SCHED_ACTS			= 9;

class CBaseZooAnimal : public CAI_BaseNPC
{
public:
	DECLARE_CLASS( CBaseZooAnimal, CAI_BaseNPC );
	DECLARE_DATADESC();
	DEFINE_CUSTOM_AI;
	 // Data Members

	int	        m_nZooAnimalAIState;
	int		m_nZooAnimalAIType;
	int		m_nMaxHitCount;
	int		m_nCurrentHitCount;
	int		m_nCurrentIcon;
	int		m_nCurrentFleePath;
	int		m_nCurrentAIAct;
	int		m_nHurtFlickerRate;

	bool		m_bIsHurt;

	float		m_flIconVerticalDisplacment;

	Activity	m_currentMeleeAttackActivity;

	Activity	m_aiMeleeAttackActivity[ ZOO_ANINAL_MAX_AI_MELEE_ATTACK_ACTIVITY ];

	int		m_aiPreActivity[ ZOO_ANIMAL_MAX_AI_SCHED_ACTS ][ ZOO_ANIMAL_MAX_AI_ACTS ];
	int		m_aiPostActivity[ ZOO_ANIMAL_MAX_AI_SCHED_ACTS ][ ZOO_ANIMAL_MAX_AI_ACTS ];

	int		m_aiPlayerDamage[ ZOO_ANIMAL_MAX_PLAYER_DAMAGES ];

	bool		m_aiLockPreActivity[ ZOO_ANIMAL_MAX_AI_SCHED_ACTS ][ ZOO_ANIMAL_MAX_AI_ACTS ];
	bool		m_aiLockPostActivity[ ZOO_ANIMAL_MAX_AI_SCHED_ACTS ][ ZOO_ANIMAL_MAX_AI_ACTS ];
	bool		m_activeTouchForceOnPlayer[ ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER ];

	float		m_aiDamage[ ZOO_ANIMAL_MAX_AI_DAMAGES ];
	float		m_iconTime[ ZOO_ANIMAL_MAX_ICONS ];
	float		m_iconWaitTime[ ZOO_ANIMAL_MAX_ICONS ];
	float		m_aiTimerThinkTime[ ZOO_ANIMAL_MAX_AI_TIMERS ];
	float		m_aiTimerWaitThinkTime[ ZOO_ANIMAL_MAX_AI_TIMERS ];
	float		m_aiTouchForceOnPlayer[ ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER ][ ZOO_ANIMAL_MAX_TOUCH_FORCE_ON_PLAYER ];

	string_t	m_icons[ ZOO_ANIMAL_MAX_ICONS ];

	Vector		m_aiRange[ ZOO_ANIMAL_MAX_AI_RANGES ];
	Vector		m_aiRangeOffset[ ZOO_ANIMAL_MAX_AI_RANGES ];

	string_t	m_pathList[ ZOO_ANIMAL_MAX_AI_PATH_TYPES ][ ZOO_ANIMAL_MAX_AI_PATHS ];

	bool		** m_pAIPlayerStateDamage;

	const char	** m_pSounds;

											// Helper for testing whether the NPC is within a certain distance of another entity.

	CZooAnimal_ProxTester			m_PlayerSelfProxTester;

	CBaseEntity				*	m_pPathCorner;

														// HACK

	CDynamicProp				 * m_pIcon[ ZOO_ANIMAL_MAX_ICONS ];
	//CSprite				** m_pIcon;

	CBaseEntity		*GetPlayer()	{ return UTIL_GetLocalPlayer();	}

	// Default Constructor

	CBaseZooAnimal();

	// GET Functions

	float					GetMinRunSpeed();
	float					GetMaxRunSpeed();
	float					GetMinWalkSpeed();
	float					GetMaxWalkSpeed();
	float					GetAIDamage( int aiDamage );
	float					GetIconTime( int icon );
	float					GetAITimerThinkTime( int aiTimer );
	
	int					GetHitCount();
	int					GetAIState();
	int					GetAIType();
	int					GetAIPlayerDamage( int aiPlayerDamage );
	int					GetAISchedAct();
	int					GetAIPreAct( int aiSchedule, int aiAct );
	int					GetAIPostAct( int aiSchedule, int aiAct );

	bool					GetAIPlayerStateDamage( int aiState, int aiPlayerDamage );

	Vector				GetAIRange( int aiRange );
	Vector				GetAIRangeOffset( int aiRangeOffset );
	Vector				GetTouchForceOnPlayer( int aiTouchForceType );

	int				GetConVarInt( int conVar );
	float				GetConVarFloat( int conVar );
	Vector				GetConVarVector( int conVar );

	// SET Functions

	void				SetIconWaitTime( int icon, float iconTime );
	void				SetAITimerWaitThinkTime( int aiTimer, float aiTimerTime );
	void				SetAIState( int aiState );

		 // Member Functions

	bool					EvalPlayerSelfProximity( Vector offset, Vector dist, int collisionType );
	bool					IsIconWaitTimeFinished( int icon );
	bool					IsAITimerWaitThinkTimeFinished( int aiTimer );
	bool					IsStunned();
	bool					IsInvincible();

	void					DecrementHitCount( int hits );
	void					InitIcons();
	void					ChangeIcon( int icon );
	void					TurnOnIcon( int icon );
	void					TurnOffIcon( int icon );
	void					ResetHitCount();
	void					ClearIconWaitTime( int icon );
	void					ClearAITimerWaitThinkTime( int aiTimer );
	void					TouchRange( CBaseEntity *pOther );
	void					PlayZooAnimalSound( int aiSound );
	void					MonkeyStateMachine();
	void					BirdStateMachine();
	void					WalrusStateMachine();
	void					LockAIPreAct( int aiSchedule, int aiAct );
	void					LockAIPostAct( int aiSchedule, int aiAct );
	void					UnLockAIPreAct( int aiSchedule, int aiAct );
	void					UnLockAIPostAct( int aiSchedule, int aiAct );
	void					ToggleAllAIPreAct( bool toggle );
	void					ToggleAllAIPostAct( bool toggle );

        void		Spawn( void );
	void		Precache( void );
	void		RunTask( const Task_t *pTask );
	void		StartTask( const Task_t *pTask );
	void		MoveOrigin( const Vector &vecDelta );
	void		ThrowAt( const Vector &vecPos );
	void		ThrowThink( void );
	void		OnChangeActivity( Activity NewActivity );
	void		Touch( CBaseEntity *pOther );
	void		TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
	void		GatherConditions( void );
	void		PrescheduleThink( void );
	void		ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut );
	void		BuildScheduleTestBits( void );
	void		HandleAnimEvent( animevent_t *pEvent );

	int		OnTakeDamage_Alive( const CTakeDamageInfo &info );

	bool		IsFirmlyOnGround();
	bool		HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
	float		MaxYawSpeed( void );

	Class_T Classify( void );
	
	int		SelectSchedule( void );
	int		SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
	int		TranslateSchedule( int scheduleType );

	bool	CanBeAnEnemyOf( CBaseEntity *pEnemy );

protected:
	int		CalcDamageInfo( CTakeDamageInfo *pInfo );
	float		m_flNextNPCThink;
};

class CBSG_Monkey : public CBaseZooAnimal
{
public:
	DEFINE_CUSTOM_AI;
	//DECLARE_DATADESC();
	DECLARE_CLASS( CBSG_Monkey, CBaseZooAnimal );

	// Default Constructor

	CBSG_Monkey();

	// Default Deconstructor

	~CBSG_Monkey();
private:
protected:
};

class CBSG_Bird : public CBaseZooAnimal
{	
public:
	DEFINE_CUSTOM_AI;
	//DECLARE_DATADESC();
	DECLARE_CLASS( CBSG_Bird, CBaseZooAnimal );

	// Default Constructor

	CBSG_Bird();

	// Default Deconstructor

	~CBSG_Bird();
private:
protected:
};

class CBSG_Walrus : public CBaseZooAnimal
{	
public:
	DEFINE_CUSTOM_AI;
	//DECLARE_DATADESC();
	DECLARE_CLASS( CBSG_Walrus, CBaseZooAnimal );

	// Default Constructor

	CBSG_Walrus();

	// Default Deconstructor

	~CBSG_Walrus();

	// Member Functions

	int		OnTakeDamage_Alive( const CTakeDamageInfo &info );

	void	HandleAnimEvent( animevent_t *pEvent );
private:
protected:
};

#endif NPC_ZOO_ANIMAL_H


The Ghastleybriar Zoo Incident - A.I. CPP

#include "cbase.h"
#include "ai_interactions.h"
#include "npcevent.h"
#include "ai_senses.h"
#include "bsg_npc_zoo_animal.h"
#include "hl2_shareddefs.h"

#include "tier0/memdbgon.h"

#define ZOO_ANIMAL_CONSOLE 1

int g_interactionZooAnimalMelee = 0;		//melee bash attack

//-----------------------------------------------------------------------------
// Think contexts.
//-----------------------------------------------------------------------------
static const char *s_pPitchContext = "PitchContext";

//-----------------------------------------------------------------------------
// Zoo Animal Constants
//-----------------------------------------------------------------------------

const int	ZOO_ANIMAL_DEFAULT_HIT_POINTS		= 1;
const int	ZOO_ANIMAL_DEFAULT_PLAYER_DAMAGE	= 0;

const float ZOO_ANIMAL_DEFAULT_ICON_TIME		= 0.1f;
const float ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME	= 0.1f;
const float ZOO_ANIMAL_DEFAULT_AI_DAMAGE		= 0.0f;
const float ZOO_ANIMAL_DEFAULT_TOUCH_FORCE_ON_PLAYER	= 0.0f;
const float ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET	        = 0.0f;

float		ZOO_ANIMAL_DEFAULT_AI_RANGE		= 32.0f; // Not constant bc we want to base this on the npc's bounding box/hull size

//-----------------------------------------------------------------------------
// Zoo Animal Hit Counts
//-----------------------------------------------------------------------------

enum HIT_COUNT_ZOO_ANIMAL
{
	HIT_COUNT_ZOO_ANIMAL_ZERO,
	HIT_COUNT_ZOO_ANIMAL_ONE,
	HIT_COUNT_ZOO_ANIMAL_TWO
};

//-----------------------------------------------------------------------------
// Zoo Animal AI States
//-----------------------------------------------------------------------------
enum AI_STATE_ZOO_ANIMAL
{
	 AI_STATE_ZOO_ANIMAL_NEUTRAL,
	 AI_STATE_ZOO_ANIMAL_DEFENSIVE,
	 AI_STATE_ZOO_ANIMAL_AGGRESSIVE,
	 AI_STATE_ZOO_ANIMAL_STUNNED
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Types
//-----------------------------------------------------------------------------
enum AI_TYPE_ZOO_ANIMAL
{
	AI_TYPE_ZOO_ANIMAL_BIRD,
	AI_TYPE_ZOO_ANIMAL_MONKEY,
	AI_TYPE_ZOO_ANIMAL_WALRUS
};

//-----------------------------------------------------------------------------
// Zoo Animal Icons
//-----------------------------------------------------------------------------
enum ICON_ZOO_ANIMAL
{
	ICON_ZOO_ANIMAL_PASSIVE,
	ICON_ZOO_ANIMAL_ALERT,
	ICON_ZOO_ANIMAL_ANGRY,
	ICON_ZOO_ANIMAL_FEAR,
	ICON_ZOO_ANIMAL_DAZED,
	ICON_ZOO_ANIMAL_CONFUSED
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Timer
//-----------------------------------------------------------------------------
enum AI_TIMER_ZOO_ANIMAL
{
	// Flee Wait Think Time:  HALF LIFE 2 amount of time ( AI thinks ) until the NPC re-evaulates its path for fleeing from the Player
	// Flee Think Time:  USER DEFINED amount of time ( seconds ) until the NPC re-evaluates its path for fleeing from the player

	AI_TIMER_ZOO_ANIMAL_FLEE,

	// Active Wait Think Time:  HALF LIFE 2 amount of time ( AI thinks ) the NPC actively engages ( AGGRESSIVE or DEFENSIVE )the Player.
	//							NOTE: This time is "reset" every time the NPC attacks or runs away due to the Player being close to teh NPC
	// Active Think Time:	USER DEFINED amount of time ( seconds ) the NPC actively engages ( AGGRESSIVE or DEFENSIVE )the Player.
	//						NOTE: This time is "reset" every time the NPC attacks or runs away due to the Player being close to teh NPC

	AI_TIMER_ZOO_ANIMAL_START_FLEE,
	AI_TIMER_ZOO_ANIMAL_RAGE,
	AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION,
	AI_TIMER_ZOO_ANIMAL_CHASE,
	AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION,

	// Defensive Melee Attack Wait Think Time:  HALF LIFE 2 amount of time ( AI thinks ) the NPC waits before performing an defensive melee attack on the Player.
	//											NOTE: This time is set after each defensive melee attack
	// Defensive Melee Attack Think Time:  USER DEFINED amount of time ( seconds ) the NPC waits before performing an defensive melee attack on the Player.
	//										NOTE: This time is set after each defensive melee attack

	AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE,

	// Aggressive Melee Attack Think Time:  HALF LIFE 2 amount of time ( AI thinks ) the NPC waits before performing an aggressive melee attack on the Player.
	//										NOTE: This time is set after each aggressive melee attack
	// Aggressive Melee Attack Think Time:  USER DEFINED amount of time ( seconds ) the NPC waits before performing an aggressive melee attack on the Player.
	//										NOTE: This time is set after each aggressive melee attack

	AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE,


	AI_TIMER_ZOO_ANIMAL_STUNNED,
	AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN,
	AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE,
	AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP,
	AI_TIMER_ZOO_ANIMAL_HURT,
	AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE,
	AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Range
//-----------------------------------------------------------------------------
enum AI_RANGE_ZOO_ANIMAL
{
	// The proximity at which the NPC becomes aggressive toward the Player

	AI_RANGE_ZOO_ANIMAL_AGGRESSIVE,

	// The proximity at which the NPC becmoe defensive toward the Player

	AI_RANGE_ZOO_ANIMAL_DEFENSIVE,

	// The threshold distance the NPC must be from the Player in order for the NPC to attempt to hit 
	// the Player with an Aggressive Melee Attack

	AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE,

	// The threshold distance the NPC must be from the Player in order for the NPC to attempt to hit 
	// the Player with a Defensive Melee Attack

	AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE,

	AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT,
	AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT,
	AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE,
	AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY,
	AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH,
	AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH,
	AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Damage
//-----------------------------------------------------------------------------
enum AI_DAMAGE_ZOO_ANIMAL
{
	AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE,
	AI_DAMAGE_ZOO_ANIMAL_DEFENSIVE_MELEE
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Sound
//-----------------------------------------------------------------------------
enum AI_SOUND_ZOO_ANIMAL
{
	AI_SOUND_ZOO_ANIMAL_FLEE,
	AI_SOUND_ZOO_ANIMAL_ANGRY,
	AI_SOUND_ZOO_ANIMAL_DAZED,
	AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK,
	AI_SOUND_ZOO_ANIMAL_HURT
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Sound
//-----------------------------------------------------------------------------
enum AI_PATH_TYPE_ZOO_ANIMAL
{
	AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT,
	AI_PATH_TYPE_ZOO_ANIMAL_FLEE,
	AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE,
	AI_PATH_TYPE_ZOO_ANIMAL_RAGE
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Schedule Activity to play
//-----------------------------------------------------------------------------
enum AI_SCHED_ACT_ZOO_ANIMAL
{
	AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH,
	AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_COOLDOWN,
	AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER,
	AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER,
	AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY,
	AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER,
	AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER,
	AI_SCHED_ACT_ZOO_ANIMAL_STUNNED,
	AI_SCHED_ACT_ZOO_ANIMAL_HURT
};

//-----------------------------------------------------------------------------
// Player Damage on Zoo Animal
//-----------------------------------------------------------------------------
enum PLAYER_DAMAGE_ZOO_ANIMAL
{
	PLAYER_DAMAGE_ZOO_ANIMAL_TRAP,
	PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1,
	PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2,
	PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3
};

//-----------------------------------------------------------------------------
// Touch Forces on the Player
//-----------------------------------------------------------------------------
enum AI_TOUCH_FORCE_PLAYER
{
	AI_TOUCH_FORCE_PLAYER_FORWARD,
	AI_TOUCH_FORCE_PLAYER_RIGHT,
	AI_TOUCH_FORCE_PLAYER_UP
};

//-----------------------------------------------------------------------------
// Touch Forces on the Player
//-----------------------------------------------------------------------------
enum AI_TOUCH_FORCE_PLAYER_TYPE
{
	AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY,
	AI_TOUCH_FORCE_PLAYER_TYPE_RAGE
};

//-----------------------------------------------------------------------------
// Zoo Animal AI Attack Activity
//-----------------------------------------------------------------------------
enum AI_ATTACK_ACTIVITY
{
	AI_ATTACK_ACTIVITY_ZOO_ANIMAL_MELEE_ATTACK_1,
	AI_ATTACK_ACTIVITY_ZOO_ANIMAL_MELEE_ATTACK_2
};

//-----------------------------------------------------------------------------
// Zoo Animal AI ConVars
//-----------------------------------------------------------------------------

enum AI_CONVAR_ZOO_ANIMAL
{
	AI_CONVAR_ZOO_ANIMAL_FLEE_TIME,
	AI_CONVAR_ZOO_ANIMAL_START_FLEE_TIME,
	AI_CONVAR_ZOO_ANIMAL_CHASE_TIME,
	AI_CONVAR_ZOO_ANIMAL_CHASE_EVAL_TIME,
	AI_CONVAR_ZOO_ANIMAL_ACTIVE_TIME,
	AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_TIME,
	AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_TIME,
	AI_CONVAR_ZOO_ANIMAL_STUNNED_TIME,
	AI_CONVAR_ZOO_ANIMAL_HEALTH_REGEN_TIME,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_MELEE_TIME,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_TRAP_TIME,
	AI_CONVAR_ZOO_ANIMAL_HURT_TIME,
	AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_TIME,
	AI_CONVAR_ZOO_ANIMAL_RAGE_TIME,
	AI_CONVAR_ZOO_ANIMAL_MAX_HIT_COUNT,
	AI_CONVAR_ZOO_ANIMAL_HURT_FLICKER_RATE,
	AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_RANGE,
	AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_RANGE,
	AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE,
	AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE,
	AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT_RANGE,
	AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT_RANGE,
	AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_RANGE,
	AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_TOUCH_RANGE,
	AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_DAMAGE,
	AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE,
	AI_CONVAR_ZOO_ANIMAL_STATE,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_F,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_R,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_U,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_F,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_R,
	AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_U,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_TRAP,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_1,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_2,
	AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_3
};

//-----------------------------------------------------------------------------
// Animation events.
//-----------------------------------------------------------------------------

//#define AE_ZOO_ANIMAL_MELEE_ATTACK_SWING_GESTURE ( 3 )
#define AE_ZOO_ANIMAL_MELEE_ATTACK ( 3 )

//-----------------------------------------------------------------------------
// Custom schedules.
//-----------------------------------------------------------------------------

enum
{
	// Custom Zoo Animal Schedules
	
	SCHED_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH = LAST_SHARED_SCHEDULE,
	SCHED_ZOO_ANIMAL_NEUTRAL_COOLDOWN,
	SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER,
	SCHED_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER,
	SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY,
	SCHED_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER,
	SCHED_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER,
	SCHED_ZOO_ANIMAL_STUNNED,
	SCHED_ZOO_ANIMAL_HURT,
	SCHED_ZOO_ANIMAL_ALERT_FACE,
	SCHED_ZOO_ANIMAL_ALERT_FACE_BESTSOUND,
	SCHED_ZOO_ANIMAL_ALERT_REACT_TO_COMBAT_SOUND,
	SCHED_ZOO_ANIMAL_ALERT_SCAN,
	SCHED_ZOO_ANIMAL_ALERT_STAND,
	SCHED_ZOO_ANIMAL_ALERT_WALK,
};


//=========================================================
// tasks
//=========================================================

enum 
{
	// Custom Zoo Animal Tasks

	TASK_ZOO_ANIMAL_DEFENSIVE_START_GET_PATH_TO_FLEE = LAST_SHARED_TASK,
	TASK_ZOO_ANIMAL_DEFENSIVE_END_GET_PATH_TO_FLEE,
	TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_TO_PLAYER,
	TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_TO_PLAYER,
	TASK_ZOO_ANIMAL_AGGRESSIVE_START_ATTACK_PLAYER,
	TASK_ZOO_ANIMAL_AGGRESSIVE_END_ATTACK_PLAYER,
	TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_WILDLY,
	TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_WILDLY,
	TASK_ZOO_ANIMAL_DEFENSIVE_START_ATTACK_PLAYER,
	TASK_ZOO_ANIMAL_DEFENSIVE_END_ATTACK_PLAYER,
	TASK_ZOO_ANIMAL_NEUTRAL_START_RETURN_TO_A_PATH,
	TASK_ZOO_ANIMAL_NEUTRAL_END_RETURN_TO_A_PATH,
	TASK_ZOO_ANIMAL_NEUTRAL_START_COOLDOWN,
	TASK_ZOO_ANIMAL_NEUTRAL_END_COOLDOWN,
	TASK_ZOO_ANIMAL_STUNNED_START,
	TASK_ZOO_ANIMAL_STUNNED_END,
	TASK_ZOO_ANIMAL_SET_TOLERANCE_DISTANCE,
	TASK_ZOO_ANIMAL_GET_CHASE_PATH_TO_ENEMY,
	TASK_ZOO_ANIMAL_MOVE_ON_PATH,
	TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY,
	TASK_ZOO_ANIMAL_POST_SET_AND_WAIT_ACTIVITY,
	TASK_ZOO_ANIMAL_MELEE_ATTACK,
	TASK_ZOO_ANIMAL_HURT,
};

//=========================================================
// conditions 
//=========================================================

enum
{
	// Custom Zoo Animal Conditions
	
	COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER = LAST_SHARED_CONDITION,
	COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER,
	COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER,
	COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER,
	COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER,
	COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH,
	COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN,
	COND_ZOO_ANIMAL_STUNNED,
	COND_ZOO_ANIMAL_HURT,
};

//=========================================================
// private activities
//=========================================================

int ACT_DAZE;
int ACT_MAD;
int ACT_SHOCK;

//-----------------------------------------------------------------------------
// Skill settings.
//-----------------------------------------------------------------------------

// Zoo Animal

ConVar bsg_zooanimal_debug( "bsg_zooanimal_debug", "0", FCVAR_NONE, "0", true, 0, true, 1 );

// Monkey 

ConVar bsg_monkey_fleetime( "bsg_monkey_fleetime", "15.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_startfleetime( "bsg_monkey_startfleetime", "0.1", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_chasetime( "bsg_monkey_chasetime", "35.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_chaseevaltime( "bsg_monkey_chaseevaltime", "40.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_aggmeleetime( "bsg_monkey_aggmeleetime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_defmeleetime( "bsg_monkey_defmeleetime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_stunnedtime( "bsg_monkey_stunnedtime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_healthregentime( "bsg_monkey_healthregentime", "40.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_playermeleetime( "bsg_monkey_playermeleetime", "1.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_playertraptime( "bsg_monkey_playertraptime", "0.1", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_hurttime( "bsg_monkey_hurttime", "5.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_changefleepathtime( "bsg_monkey_changefleepathtime", "1.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_ragetime( "bsg_monkey_ragetime", "0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_maxhitcount( "bsg_monkey_maxhitcount", "3", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_monkey_hurtflickerrate( "bsg_monkey_hurtflickerrate", "10", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_defrange( "bsg_monkey_defrange", "128.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_aggrange( "bsg_monkey_aggrange", "650.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_defmeleerange( "bsg_monkey_defmeleerange", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_aggmeleerange( "bsg_monkey_aggmeleerange", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_defmeleehitrange( "bsg_monkey_defmeleehitrange", "32.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_aggmeleehitrange( "bsg_monkey_aggmeleehitrange", "32.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_changefleepathrange( "bsg_monkey_changefleepathrange", "128.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_changefleepathoff( "bsg_monkey_changefleepathoff", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_playertouchrange( "bsg_monkey_playertouchrange", "42.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_monkey_defmeleedmg( "bsg_monkey_defmeleedmg", "20.0", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_monkey_aggmeleedmg( "bsg_monkey_aggmeleedmg", "20.0", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_monkey_touchforceonplayerproxf( "bsg_monkey_touchforceonplayerfproxf", "-250.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_touchforceonplayerproxr( "bsg_monkey_touchforceonplayerrproxr", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_touchforceonplayerproxu( "bsg_monkey_touchforceonplayerproxu", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_touchforceonplayerragef( "bsg_monkey_touchforceonplayerfragef", "-250.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_touchforceonplayerrager( "bsg_monkey_touchforceonplayerrager", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_touchforceonplayerrageu( "bsg_monkey_touchforceonplayerrageu", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_monkey_playerdmgtrap( "bsg_monkey_playerdmgtrap", "3", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_monkey_playerdmgbag1( "bsg_monkey_playerdmgbag1", "1", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_monkey_playerdmgbag2( "bsg_monkey_playerdmgbag2", "2", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_monkey_playerdmgbag3( "bsg_monkey_playerdmgbag3", "3", FCVAR_NONE, "0", true, 0, false, 0 );

// Bird

ConVar bsg_bird_fleetime( "bsg_bird_fleetime", "15.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_startfleetime( "bsg_bird_startfleetime", "0.1", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_chasetime( "bsg_bird_chasetime", "35.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_chaseevaltime( "bsg_bird_chaseevaltime", "40.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_aggmeleetime( "bsg_bird_aggmeleetime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_defmeleetime( "bsg_bird_defmeleetime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_stunnedtime( "bsg_bird_stunnedtime", "3.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_healthregentime( "bsg_bird_healthregentime", "40.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_playermeleetime( "bsg_bird_playermeleetime", "1.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_playertraptime( "bsg_bird_playertraptime", "0.1", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_hurttime( "bsg_bird_hurttime", "5.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_changefleepathtime( "bsg_bird_changefleepathtime", "1.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_ragetime( "bsg_bird_ragetime", "0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_maxhitcount( "bsg_bird_maxhitcount", "1", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_bird_hurtflickerrate( "bsg_bird_hurtflickerrate", "10", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_defrange( "bsg_bird_defrange", "128.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_aggrange( "bsg_bird_aggrange", "650.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_defmeleerange( "bsg_bird_defmeleerange", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_aggmeleerange( "bsg_bird_aggmeleerange", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_defmeleehitrange( "bsg_bird_defmeleehitrange", "32.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_aggmeleehitrange( "bsg_bird_aggmeleehitrange", "32.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_changefleepathrange( "bsg_bird_changefleepathrange", "128.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_changefleepathoff( "bsg_bird_changefleepathoff", "64.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_playertouchrange( "bsg_bird_playertouchrange", "42.0", FCVAR_NONE, "0", true, 0.1, false, 0 );
ConVar bsg_bird_defmeleedmg( "bsg_bird_defmeleedmg", "20.0", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_bird_aggmeleedmg( "bsg_bird_aggmeleedmg", "20.0", FCVAR_NONE, "0", true, 1, false, 0 );
ConVar bsg_bird_touchforceonplayerproxf( "bsg_bird_touchforceonplayerproxf", "-250.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_touchforceonplayerproxr( "bsg_bird_touchforceonplayerproxr", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_touchforceonplayerproxu( "bsg_bird_touchforceonplayerproxu", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_touchforceonplayerragef( "bsg_bird_touchforceonplayerragef", "-250.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_touchforceonplayerrager( "bsg_bird_touchforceonplayerrager", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_touchforceonplayerrageu( "bsg_bird_touchforceonplayerrageu", "0.0", FCVAR_NONE, "0", false, 0, false, 0 );
ConVar bsg_bird_playerdmgtrap( "bsg_bird_playerdmgtrap", "3", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_bird_playerdmgbag1( "bsg_bird_playerdmgbag1", "1", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_bird_playerdmgbag2( "bsg_bird_playerdmgbag2", "2", FCVAR_NONE, "0", true, 0, false, 0 );
ConVar bsg_bird_playerdmgbag3( "bsg_bird_playerdmgbag3", "3", FCVAR_NONE, "0", true, 0, false, 0 );

BEGIN_DATADESC( CBaseZooAnimal )

	DEFINE_FIELD( m_flNextNPCThink, FIELD_TIME ),

	// Defining Fields for Zoo Animal

	DEFINE_FIELD( m_PlayerSelfProxTester, FIELD_CLASSPTR),
		
	DEFINE_FIELD( m_nZooAnimalAIState, FIELD_INTEGER ),
	DEFINE_FIELD( m_nZooAnimalAIType, FIELD_INTEGER ),
	DEFINE_FIELD( m_nCurrentHitCount, FIELD_INTEGER ),
	DEFINE_FIELD( m_nCurrentIcon, FIELD_INTEGER ),
	DEFINE_FIELD( m_nCurrentFleePath, FIELD_INTEGER ),
	DEFINE_FIELD( m_nCurrentAIAct, FIELD_INTEGER ),
	DEFINE_FIELD( m_nHurtFlickerRate, FIELD_INTEGER ),

	DEFINE_FIELD( m_bIsHurt, FIELD_BOOLEAN ),

	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_FLEE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_STUNNED ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ], FIELD_FLOAT ),
	DEFINE_FIELD( m_aiTimerWaitThinkTime[ AI_TIMER_ZOO_ANIMAL_RAGE ], FIELD_FLOAT ),

	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_PASSIVE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_ALERT ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_ANGRY ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_FEAR ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_DAZED ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconTime[ ICON_ZOO_ANIMAL_CONFUSED ], FIELD_FLOAT ),

	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_PASSIVE ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_ALERT ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_ANGRY ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_FEAR ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_DAZED ], FIELD_FLOAT ),
	DEFINE_FIELD( m_iconWaitTime[ ICON_ZOO_ANIMAL_CONFUSED ], FIELD_FLOAT ),

	DEFINE_FIELD( m_pIcon[ ICON_ZOO_ANIMAL_DAZED ], FIELD_CLASSPTR ),

	DEFINE_KEYFIELD( m_nMaxHitCount, FIELD_INTEGER, "maxHitCount" ),
	DEFINE_KEYFIELD( m_nHurtFlickerRate, FIELD_INTEGER, "hurtFlickerRate" ),

	DEFINE_KEYFIELD( m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ] , FIELD_INTEGER, "playerDmgTrap" ),
	DEFINE_KEYFIELD( m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ] , FIELD_INTEGER, "playerDmgBag1" ),
	DEFINE_KEYFIELD( m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ] , FIELD_INTEGER, "playerDmgBag2" ),
	DEFINE_KEYFIELD( m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ] , FIELD_INTEGER, "playerDmgBag3" ),

	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ].x, FIELD_FLOAT, "aggRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_DEFENSIVE ].x, FIELD_FLOAT, "defRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE ].x, FIELD_FLOAT, "defMeleeRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE ].x, FIELD_FLOAT, "aggMeleeRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT ].x, FIELD_FLOAT, "defMeleeHitRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT ].x, FIELD_FLOAT, "aggMeleeHitRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE ].x, FIELD_FLOAT, "toleranceDistance" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY ].x, FIELD_FLOAT, "chasePathToEnemy" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ].x, FIELD_FLOAT, "changeFleePathRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH ].x, FIELD_FLOAT, "playerTouchRange" ),
	DEFINE_KEYFIELD( m_aiRange[ AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH ].x, FIELD_FLOAT, "rageTouchRange" ),

	DEFINE_KEYFIELD( m_aiRangeOffset[ AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ].x, FIELD_FLOAT, "changeFleePathOffset" ),
	DEFINE_KEYFIELD( m_aiRangeOffset[ AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH ].x, FIELD_FLOAT, "rageTouchOffset" ),

	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_FLEE ], FIELD_FLOAT, "fleeTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_START_FLEE ], FIELD_FLOAT, "startFleeTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE ], FIELD_FLOAT, "chaseTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ], FIELD_FLOAT, "chaseEvalTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE ], FIELD_FLOAT, "aggMeleeTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ], FIELD_FLOAT, "defMeleeAttackTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_STUNNED ], FIELD_FLOAT, "stunnedTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ], FIELD_FLOAT, "healthRegenTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ], FIELD_FLOAT, "playerMeleeTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ], FIELD_FLOAT, "playerTrapTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT ], FIELD_FLOAT, "hurtTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ], FIELD_FLOAT, "changeFleePathTime" ),
	DEFINE_KEYFIELD( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_RAGE ], FIELD_FLOAT, "rageTime" ),

	DEFINE_KEYFIELD( m_aiDamage[ AI_DAMAGE_ZOO_ANIMAL_DEFENSIVE_MELEE ], FIELD_FLOAT, "defMeleeDamage" ),
	DEFINE_KEYFIELD( m_aiDamage[ AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE ], FIELD_FLOAT, "aggMeleeDamage" ),

	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_FORWARD ], FIELD_FLOAT, "forceOnPlayerForward" ),
	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_RIGHT ], FIELD_FLOAT, "forceOnPlayerRight" ),
	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_UP ], FIELD_FLOAT, "forceOnPlayerUp" ),
	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ][ AI_TOUCH_FORCE_PLAYER_FORWARD ], FIELD_FLOAT, "rageForceOnPlayerForward" ),
	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ][ AI_TOUCH_FORCE_PLAYER_RIGHT ], FIELD_FLOAT, "rageForceOnPlayerRight" ),
	DEFINE_KEYFIELD( m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ][ AI_TOUCH_FORCE_PLAYER_UP ], FIELD_FLOAT, "rageForceOnPlayerUp" ),

	DEFINE_KEYFIELD( m_flIconVerticalDisplacment, FIELD_FLOAT, "iconVertDisplacement" ),

	// This may change depending on the method for polling the path corners to travel to.
	// If a "good" naming scheme is used, you could potentially have many more path corners
	// an npc could travel to and poll only those path corners that are named. Then randomly
	// choose from those paths.

	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][0], FIELD_STRING, "m_pathList_0" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][1], FIELD_STRING, "m_pathList_1" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][2], FIELD_STRING, "m_pathList_2" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][3], FIELD_STRING, "m_pathList_3" ),

	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][0], FIELD_STRING, "fleePathList_0" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][1], FIELD_STRING, "fleePathList_1" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][2], FIELD_STRING, "fleePathList_2" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][3], FIELD_STRING, "fleePathList_3" ),

	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][0], FIELD_STRING, "altFleePathList_0" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][1], FIELD_STRING, "altFleePathList_1" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][2], FIELD_STRING, "altFleePathList_2" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][3], FIELD_STRING, "altFleePathList_3" ),

	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][0], FIELD_STRING, "ragePathList_0" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][1], FIELD_STRING, "ragePathList_1" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][2], FIELD_STRING, "ragePathList_2" ),
	DEFINE_KEYFIELD( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][3], FIELD_STRING, "ragePathList_3" ),
	
	// Outputs

	// Function Pointers for Zoo Animal

	DEFINE_THINKFUNC( ThrowThink ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( npc_zoo_animal_00, CBaseZooAnimal ); // DUMMY PARENT
LINK_ENTITY_TO_CLASS( npc_zoo_animal_01, CBSG_Monkey );
LINK_ENTITY_TO_CLASS( npc_zoo_animal_02, CBSG_Bird );
LINK_ENTITY_TO_CLASS( npc_zoo_animal_03, CBSG_Walrus );

//-----------------------------------------------------------------------------
// Default Constructor
//-----------------------------------------------------------------------------

CBaseZooAnimal::CBaseZooAnimal()
{
	m_nZooAnimalAIState	= AI_STATE_ZOO_ANIMAL_NEUTRAL;
	m_nZooAnimalAIType	= AI_TYPE_ZOO_ANIMAL_MONKEY;
	m_nCurrentIcon		= ICON_ZOO_ANIMAL_PASSIVE;
	m_nMaxHitCount		= 1; 
	m_nCurrentHitCount	= m_nMaxHitCount;
	m_nCurrentFleePath	= 0;
	m_nCurrentAIAct		= 0;
	m_nHurtFlickerRate	= 1;

	m_iHealth		= 1;

	m_bIsHurt		= false;

	m_pPathCorner		= NULL;
	m_pSounds		= new const char*[ ZOO_ANIMAL_MAX_AI_SOUNDS ];
	m_pAIPlayerStateDamage	= new bool*[ ZOO_ANIMAL_MAX_PLAYER_DAMAGES ];

	for ( int i = 0; i < ZOO_ANIMAL_MAX_PLAYER_DAMAGES; i++ )
	{
		m_pAIPlayerStateDamage[ i ] = new bool[ ZOO_ANIMAL_MAX_AI_STATES ];

		for ( int j = 0; j < ZOO_ANIMAL_MAX_AI_STATES; j++ )
		{
			m_pAIPlayerStateDamage[ i ][ j ] = true;
		}
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_ICONS; i++ )
	{
		m_pIcon[ i ] = NULL;
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_SOUNDS; i ++)
	{
		m_pSounds[ i ]	= NULL;
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_ICONS; i++ )
	{
		m_iconWaitTime[i] = FLT_MAX;
		m_iconTime[i]			= FLT_MAX;
	}

	m_iconTime[ ICON_ZOO_ANIMAL_DAZED ] = ZOO_ANIMAL_DEFAULT_ICON_TIME;

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_TIMERS; i++ )
	{
		m_aiTimerWaitThinkTime[i]	= ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
		m_aiTimerThinkTime[i]			= ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME; 
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATH_TYPES; i++ ) 
	{
		for ( int j = 0; j < ZOO_ANIMAL_MAX_AI_PATHS; j++ )
		{
			m_pathList[ i ][ j ] = NULL_STRING;
		}
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_SCHED_ACTS; i++ )
	{
		for ( int j = 0; j < ZOO_ANIMAL_MAX_AI_ACTS; j++ )
		{
			m_aiPreActivity[ i ][ j ] = ( int )ACT_INVALID;
			m_aiPostActivity[ i ][ j ]= ( int )ACT_INVALID;
			m_aiLockPreActivity[ i ][ j ] = true;
			m_aiLockPostActivity[ i ][ j ] = true;
		}
	}

	// Determine the minimum distance between the npc and the player.
	//	- This roughly comes out to be 
	//		1/2 bounding box width of npc + 1/2 bounding box width of player

	float xNPCDist		= fabs( GetHullMaxs().x - GetHullMins().x );
	float yNPCDist		= fabs( GetHullMaxs().y - GetHullMins().y );
	float npcMinDist = ( xNPCDist < yNPCDist ) ? xNPCDist/2.0f : yNPCDist/2.0f;

	//CBaseEntity * pPlayer = GetPlayer();
	
	float xPlayerDist		= 32.0f; // see if we can actually poll this someway to be safe
	float yPlayerDist		= 32.0f; // see if we can actually poll this someway to be safe
	float playerMinDist	= ( xPlayerDist < yPlayerDist ) ? xPlayerDist/2.0f : yPlayerDist/2.0f;

	ZOO_ANIMAL_DEFAULT_AI_RANGE = npcMinDist + playerMinDist;

	m_flIconVerticalDisplacment	= GetHullMaxs().z; 

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_RANGES; i++ )
	{
		m_aiRange[ i ].x = ZOO_ANIMAL_DEFAULT_AI_RANGE;
		m_aiRange[ i ].y = ZOO_ANIMAL_DEFAULT_AI_RANGE;
		m_aiRange[ i ].z = ZOO_ANIMAL_DEFAULT_AI_RANGE;
	}

	m_aiRange[ AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH ].x = ZOO_ANIMAL_DEFAULT_AI_RANGE * 1.5f;
	m_aiRange[ AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH ].y = ZOO_ANIMAL_DEFAULT_AI_RANGE * 1.5f;
	m_aiRange[ AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH ].z = fabs( GetHullMaxs().z - GetHullMins().z )* 4.0f;

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_RANGES; i++ )
	{
		m_aiRangeOffset[ i ].x = ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET;
		m_aiRangeOffset[ i ].y = ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET;
		m_aiRangeOffset[ i ].z = ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET;
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_DAMAGES; i++ )
	{
		m_aiDamage[ i ] = ZOO_ANIMAL_DEFAULT_AI_DAMAGE;
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER; i++ )
	{
		for ( int j = 0; j < ZOO_ANIMAL_MAX_TOUCH_FORCE_ON_PLAYER; j++ )
		{
			m_aiTouchForceOnPlayer[ i ][ j ] = 0.0f;
		}
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER; i++ )
	{
		m_activeTouchForceOnPlayer[ i ] = false;
	}

	for ( int i = 0; i < ZOO_ANIMAL_MAX_PLAYER_DAMAGES; i++ )
	{
		m_aiPlayerDamage[ i ] = 0;
	}

	m_currentMeleeAttackActivity = ACT_MELEE_ATTACK_SWING_GESTURE;

	m_aiMeleeAttackActivity[ AI_ATTACK_ACTIVITY_ZOO_ANIMAL_MELEE_ATTACK_1 ] = ACT_MELEE_ATTACK_SWING_GESTURE;
	m_aiMeleeAttackActivity[ AI_ATTACK_ACTIVITY_ZOO_ANIMAL_MELEE_ATTACK_2 ] = ACT_GESTURE_MELEE_ATTACK1;

	m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_FORWARD ] = -250.0f; // TO REMOVE, LD CHANGE
	m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_RIGHT ]		= 0.0f; // TO REMOVE, LD CHANGE
	m_aiTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ][ AI_TOUCH_FORCE_PLAYER_UP ]			= 0.0f; // TO REMOVE, LD CHANGE

	m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ]		= 1;
	m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ]	= 1;
	m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ]	= 2;
	m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ]	= 3;

	// TO REMOVE

	for ( int i = 0; i < ZOO_ANIMAL_MAX_ICONS; i++ )
	{
		m_icons[ i ] = NULL_STRING; 
	}

	//m_icons[ ICON_ZOO_ANIMAL_ALERT ]	= MAKE_STRING( "gui/sprites/exclamation.vmt" );
	//m_icons[ ICON_ZOO_ANIMAL_ANGRY ]	= MAKE_STRING( "gui/sprites/madskull.vmt" );
	m_icons[ ICON_ZOO_ANIMAL_DAZED ]	= MAKE_STRING( "models/daze/daze.mdl" );
}

//-----------------------------------------------------------------------------
// Purpose: Get the AI Damage. Note that even though this
//					data member is used exclusively for this class, we use the GET method
//					to check to make sure the AI Damage was set properly.
// Input:		AI Damage Type ( int )
// Output:  AI Damage ( float )
//-----------------------------------------------------------------------------

float CBaseZooAnimal::GetAIDamage( int aiDamage )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiDamage )
		{
			case AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE ) > ZOO_ANIMAL_DEFAULT_AI_DAMAGE )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE );
				}
				break;
			}

			case AI_DAMAGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_DAMAGE ) > ZOO_ANIMAL_DEFAULT_AI_DAMAGE )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE );
				}
				break;
			}
		}
		return ZOO_ANIMAL_DEFAULT_AI_DAMAGE;
	}
	else
	{
		if ( aiDamage >= 0 && aiDamage < ZOO_ANIMAL_MAX_AI_DAMAGES )
		{
			if ( m_aiDamage[ aiDamage ] <= ZOO_ANIMAL_DEFAULT_AI_DAMAGE )
			{
				return ZOO_ANIMAL_DEFAULT_AI_DAMAGE;
			}
			else
			{
				switch ( aiDamage )
				{
					case AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
					case AI_DAMAGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
					{
						if ( m_aiDamage[ aiDamage ] > ZOO_ANIMAL_DEFAULT_AI_DAMAGE )
						{
							return m_aiDamage[ aiDamage ];
						}
						break;
					}
				}
			}
		}
		return ZOO_ANIMAL_DEFAULT_AI_DAMAGE;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the AI Range. Note that even though this
//					data member is used exclusively for this class, we use the GET method
//					to check to make sure the AI Range was set properly.
// Input:		None ( void )
// Output:  AI Range ( float )
//-----------------------------------------------------------------------------

Vector CBaseZooAnimal::GetAIRange( int aiRange )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiRange )
		{
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
			{
				float aggressiveRange = GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ).x;

				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE ) >= aggressiveRange )
				{
					return Vector( ( aggressiveRange - 0.1 ), ( aggressiveRange - 0.1 ), ( aggressiveRange - 0.1 ) );
				}
				else if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
			{
				float defensiveRange = GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE ).x;

				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE ) >= defensiveRange )
				{
					return Vector( ( defensiveRange - 0.1 ), ( defensiveRange - 0.1 ), ( defensiveRange - 0.1 ) );
				}
				else if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE:
			{
				return m_aiRange[ aiRange ];
			}

			case AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY:
			{
				return m_aiRange[ aiRange ];
			}

			case AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_TOUCH_RANGE ) > ZOO_ANIMAL_DEFAULT_AI_RANGE )
				{
					float x, y, z;

					x = GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_TOUCH_RANGE );
					y = x;
					z = x;

					return Vector( x, y, z );
				}
				break;
			}

			case AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH:
			{
				break;
			}
		}
		return Vector( ZOO_ANIMAL_DEFAULT_AI_RANGE, ZOO_ANIMAL_DEFAULT_AI_RANGE, ZOO_ANIMAL_DEFAULT_AI_RANGE );
	}
	else
	{
		if ( aiRange >= 0 && aiRange < ZOO_ANIMAL_MAX_AI_RANGES )
		{
			if ( m_aiRange[ aiRange ].x <= ZOO_ANIMAL_DEFAULT_AI_RANGE && 
					 m_aiRange[ aiRange ].y <= ZOO_ANIMAL_DEFAULT_AI_RANGE &&
					 m_aiRange[ aiRange ].y <= ZOO_ANIMAL_DEFAULT_AI_RANGE )
			{
				return Vector( ZOO_ANIMAL_DEFAULT_AI_RANGE, ZOO_ANIMAL_DEFAULT_AI_RANGE,ZOO_ANIMAL_DEFAULT_AI_RANGE );
			}
			else
			{
				switch ( aiRange )
				{
					case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE:
					case AI_RANGE_ZOO_ANIMAL_DEFENSIVE:
					case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT:
					case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT:
					case AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE:
					case AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY:
					case AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH:
					case AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH:
					case AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH:
					{
						return m_aiRange[ aiRange ];
					}

					case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
					{
						float aggressiveRange = GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ).x;

						if ( m_aiRange[ aiRange ].x >= aggressiveRange )
						{
							return Vector( ( aggressiveRange - 0.1 ), ( aggressiveRange - 0.1 ), ( aggressiveRange - 0.1 ) );
						}
						return m_aiRange[ aiRange ];
					}

					case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
					{
						float defensiveRange = GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE ).x;

						if ( m_aiRange[ aiRange ].x >= defensiveRange )
						{
							return Vector( ( defensiveRange - 0.1 ), ( defensiveRange - 0.1 ), ( defensiveRange - 0.1 ) );
						}
						return m_aiRange[ aiRange ];
					}
				}
			}
		}
		return Vector( ZOO_ANIMAL_DEFAULT_AI_RANGE, ZOO_ANIMAL_DEFAULT_AI_RANGE, ZOO_ANIMAL_DEFAULT_AI_RANGE );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the AI Range Offset. Note that even though this
//					data member is used exclusively for this class, we use the GET method
//					to check to make sure the AI Range was set properly.
// Input:		None ( void )
// Output:  AI Range Offset( float )
//-----------------------------------------------------------------------------

Vector CBaseZooAnimal::GetAIRangeOffset( int aiRangeOffset )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiRangeOffset )
		{
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE:
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT:
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
			case AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE:
			case AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY:
			case AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH:
			case AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH:
			{
				return m_aiRangeOffset[ aiRangeOffset ];
			}
			case AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH:
			{
				return Vector( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET ), 
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET ), 
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET ) );
			}

		}
		return Vector( ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET, ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET, ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET );
	}
	else
	{
		switch ( aiRangeOffset )
		{
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE:
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT:
			case AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE:
			case AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE:
			case AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE:
			case AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY:
			case AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH:
			case AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH:
			case AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH:
			{
				return m_aiRangeOffset[ aiRangeOffset ];
			}
		}
		return Vector( ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET, ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET, ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the Icon Think Time for the appropriate Icon. Note that even though this
//					data member is used exclusively for this class, we use the GET method
//					to check to make sure the "think time" was set properly.
// Input:		Icon ( int )
// Output:  Icon Time( float )
//-----------------------------------------------------------------------------

float CBaseZooAnimal::GetIconTime( int icon )
{
	if ( icon >= 0 && icon < ZOO_ANIMAL_MAX_ICONS )
	{
		if ( m_iconTime[ icon ] <= ZOO_ANIMAL_DEFAULT_ICON_TIME )
		{
			return ZOO_ANIMAL_DEFAULT_ICON_TIME;
		}
		return m_iconTime[ icon ];
	}
	return ZOO_ANIMAL_DEFAULT_ICON_TIME;
}

//-----------------------------------------------------------------------------
// Purpose: Get the AI Timer Think Time for the appropriate AI Timer. Note that even 
//					though this data member is used exclusively for this class, we use the GET method
//					to check to make sure the "think time" was set properly.
// Input:		AI Timer ( int )
// Output:  AI Timer Time( float )
//-----------------------------------------------------------------------------

float CBaseZooAnimal::GetAITimerThinkTime( int aiTimer )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiTimer )
		{
			case AI_TIMER_ZOO_ANIMAL_FLEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_FLEE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_FLEE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_START_FLEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_START_FLEE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_START_FLEE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_RAGE:
			{
				/*
				if ( bsg_zooanimal_ragetime->GetFloat() > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return bsg_zooanimal_ragetime->GetFloat();
				}
				*/
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION:
			{
				/*
				if ( bsg_zooanimal_ragetime->GetFloat() > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return bsg_zooanimal_ragetime->GetFloat();
				}
				*/
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_CHASE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHASE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHASE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHASE_EVAL_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHASE_EVAL_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_STUNNED:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_STUNNED_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_STUNNED_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_HEALTH_REGEN_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_HEALTH_REGEN_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_MELEE_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_MELEE_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_TRAP_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_PLAYER_TRAP_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_HURT:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_HURT_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_HURT_TIME );
				}
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE:
			{
				break;
			}

			case AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH:
			{
				if ( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_TIME ) > ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
				{
					return GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_TIME );
				}
				break;
			}
		}
		return ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
	}
	else
	{
		if ( aiTimer >= 0 && aiTimer < ZOO_ANIMAL_MAX_AI_TIMERS )
		{
			if ( m_aiTimerThinkTime[ aiTimer ] <= ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
			{
				return ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
			}
			else
			{
				switch ( aiTimer )
				{
					case AI_TIMER_ZOO_ANIMAL_FLEE:
					case AI_TIMER_ZOO_ANIMAL_START_FLEE:
					case AI_TIMER_ZOO_ANIMAL_RAGE:
					case AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION:
					case AI_TIMER_ZOO_ANIMAL_CHASE:
					case AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION:
					case AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE:
					case AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE:
					case AI_TIMER_ZOO_ANIMAL_STUNNED:
					case AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN:
					case AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE:
					case AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP:
					case AI_TIMER_ZOO_ANIMAL_HURT:
					case AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE:
					case AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH:
					{
						return m_aiTimerThinkTime[ aiTimer ];
					}
				}
			}
		}
		return ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the amount of Force to apply to the Player when the Player 
//					touches the NPC
// Input:		Type of Touch Force Type to apply ( int )
// Output:  Touche Force to apply FORWARD + RIGHT + UP ( Vector )
//-----------------------------------------------------------------------------

Vector CBaseZooAnimal::GetTouchForceOnPlayer( int aiTouchForceType )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiTouchForceType )
		{
			case AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY:
			{
				return Vector( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_F ),
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_R ),
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_U ) );
			}

			case AI_TOUCH_FORCE_PLAYER_TYPE_RAGE:
			{
				return Vector( GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_F ),
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_R ),
											 GetConVarFloat( AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_U ) );
			}
		}
		return Vector( 0.0f, 0.0f, 0.0f );
	}
	else
	{
		if ( aiTouchForceType >= 0 && aiTouchForceType < ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER )
		{
			return Vector( m_aiTouchForceOnPlayer[ aiTouchForceType ][ AI_TOUCH_FORCE_PLAYER_FORWARD ],
										 m_aiTouchForceOnPlayer[ aiTouchForceType ][ AI_TOUCH_FORCE_PLAYER_RIGHT ],
										 m_aiTouchForceOnPlayer[ aiTouchForceType ][ AI_TOUCH_FORCE_PLAYER_UP ] );
		}
		return Vector( 0.0f, 0.0f, 0.0f );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the amount of Damage ( Hits ) the Player applies to the NPC
// Input:		Type of Touch Force to apply: FORWARD or UP ( int )
// Output:  Touche Force to apply ( float )
//----------------------------------------------------------------------------

int CBaseZooAnimal::GetAIPlayerDamage( int aiPlayerDamage )
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		switch ( aiPlayerDamage )
		{
			case PLAYER_DAMAGE_ZOO_ANIMAL_TRAP:
			{
				return GetConVarInt( AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_TRAP );
			}

			case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1:
			{
				return GetConVarInt( AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_1 );
			}

			case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2:
			{
				return GetConVarInt( AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_2 );
			}

			case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3:
			{
				return GetConVarInt( AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_3 );
			}
		}
		return ZOO_ANIMAL_DEFAULT_PLAYER_DAMAGE;
	}
	else
	{
		if ( aiPlayerDamage >= 0 && aiPlayerDamage < ZOO_ANIMAL_MAX_PLAYER_DAMAGES )
		{
			if ( m_aiPlayerDamage[ aiPlayerDamage ] < ZOO_ANIMAL_DEFAULT_PLAYER_DAMAGE )
			{
				return ZOO_ANIMAL_DEFAULT_PLAYER_DAMAGE;
			}
			else
			{
				switch ( aiPlayerDamage )
				{
					case PLAYER_DAMAGE_ZOO_ANIMAL_TRAP:
					{
						return m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ];
					}

					case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1:
					{
						return m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ];
					}

					case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2:
					{
						return m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ];
					}

					case PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3:
					{
						return m_aiPlayerDamage[ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ];
					}
				}
			}
		}
		return ZOO_ANIMAL_DEFAULT_PLAYER_DAMAGE;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get AI Schedule Activity for current schedule
// Input:		None( void )
// Output:  AI Schedule Activity ( int )
//----------------------------------------------------------------------------

int	CBaseZooAnimal::GetAISchedAct()
{
	const char * currentSchedule = this->GetCurSchedule()->GetName();

	char testSchedule1 [] = "SCHED_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH";

	if ( strcmp( currentSchedule, testSchedule1 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH;
	}

	char testSchedule2 [] = "SCHED_ZOO_ANIMAL_NEUTRAL_COOLDOWN";

	if ( strcmp( currentSchedule, testSchedule2 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_COOLDOWN;
	}

	char testSchedule3 [] = "SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER";

	if ( strcmp( currentSchedule, testSchedule3 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER;
	}

	char testSchedule4 [] = "SCHED_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER";

	if ( strcmp( currentSchedule, testSchedule4 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER;
	}

	char testSchedule5 [] = "SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY";

	if ( strcmp( currentSchedule, testSchedule5 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY;
	}

	char testSchedule6 [] = "SCHED_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER";

	if ( strcmp( currentSchedule, testSchedule6 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER;
	}

	char testSchedule7 [] = "SCHED_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER";

	if ( strcmp( currentSchedule, testSchedule7 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER;
	}

	char testSchedule8 [] = "SCHED_ZOO_ANIMAL_STUNNED";

	if ( strcmp( currentSchedule, testSchedule8 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_STUNNED;
	}

	char testSchedule9 [] = "SCHED_ZOO_ANIMAL_HURT";

	if (  strcmp( currentSchedule, testSchedule9 ) == 0 )
	{
		return AI_SCHED_ACT_ZOO_ANIMAL_HURT;
	}
	return AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH;
}

//-----------------------------------------------------------------------------
// Purpose: Check if AI Pre-Activity is Locked and get it if it is NOT Locked 
//					and NOT INVALID
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  AI Pre-Activity ( int )
//----------------------------------------------------------------------------

int CBaseZooAnimal::GetAIPreAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		if ( m_aiLockPreActivity[ aiSchedule ][ aiAct ] ||
				 m_aiPreActivity[ aiSchedule ][ aiAct ] == ACT_INVALID )
		{
			return ACT_INVALID;
		}
		else
		{
			return m_aiPreActivity[ aiSchedule ][ aiAct ];
		}
	}
	return ACT_INVALID;
}

//-----------------------------------------------------------------------------
// Purpose: Check if AI Post-Activity is Locked and get it if it is NOT Locked 
//					and NOT INVALID
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  AI Post-Activity ( int )
//----------------------------------------------------------------------------

int CBaseZooAnimal::GetAIPostAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		if ( m_aiLockPostActivity[ aiSchedule ][ aiAct ] ||
				 m_aiPostActivity[ aiSchedule ][ aiAct ] == ACT_INVALID )
		{
			return ACT_INVALID;
		}
		else
		{
			return m_aiPostActivity[ aiSchedule ][ aiAct ];
		}
	}
	return ACT_INVALID;
}

//-----------------------------------------------------------------------------
// Purpose: Lock the inputed AI Pre-Activity
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  None ( void )
//----------------------------------------------------------------------------

void CBaseZooAnimal::LockAIPreAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		m_aiLockPreActivity[ aiSchedule ][ aiAct ] = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Lock the inputed AI Post-Activity
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  None ( void )
//----------------------------------------------------------------------------

void CBaseZooAnimal::LockAIPostAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		m_aiLockPostActivity[ aiSchedule ][ aiAct ] = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: UnLock the inputed AI Pre-Activity
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  None ( void )
//----------------------------------------------------------------------------

void	CBaseZooAnimal::UnLockAIPreAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		m_aiLockPreActivity[ aiSchedule ][ aiAct ] = false;
	}
}

//-----------------------------------------------------------------------------
// Purpose: UnLock the inputed AI Post-Activity
// Input:		Current AI Schedule ( int ), Current AI Activity ( int )
// Output:  None ( void )
//----------------------------------------------------------------------------

void	CBaseZooAnimal::UnLockAIPostAct( int aiSchedule, int aiAct )
{
	if ( aiSchedule >= 0 && aiSchedule < ZOO_ANIMAL_MAX_AI_SCHED_ACTS &&
			 aiAct >= 0 && aiAct < ZOO_ANIMAL_MAX_AI_ACTS )
	{
		m_aiLockPostActivity[ aiSchedule ][ aiAct ] = false;
	}
}

void CBaseZooAnimal::ToggleAllAIPreAct( bool toggle )
{
	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_SCHED_ACTS; i++ )
	{
		for ( int j = 0; j < ZOO_ANIMAL_MAX_AI_ACTS; j++ )
		{
			m_aiLockPreActivity[ i ][ j ] = toggle;
		}
	}
}

void CBaseZooAnimal::ToggleAllAIPostAct( bool toggle )
{
	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_SCHED_ACTS; i++ )
	{
		for ( int j = 0; j < ZOO_ANIMAL_MAX_AI_ACTS; j++ )
		{
			m_aiLockPostActivity[ i ][ j ] = toggle;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Check the distance between the Player and Self (Zoo Animal). If
//					Self is within the distance specified, then
//					return TRUE.
// Input:		Distance ( float )
// Output:  ( TRUE or FALSE )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::EvalPlayerSelfProximity( Vector offset, Vector dist, int collisionType )
{
	Vector forward, zero;

	AngleVectors( this->GetAbsAngles(), &forward );
	zero.Init( 0.0f, 0.0f, 0.0f );

	return ( m_PlayerSelfProxTester.Check( GetPlayer(), zero, zero, this, offset, forward, dist, collisionType ) );
}

//-----------------------------------------------------------------------------
// Purpose: Check if the Icon Timer has expired for the appropriate Icon
// Input	:	Icon ( int )
// Ouput	: ( TRUE or FALSE )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::IsIconWaitTimeFinished( int icon )
{
	return ( gpGlobals->curtime >= m_iconWaitTime[ icon ] );
}

//-----------------------------------------------------------------------------
// Purpose: Check if the AI Timer has expired for the appropriate AI Timer
// Input	:	AI Timer ( int )
// Ouput	: ( TRUE or FALSE )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::IsAITimerWaitThinkTimeFinished( int aiTimer )
{
	return ( gpGlobals->curtime >= m_aiTimerWaitThinkTime[ aiTimer ] );
}

//-----------------------------------------------------------------------------
// Purpose: Check if the npc is stunned
// Input	:	None ( void )
// Ouput	: ( TRUE or FALSE )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::IsStunned()
{
	return ( m_nCurrentHitCount == HIT_COUNT_ZOO_ANIMAL_ZERO );
}

//-----------------------------------------------------------------------------
// Purpose: Check if the npc is invincible
// Input	:	None ( void )
// Ouput	: ( TRUE or FALSE )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::IsInvincible()
{
	return m_bIsHurt;
}

//-----------------------------------------------------------------------------
// Purpose: Set the Icon Time for the appropriate icon. Note the inputed time used 
//					to set the wait time. The wait time is a time measured in engine.
// Input:		Icon ( int ), Icon Time ( float )
// Outpu:		None ( void ) 
//-----------------------------------------------------------------------------

void CBaseZooAnimal::SetIconWaitTime( int icon, float iconTime )
{
	if ( icon >= 0 && icon < ZOO_ANIMAL_MAX_ICONS )
	{
		if ( iconTime >= ( INT_MAX/10 ) )
		{
			m_iconWaitTime[ icon ] = FLT_MAX;
		}
		else
		{
			int		minThinks					= Ceil2Int( iconTime * 10 );
			m_iconWaitTime[ icon ]	= gpGlobals->curtime + ( 0.1 * minThinks );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Set the AI Timer Time for the appropriate AI Timer. Note the inputed time used to set the
//					wait time. The wait time is a time measured in engine.
// Input:		AI Timer ( int ), AI Timer Time ( float )
// Outpu:		None ( void ) 
//-----------------------------------------------------------------------------

void CBaseZooAnimal::SetAITimerWaitThinkTime( int aiTimer, float aiTimerTime )
{
	if ( aiTimer >= 0 && aiTimer < ZOO_ANIMAL_MAX_AI_TIMERS )
	{
		if ( aiTimerTime >= ( INT_MAX/10 ) )
		{
			m_aiTimerWaitThinkTime[ aiTimer ] = FLT_MAX;
		}
		else
		{
			int		minThinks										= Ceil2Int( aiTimerTime * 10 );
			m_aiTimerWaitThinkTime[ aiTimer ]	= gpGlobals->curtime + ( 0.1 * minThinks );
		}
	}
}

void CBaseZooAnimal::SetAIState( int aiState )
{
	if ( aiState >= 0 && aiState < ZOO_ANIMAL_MAX_AI_STATES )
	{
		m_nZooAnimalAIState = aiState;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Set the Icon Wait Time for the appropriate Icon to the Max value so
//					this time can never be reached.
// Input:		Icon ( int )
// Output:	None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::ClearIconWaitTime( int icon )
{
	m_iconWaitTime[ icon ] = FLT_MAX;
}

//-----------------------------------------------------------------------------
// Purpose: Set the AI Timer Wait Time for the appropriate AI Timer to the Max value so
//					this time can never be reached.
// Input:		AI Timer ( int )
// Output:	None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::ClearAITimerWaitThinkTime( int aiTimer )
{
	m_aiTimerWaitThinkTime[ aiTimer ] = FLT_MAX;
}

//-----------------------------------------------------------------------------
// Purpose: Check if the Player is within a specified distance of the NPC. If it is,
//					apply a force to the Player in the opposite direction the Player is facing.
// Input:		Entity ( pOther ), Distance ( dist ), Offset ( offset ), Touch Force Type ( aiTouchForceType )
// Output:	None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::TouchRange( CBaseEntity *pOther )
{
	for ( int i = 0; i <= ZOO_ANIMAL_MAX_TYPE_TOUCH_FORCE_ON_PLAYER; i++ )
	{
		switch ( i )
		{
			case AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY:
			{
				if ( m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ] )
				{
					Vector zero, dist;

					zero.Init( 0.0f, 0.0f, 0.0f );

					dist = GetAIRange( AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH );

					if ( m_PlayerSelfProxTester.Check( pOther, zero, zero, this, zero, zero, dist, ZOO_ANIMAL_SPHERICAL_COLLISION ) )
					{
						//Touch( GetPlayer() );

						// HACK for now
							
						Vector forward, right, up, force;

						force = GetTouchForceOnPlayer( AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY );
						
   						//AngleVectors( pOther->GetLocalAngles(), &forward, &right, &up );
						//GetPlayer()->ApplyAbsVelocityImpulse( ( forward * ( force.x ) ) + 
						//										( right * ( force.y ) ) +
						//										( up * ( force.z ) ) );
						Vector playerPos = GetPlayer()->GetAbsOrigin();
						Vector animalPos = this->GetAbsOrigin();
						Vector dirVec = playerPos - animalPos;

						dirVec /= ( dirVec.Length() != 0 ) ? dirVec.Length() : 1;

						dirVec.x *= force.x;
						dirVec.y *= force.y;
						dirVec.z = force.z;

						GetPlayer()->ApplyAbsVelocityImpulse( dirVec );
					}
				}
				break;
			}

			case AI_TOUCH_FORCE_PLAYER_TYPE_RAGE:
			{
				if ( m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] )
				{
					Vector zero, dist, offset, forward;

					zero.Init( 0.0f, 0.0f, 0.0f );

					dist		= GetAIRange( AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH );
					offset	= GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_RAGE_TOUCH );

					AngleVectors( this->GetLocalAngles(), &forward );

					if ( m_PlayerSelfProxTester.Check( pOther, zero, zero, this, offset, forward, dist, ZOO_ANIMAL_SPHERICAL_COLLISION ) )
					{
						//Touch( GetPlayer() );

						// HACK for now
							
						Vector right, up, force;

						force = GetTouchForceOnPlayer( AI_TOUCH_FORCE_PLAYER_TYPE_RAGE );
						
   						//AngleVectors( pOther->GetLocalAngles(), &forward, &right, &up );
						//GetPlayer()->ApplyAbsVelocityImpulse( ( forward * ( force.x ) ) + 
						//										( right * ( force.y ) ) +
						//										( up * ( force.z ) ) );

						Vector playerPos = GetPlayer()->GetAbsOrigin();
						Vector animalPos = this->GetAbsOrigin();
						Vector dirVec = playerPos - animalPos;

						dirVec /= ( dirVec.Length() != 0 ) ? dirVec.Length() : 1;

						dirVec.x *= force.x;
						dirVec.y *= force.y;
						dirVec.z = force.z;

						GetPlayer()->ApplyAbsVelocityImpulse( dirVec );

						CTakeDamageInfo info( this, this, GetAIDamage( AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE ), DMG_DROWN );
 						GetPlayer()->TakeDamage( info );
					}
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Play a specified sound for the NPC
// Input:		Sound to Play ( aiSound )
// Output:	None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::PlayZooAnimalSound( int aiSound )
{
	if ( aiSound >= 0 && aiSound < ZOO_ANIMAL_MAX_AI_SOUNDS && m_pSounds[ aiSound ] != NULL )
	{
		EmitSound( m_pSounds[ aiSound ] );	
	}
}

//-----------------------------------------------------------------------------
// Purpose: Reset the npcs "Health"
// Input:		None ( void )
// Ouput:		None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::ResetHitCount()
{
	if ( bsg_zooanimal_debug.GetInt() )
	{
		m_nCurrentHitCount = ( GetConVarInt( AI_CONVAR_ZOO_ANIMAL_MAX_HIT_COUNT ) <= HIT_COUNT_ZOO_ANIMAL_ONE ) ? HIT_COUNT_ZOO_ANIMAL_ONE : GetConVarInt( AI_CONVAR_ZOO_ANIMAL_MAX_HIT_COUNT );
	}
	else
	{
		m_nCurrentHitCount = ( m_nMaxHitCount < HIT_COUNT_ZOO_ANIMAL_ONE ) ? HIT_COUNT_ZOO_ANIMAL_ONE : m_nMaxHitCount;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Get the npc's current "Health"
// Input:		None ( void )
// Ouput:		Current NPC Health ( int )
//-----------------------------------------------------------------------------

int CBaseZooAnimal::GetHitCount()
{
	return m_nCurrentHitCount;
}

//-----------------------------------------------------------------------------
// Purpose: Get the npc's current State
// Input:		None ( void )
// Ouput:		Current NPC State ( int )
//-----------------------------------------------------------------------------

int CBaseZooAnimal::GetAIState()
{
	return m_nZooAnimalAIState;
}

//-----------------------------------------------------------------------------
// Purpose: Get the npc's type
// Input:		None ( void )
// Ouput:		NPC Type ( int )
//-----------------------------------------------------------------------------

int CBaseZooAnimal::GetAIType()
{
	return m_nZooAnimalAIType;
}

//-----------------------------------------------------------------------------
// Purpose: Determine if the Player should damage the NPC based on its state
// Input:		NPC's State ( int ), Player Damage Type ( int )
// Ouput:		Damage NPC? ( bool )
//-----------------------------------------------------------------------------

bool CBaseZooAnimal::GetAIPlayerStateDamage( int aiState, int aiPlayerDamage )
{
	if ( 0 < aiState && aiState < ZOO_ANIMAL_MAX_AI_STATES &&
			 0 < aiPlayerDamage && aiPlayerDamage < ZOO_ANIMAL_MAX_PLAYER_DAMAGES )
	{
		return m_pAIPlayerStateDamage[ aiState ][ aiPlayerDamage ];
	}
	return true;
}

//-----------------------------------------------------------------------------
// Purpose: Decrement the npc's "Health" by hits
// Input:		Amount of Hits to Decrement ( int )
// Ouput:		None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::DecrementHitCount( int hits )
{
	m_nCurrentHitCount -= hits;

	if ( m_nCurrentHitCount < HIT_COUNT_ZOO_ANIMAL_ZERO )
	{
		m_nCurrentHitCount = HIT_COUNT_ZOO_ANIMAL_ZERO;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Init Icons
// Input:		None ( void )
// Ouput:		None ( void )
//-----------------------------------------------------------------------------

void CBaseZooAnimal::InitIcons()
{
	const Vector	&	originZooAnimal	= this->GetAbsOrigin();
	Vector					originIcon;

	for ( int i = 0; i < ZOO_ANIMAL_MAX_ICONS; i++ )
	{
		if ( m_icons[ i ] != NULL_STRING )
		{
			originIcon			= originZooAnimal;
			originIcon.z	 += m_flIconVerticalDisplacment;
			//originIcon.z	  += GetHullMaxs().z + m_flIconVerticalDisplacment;
 
			m_pIcon[ i ] = dynamic_cast< CDynamicProp * >( CreateEntityByName( "dynamic_prop" ) );
			//m_pIcon[ i ] = dynamic_cast< CSprite * >( CreateEntityByName( "env_sprite" ) );

			//m_pIcon[i]->SetModel( STRING( m_icons[i] ) );
			m_pIcon[ i ]->SetModel( STRING( m_icons[i] ) );
			m_pIcon[ i ]->SetAbsOrigin( originIcon );
			m_pIcon[ i ]->SetAbsAngles( this->GetAbsAngles() );
			m_pIcon[ i ]->SetParent( this );
			//m_pIcon[i]->m_bStartDisabled = false;
			m_pIcon[ i ]->AddSpawnFlags( 1 );
			m_pIcon[ i ]->SetRenderMode( kRenderWorldGlow );

			DispatchSpawn( m_pIcon[i] );
			m_pIcon[ i ]->Activate();
			m_pIcon[ i ]->AddEffects( EF_NODRAW );
		}
		else
		{
			m_pIcon[ i ] = NULL;
		}
	}

	// small HACK 

	inputdata_t iconDazed;
	iconDazed.value.SetString( MAKE_STRING( "idle" ) );

	m_pIcon[ ICON_ZOO_ANIMAL_DAZED ]->InputSetAnimation( iconDazed );

	//m_pIcon[ICON_ZOO_ANIMAL_PASSIVE]->SetRenderColor( 0,   255, 0 );		// green
	//m_pIcon[ICON_ZOO_ANIMAL_ALERT]->SetRenderColor( 255, 255, 0 );		// yellow
	//m_pIcon[ICON_ZOO_ANIMAL_ANGRY]->SetRenderColor( 255, 0,   0 );		// red
	//m_pIcon[ICON_ZOO_ANIMAL_FEAR]->SetRenderColor( 0,   0,   255 );		// blue
	//m_pIcon[ICON_ZOO_ANIMAL_DAZED]->SetRenderColor( 255, 165, 0 );		// orange
	//m_pIcon[ICON_ZOO_ANIMAL_CONFUSED]->SetRenderColor( 160, 32,  240 );	// purple
}

void CBaseZooAnimal::TurnOnIcon( int icon )
{
	if ( icon >= 0 && icon < ZOO_ANIMAL_MAX_ICONS && m_pIcon[ icon ] != NULL )
	{
		m_pIcon[ icon ]->RemoveEffects( EF_NODRAW );
	}
}

void CBaseZooAnimal::TurnOffIcon( int icon )
{
	if ( icon >= 0 && icon < ZOO_ANIMAL_MAX_ICONS && m_pIcon[ icon ] != NULL )
	{
		m_pIcon[ icon ]->AddEffects( EF_NODRAW );
	}
}

void CBaseZooAnimal::ChangeIcon( int icon )
{
	if ( icon >= 0 && icon < ZOO_ANIMAL_MAX_ICONS && m_nCurrentIcon != icon )
	{
		TurnOffIcon( m_nCurrentIcon );
		ClearIconWaitTime( m_nCurrentIcon );

		m_nCurrentIcon = icon;

		TurnOnIcon( m_nCurrentIcon );
		SetIconWaitTime( m_nCurrentIcon, GetIconTime( m_nCurrentIcon ) );
	}
}

int CBaseZooAnimal::GetConVarInt( int conVar )
{
	switch ( m_nZooAnimalAIType )
	{
		case AI_TYPE_ZOO_ANIMAL_MONKEY:
		{
			switch ( conVar )
			{
				case AI_CONVAR_ZOO_ANIMAL_MAX_HIT_COUNT:
					return bsg_monkey_maxhitcount.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_HURT_FLICKER_RATE:
					return bsg_monkey_hurtflickerrate.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_TRAP:
					return bsg_monkey_playerdmgtrap.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_1:
					return bsg_monkey_playerdmgbag1.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_2:
					return bsg_monkey_playerdmgbag2.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_3:
					return bsg_monkey_playerdmgbag3.GetInt();
			}
		}

		case AI_TYPE_ZOO_ANIMAL_BIRD:
		{
			switch ( conVar )
			{
				case AI_CONVAR_ZOO_ANIMAL_MAX_HIT_COUNT:
					return bsg_bird_maxhitcount.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_HURT_FLICKER_RATE:
					return bsg_bird_hurtflickerrate.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_TRAP:
					return bsg_bird_playerdmgtrap.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_1:
					return bsg_bird_playerdmgbag1.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_2:
					return bsg_bird_playerdmgbag2.GetInt();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_DAMAGE_BAG_3:
					return bsg_bird_playerdmgbag3.GetInt();
			}
		}
	}
	return 0;
}

float CBaseZooAnimal::GetConVarFloat( int conVar )
{
	switch ( m_nZooAnimalAIType )
	{
		case AI_TYPE_ZOO_ANIMAL_MONKEY:
		{
			switch ( conVar )
			{
				case AI_CONVAR_ZOO_ANIMAL_FLEE_TIME:
					return bsg_monkey_fleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHASE_TIME:
					return bsg_monkey_chasetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHASE_EVAL_TIME:
					return bsg_monkey_chaseevaltime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_TIME:
					return bsg_monkey_aggmeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_TIME:
					return bsg_monkey_defmeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_STUNNED_TIME:
					return bsg_monkey_stunnedtime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_HEALTH_REGEN_TIME:
					return bsg_monkey_healthregentime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_MELEE_TIME:
					return bsg_monkey_playermeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_TRAP_TIME:
					return bsg_monkey_playertraptime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_HURT_TIME:
					return bsg_monkey_hurttime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_TIME:
					return bsg_monkey_changefleepathtime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_RANGE:
					return bsg_monkey_defrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_RANGE:
					return bsg_monkey_aggrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE:
					return bsg_monkey_defmeleerange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE:
					return bsg_monkey_aggmeleerange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT_RANGE:
					return bsg_monkey_defmeleehitrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT_RANGE:
					return bsg_monkey_aggmeleehitrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_RANGE:
					return bsg_monkey_changefleepathrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET:
					return bsg_monkey_changefleepathoff.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_TOUCH_RANGE:
					return bsg_monkey_playertouchrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_DAMAGE:
					return bsg_monkey_defmeleedmg.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE:
					return bsg_monkey_aggmeleedmg.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_F:
					return bsg_monkey_touchforceonplayerproxf.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_R:
					return bsg_monkey_touchforceonplayerproxr.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_U:
					return bsg_monkey_touchforceonplayerproxu.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_F:
					return bsg_monkey_touchforceonplayerragef.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_R:
					return bsg_monkey_touchforceonplayerrager.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_U:
					return bsg_monkey_touchforceonplayerrageu.GetFloat();
			}
		}

		case AI_TYPE_ZOO_ANIMAL_BIRD:
		{
			switch ( conVar )
			{
				case AI_CONVAR_ZOO_ANIMAL_FLEE_TIME:
					return bsg_bird_fleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHASE_TIME:
					return bsg_bird_chasetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHASE_EVAL_TIME:
					return bsg_bird_chaseevaltime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_TIME:
					return bsg_bird_aggmeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_TIME:
					return bsg_bird_defmeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_STUNNED_TIME:
					return bsg_bird_stunnedtime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_HEALTH_REGEN_TIME:
					return bsg_bird_healthregentime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_MELEE_TIME:
					return bsg_bird_playermeleetime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_TRAP_TIME:
					return bsg_bird_playertraptime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_HURT_TIME:
					return bsg_bird_hurttime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_TIME:
					return bsg_bird_changefleepathtime.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_RANGE:
					return bsg_bird_defrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_RANGE:
					return bsg_bird_aggrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_RANGE:
					return bsg_bird_defmeleerange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_RANGE:
					return bsg_bird_aggmeleerange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT_RANGE:
					return bsg_bird_defmeleehitrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT_RANGE:
					return bsg_bird_aggmeleehitrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_RANGE:
					return bsg_bird_changefleepathrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_CHANGE_FLEE_PATH_OFFSET:
					return bsg_bird_changefleepathoff.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_PLAYER_TOUCH_RANGE:
					return bsg_bird_playertouchrange.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_DEFENSIVE_MELEE_DAMAGE:
					return bsg_bird_defmeleedmg.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_AGGRESSIVE_MELEE_DAMAGE:
					return bsg_bird_aggmeleedmg.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_F:
					return bsg_bird_touchforceonplayerproxf.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_R:
					return bsg_bird_touchforceonplayerproxr.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_PROXIMITY_U:
					return bsg_bird_touchforceonplayerproxu.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_F:
					return bsg_bird_touchforceonplayerragef.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_R:
					return bsg_bird_touchforceonplayerrager.GetFloat();
				case AI_CONVAR_ZOO_ANIMAL_TOUCH_FORCE_ON_PLAYER_RAGE_U:
					return bsg_bird_touchforceonplayerrageu.GetFloat();
			}
		}
	}
	return 0.0f;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------

void CBaseZooAnimal::Spawn( void )
{
	int aiType = GetAIType();

	//SetHullType( HULL_HUMAN );
	//SetHullSizeNormal();
	//SetCollisionGroup( HL2COLLISION_GROUP_ANTLION );

	SetSolid( SOLID_BBOX );
	//AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_STEP );

	//SetCollisionGroup( HL2COLLISION_GROUP_HEADCRAB );

	SetBloodColor( DONT_BLEED );
	m_flFieldOfView		= 0.5;
	m_NPCState				= NPC_STATE_NONE;

	CapabilitiesClear();
	CapabilitiesAdd( bits_CAP_MOVE_GROUND );

	// We can change this later, its here for consistency

	m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ]	= 2 * m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_CHASE ]; 

	if ( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT ] <= 0 )
	{
		m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT ] = ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
	}

	m_nHurtFlickerRate = ( m_nHurtFlickerRate <= 0 ) ? 1 : m_nHurtFlickerRate;

	m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ] = m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT ] / ( m_nHurtFlickerRate + 1 );

	if ( m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ] <= ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME )
	{
		m_aiTimerThinkTime[ AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ] = ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME;
	}

	bool allPathNull = true;

	// Check if no Path was set for the Path List

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
	{
		if ( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][ i ] != NULL_STRING )
		{
			allPathNull = false;
			break;
		}
	}

	m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][ 0 ] = ( allPathNull ) ? m_target : m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][ 0 ];

	allPathNull = true;

	// Check if no Flee Path was set for the Flee Path List

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
	{
		if ( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][ i ] != NULL_STRING )
		{
			allPathNull = false;
			break;
		}
	}

	m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][ 0 ] = ( allPathNull ) ? m_target : m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ][ 0 ];

	allPathNull = true;

	// Check if no Alt Flee Path was set for the Alt Flee Path List

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
	{
		if ( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][ i ] != NULL_STRING )
		{
			allPathNull = false;
			break;
		}
	}

	m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][ 0 ] = ( allPathNull ) ? m_target : m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ][ 0 ];

	allPathNull = true;

	// Check if no Rage Path was set for the Rage Path List

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
	{
		if ( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][ i ] != NULL_STRING )
		{
			allPathNull = false;
			break;
		}
	}

	m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][ 0 ] = ( allPathNull ) ? m_target : m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ][ 0 ];

	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_RANGES; i++ )
	{
		m_aiRange[ i ].y = m_aiRange[ i ].x;
		m_aiRange[ i ].z = m_aiRange[ i ].x;
	}

	m_aiRange[ AI_RANGE_ZOO_ANIMAL_PLAYER_TOUCH ].z = fabs( GetHullMaxs().z - GetHullMins().z ) * 0.75f;

	for ( int i = 0; i < ZOO_ANIMAL_DEFAULT_AI_RANGE_OFFSET; i++ )
	{
		m_aiRangeOffset[ i ].y = m_aiRangeOffset[ i ].x;
		m_aiRangeOffset[ i ].z = m_aiRangeOffset[ i ].x;
	}

	Precache();

	switch ( aiType )
	{
		case AI_TYPE_ZOO_ANIMAL_MONKEY:
			SetModel( "models/monkey/monkey.mdl" );
			break;
		case AI_TYPE_ZOO_ANIMAL_BIRD:
			SetModel( "models/oddbob/oddbob.mdl" );
			break;
		case AI_TYPE_ZOO_ANIMAL_WALRUS:
			SetModel( "models/rumpus/rumpus.mdl" );
			break;
	}

	NPCInit();
	InitIcons();
}

//-----------------------------------------------------------------------------
// Purpose: Precaches all resources this monster needs.
//-----------------------------------------------------------------------------
void CBaseZooAnimal::Precache( void )
{
	int aiType = GetAIType();

	switch ( aiType )
	{
		case AI_TYPE_ZOO_ANIMAL_MONKEY:
			// Sounds

			PrecacheScriptSound( "NPC_Monkey.Attack" );
			PrecacheScriptSound( "NPC_Monkey.Dazed" );
			PrecacheScriptSound( "NPC_Monkey.Damaged" );
			PrecacheScriptSound( "NPC_Monkey.Runaway" );
			PrecacheScriptSound( "NPC_Monkey.Angry" );

			m_pSounds[ AI_SOUND_ZOO_ANIMAL_FLEE ]			= MAKE_STRING( "NPC_Monkey.Runaway" ).ToCStr(); 
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_ANGRY ]			= MAKE_STRING( "NPC_Monkey.Angry" ).ToCStr();
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_DAZED ]			= MAKE_STRING( "NPC_Monkey.Dazed" ).ToCStr();
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK ]	= MAKE_STRING( "NPC_Monkey.Attack" ).ToCStr(); 
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_HURT ]			= MAKE_STRING( "NPC_Monkey.Damaged" ).ToCStr();

			// Models

			//PrecacheModel( "gui/sprites/exclamation.vmt" );
			//PrecacheModel( "gui/sprites/batskull.vmt" );
			PrecacheModel( "models/daze/daze.mdl" );
			PrecacheModel( "models/monkey/monkey.mdl" );
			break;
		case AI_TYPE_ZOO_ANIMAL_BIRD:
			// Sounds

			PrecacheScriptSound( "NPC_Bird.Attack" );
			PrecacheScriptSound( "NPC_Bird.Dazed" );
			PrecacheScriptSound( "NPC_Bird.Damaged" );
			PrecacheScriptSound( "NPC_Bird.Runaway" );

			m_pSounds[ AI_SOUND_ZOO_ANIMAL_FLEE ]			= MAKE_STRING( "NPC_Bird.Runaway" ).ToCStr(); 
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_ANGRY ]			= NULL;
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_DAZED ]			= MAKE_STRING( "NPC_Bird.Dazed" ).ToCStr();
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK ]	= MAKE_STRING( "NPC_Bird.Attack" ).ToCStr(); 
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_HURT ]			= MAKE_STRING( "NPC_Bird.Damaged" ).ToCStr();

			// Models

			//PrecacheModel( "gui/sprites/exclamation.vmt" );
			//PrecacheModel( "gui/sprites/batskull.vmt" );
			PrecacheModel( "models/daze/daze.mdl" );
			PrecacheModel( "models/oddbob/oddbob.mdl" );
			break;
		case AI_TYPE_ZOO_ANIMAL_WALRUS:
			// Sounds

			PrecacheScriptSound( "NPC_Walrus.Idle" );
			PrecacheScriptSound( "NPC_Walrus.Angry" );
			PrecacheScriptSound( "NPC_Walrus.Dazed" );
			PrecacheScriptSound( "NPC_Walrus.Attack" );
			PrecacheScriptSound( "NPC_Walrus.Damaged" );

			m_pSounds[ AI_SOUND_ZOO_ANIMAL_FLEE ]			= MAKE_STRING( "NPC_Walrus.Idle" ).ToCStr(); // IDLE
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_ANGRY ]			= MAKE_STRING( "NPC_Walrus.Angry" ).ToCStr(); // STARTUP
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_DAZED ]			= MAKE_STRING( "NPC_Walrus.Dazed" ).ToCStr(); 
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK ]	= MAKE_STRING( "NPC_Walrus.Attack" ).ToCStr(); // CHARGE
			m_pSounds[ AI_SOUND_ZOO_ANIMAL_HURT ]			= MAKE_STRING( "NPC_Walrus.Damaged" ).ToCStr();

			// Models

			//PrecacheModel( "gui/sprites/exclamation.vmt" );
			//PrecacheModel( "gui/sprites/batskull.vmt" );
			PrecacheModel( "models/daze/daze.mdl" );
			PrecacheModel( "models/rumpus/rumpus.mdl" );
			break;
	}

	BaseClass::Precache();
}	

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : NewActivity - 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::OnChangeActivity( Activity NewActivity )
{
	bool fRandomize = false;
	float flRandomRange = 0.0;

	// If this crab is starting to walk or idle, pick a random point within
	// the animation to begin. This prevents lots of crabs being in lockstep.
	if ( NewActivity == ACT_IDLE )
	{
		flRandomRange = 0.75;
		fRandomize = true;
	}
	else if ( NewActivity == ACT_RUN )
	{
		flRandomRange = 0.25;
		fRandomize = true;
	}

	BaseClass::OnChangeActivity( NewActivity );

	if( fRandomize )
	{
		SetCycle( random->RandomFloat( 0.0, flRandomRange ) );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Indicates this monster's place in the relationship table.
// Output : 
//-----------------------------------------------------------------------------
Class_T	CBaseZooAnimal::Classify( void )
{
	return( CLASS_ZOO_ANIMAL ); 
}

//-----------------------------------------------------------------------------
// Purpose: Allows each sequence to have a different turn rate associated with it.
// Output : float
//-----------------------------------------------------------------------------
float CBaseZooAnimal::MaxYawSpeed( void )
{
	return BaseClass::MaxYawSpeed();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseZooAnimal::MoveOrigin( const Vector &vecDelta )
{
	UTIL_SetOrigin( this, GetLocalOrigin() + vecDelta );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::ThrowThink( void )
{
	if (gpGlobals->curtime > m_flNextNPCThink)
	{
		NPCThink();
		m_flNextNPCThink = gpGlobals->curtime + 0.1;
	}

	if( GetFlags() & FL_ONGROUND )
	{
		SetThink( &CBaseZooAnimal::CallNPCThink );
		SetNextThink( gpGlobals->curtime + 0.1 );
		return;
	}

	SetNextThink( gpGlobals->curtime );
}

//-----------------------------------------------------------------------------
// Purpose: Catches the monster-specific messages that occur when tagged
//			animation frames are played.
// Input  : *pEvent - 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::HandleAnimEvent( animevent_t *pEvent )
{
	switch ( pEvent->event )
	{
		case AE_ZOO_ANIMAL_MELEE_ATTACK:
		{
			// Does no damage, because damage is applied based upon whether the target can handle the interaction
			
			float		flDist		= 0.0f;

			int			aiState		= GetAIState();
			int			aiDamage	= 0;

			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				{
					flDist		= GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE_HIT ).x; 
					aiDamage	= GetAIDamage( AI_DAMAGE_ZOO_ANIMAL_DEFENSIVE_MELEE );
					break;
				}

				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					flDist		= GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE_HIT ).x;
					aiDamage	= GetAIDamage( AI_DAMAGE_ZOO_ANIMAL_AGGRESSIVE_MELEE );
					break;
				}
			}

			const		Vector mins		=  -Vector( 16, 16, 16 ); 
			const		Vector maxs		=  Vector( 16, 16, 16);
			int			iDamage				= 0; 
			int			iDmgType			= DMG_DROWN; 
			float		forceScale		= 1.0f; 
			bool		bDamageAnyNPC = true;

			// If only a length is given assume we want to trace in our facing direction

			Vector forward;
			AngleVectors( GetAbsAngles(), &forward );
			Vector vStart = GetAbsOrigin();

			// The ideal place to start the trace is in the center of the attacker's bounding box.
			// however, we need to make sure there's enough clearance. Some of the smaller monsters aren't 
			// as big as the hull we try to trace with. (SJB)

			float flVerticalOffset = WorldAlignSize().z * 0.5;

			if( flVerticalOffset < maxs.z )
			{
				// There isn't enough room to trace this hull, it's going to drag the ground.
				// so make the vertical offset just enough to clear the ground.
				flVerticalOffset = maxs.z + 1.0;
			}

			vStart.z += flVerticalOffset;
			Vector vEnd = vStart + (forward * flDist );

			CTakeDamageInfo	dmgInfo( this, this, iDamage, iDmgType );
	
			CTraceFilterMelee traceFilter( this, COLLISION_GROUP_NONE, &dmgInfo, forceScale, bDamageAnyNPC );

			Ray_t ray;
			ray.Init( vStart, vEnd, mins, maxs );

			trace_t tr;
			enginetrace->TraceRay( ray, MASK_SHOT_HULL, &traceFilter, &tr );

			CBaseEntity *pHurt = traceFilter.m_pHit;
			
			if ( pHurt != NULL )
			{
				CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pHurt );
   			if (pBCC)
   			{
   				Vector forward, up;
   				AngleVectors( GetLocalAngles(), &forward, NULL, &up );
	   
   				if ( !pBCC->DispatchInteraction( g_interactionZooAnimalMelee, NULL, this ) )
   				{
						if ( pBCC->IsPlayer() )
						{
  						pBCC->ViewPunch( QAngle(-12,-7,0) );
  						pHurt->ApplyAbsVelocityImpulse( forward * 100 + up * 50 );
						}
	  
  				CTakeDamageInfo info( this, this, aiDamage, DMG_DROWN );
 					CalculateMeleeDamageForce( &info, forward, pBCC->GetAbsOrigin() );
 					pBCC->TakeDamage( info );
	
  				//EmitSound( "NPC_Combine.WeaponBash" );
  				}
  			}			
			//m_Sentences.Speak( "COMBINE_KICK" );
			}
			break;
		}

		default:
		{
			CAI_BaseNPC::HandleAnimEvent( pEvent );
			break;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pTask - 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::RunTask( const Task_t *pTask )
{
	switch ( pTask->iTask )
	{
		// Run Task:  Zoo Animal Run Tasks

		case TASK_ZOO_ANIMAL_DEFENSIVE_START_GET_PATH_TO_FLEE:
		{
			// This is crude/BAD...i dont remember the short hand way to do this
			// FIXME: Make sure you check that the random path chosen is a VALID path.

			string_t * fleePathList = ( m_nCurrentFleePath ) ? m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_FLEE ] : m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_ALT_FLEE ];

			m_nCurrentFleePath ^= 1;

			int * pFleePathList;
			pFleePathList = new int[ ZOO_ANIMAL_MAX_AI_PATHS ];

			int	numViablePaths = 0;

			for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
			{
				pFleePathList[ i ] = 0;

				if ( fleePathList[ i ] != NULL_STRING &&
						 gEntList.FindEntityByName( NULL, fleePathList[ i ] ) )
				{
					pFleePathList[ i ] = 1;
					numViablePaths++;
				}
			}

			if ( numViablePaths > 0 )
			{
				int randomInt = random->RandomInt( 1, numViablePaths );

				string_t randomPath = NULL_STRING;

				for ( int i = 0, j = 1; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
				{
					if ( pFleePathList[i] == 1 && j++ == randomInt )
					{
						randomPath = fleePathList[i];
					}
				}

				if ( randomPath != NULL_STRING )
				{
					inputdata_t nullData;

					InputStartScripting( nullData );
					m_target						= randomPath;
					m_pPathCorner				= gEntList.FindEntityByName( NULL, m_target );
					
					if ( m_pPathCorner != NULL )
					{
						// Generate Path List

						const int MAX_CONNECTED_PATH_CORNERS = 128;

						string_t * pConnectedPathCornerList = new string_t[ MAX_CONNECTED_PATH_CORNERS ];

						int numConnectedPathCorners = 0;

						pConnectedPathCornerList[ 0 ] = randomPath;
						pConnectedPathCornerList[ 1 ] = m_pPathCorner->m_target;

						CBaseEntity * pCurrentPathCorner = gEntList.FindEntityByName( NULL, m_pPathCorner->m_target );

						numConnectedPathCorners = 2;

						while ( pCurrentPathCorner != NULL &&
										pCurrentPathCorner != m_pPathCorner && 
										numConnectedPathCorners < MAX_CONNECTED_PATH_CORNERS )
						{
							pCurrentPathCorner = gEntList.FindEntityByName( NULL, pCurrentPathCorner->m_target );
							numConnectedPathCorners += ( pCurrentPathCorner != NULL ) ? 1 : 0;
							pConnectedPathCornerList[ numConnectedPathCorners - 1 ] = ( pCurrentPathCorner != NULL ) ? pCurrentPathCorner->m_target : NULL_STRING;
						}

						// Find the Path Corner that is farthest away from the Player

						int closestPathCorner = -1;

						float closestPathCornerDist = -1.0f;

						for ( int i = 0; i <  numConnectedPathCorners; i++ )
						{
							const Vector &originZooAnimal = this->GetAbsOrigin();
							const Vector &originPathCorner = gEntList.FindEntityByName( NULL, pConnectedPathCornerList[ i ] )->GetAbsOrigin();

							float tempDist = ( originZooAnimal.AsVector2D() - originPathCorner.AsVector2D() ).LengthSqr();

							if ( closestPathCorner == -1 ||
									 closestPathCornerDist == -1 || 
									 tempDist <= closestPathCornerDist )
							{
								closestPathCorner			= i;
								closestPathCornerDist	= tempDist;
							}
						}

						m_target						= pConnectedPathCornerList[ closestPathCorner ];
						m_pPathCorner				= gEntList.FindEntityByName( NULL, m_target );

						ChangeIcon( ICON_ZOO_ANIMAL_FEAR );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
						SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
						InputWake( nullData );
						SetIdealActivity( ACT_RUN );
						GetNavigator()->SetMovementActivity( ACT_RUN );
						PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_FLEE );
						TaskComplete();
					}
					else
					{
						TaskFail( FAIL_NO_GOAL );
					}
				}
				else
				{
					TaskFail( FAIL_NO_GOAL );
				}
			}
			else
			{
				TaskFail( FAIL_NO_GOAL );
			}
			break;
		}
			
		case TASK_ZOO_ANIMAL_DEFENSIVE_END_GET_PATH_TO_FLEE:
		{
			//SetIdealActivity( ACT_RUN );
			//GetNavigator()->SetMovementActivity( ACT_RUN );
			TaskComplete();
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_TO_PLAYER:
		{
			PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_ANGRY );
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_TO_PLAYER:
		{
			ClearEnemyMemory();
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
			SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );

			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_ATTACK_PLAYER:
		{
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_ATTACK_PLAYER:
		{
			SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE ) );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) );

			ClearEnemyMemory();
			TaskComplete();
			break;
		}
		
		case TASK_ZOO_ANIMAL_DEFENSIVE_START_ATTACK_PLAYER:
		{
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_DEFENSIVE_END_ATTACK_PLAYER:
		{
			SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE ) );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) );

			ClearEnemyMemory();
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_START_RETURN_TO_A_PATH:
		{
			SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );

			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_END_RETURN_TO_A_PATH:
		{
			// This is crude/BAD...i dont remember the short hand way to do this
			// FIXME: Make sure you check that the random path chosen is a VALID path.

			int * pPathList;
			pPathList = new int[ ZOO_ANIMAL_MAX_AI_PATHS ];

			int	numViablePaths = 0;

			for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
			{
				pPathList[i] = 0;

				if( m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][ i ] != NULL_STRING )
				{
					pPathList[i] = 1;
					numViablePaths++;
				}
			}

			if ( numViablePaths > 0 )
			{
				int randomInt = random->RandomInt( 1, numViablePaths );

				string_t randomPath = NULL_STRING;

				for ( int i = 0, j = 1; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
				{
					if ( pPathList[i] == 1 && j++ == randomInt)
					{
						randomPath = m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_DEFAULT ][ i ];
					}
				}

				if ( randomPath != NULL_STRING )
				{
					inputdata_t nullData;

					InputStartScripting( nullData );
					m_target						= randomPath;
					m_pPathCorner				= gEntList.FindEntityByName( NULL, m_target );

					if ( m_pPathCorner != NULL )
					{
						SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
						InputWake( nullData );
						// HACK - running out of time!
						switch ( m_nZooAnimalAIType )
						{
							case AI_TYPE_ZOO_ANIMAL_BIRD:
							case AI_TYPE_ZOO_ANIMAL_MONKEY:
							{
								SetIdealActivity( ACT_WALK );
								GetNavigator()->SetMovementActivity( ACT_WALK );
								break;
							}
							case AI_TYPE_ZOO_ANIMAL_WALRUS:
							{
								SetIdealActivity( ACT_RUN );
								GetNavigator()->SetMovementActivity( ACT_RUN );
								break;
							}
						}
						TaskComplete();
					}
					else
					{
						TaskFail( FAIL_NO_GOAL );
					}
				}
				else
				{
					TaskFail( FAIL_NO_GOAL );
				}
			}
			else
			{
				TaskFail( FAIL_NO_GOAL );
			}
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_START_COOLDOWN:
		{
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_END_COOLDOWN:
		{
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_STUNNED_START:
		{
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_STUNNED_END:
		{
			PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_DAZED );
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_GET_CHASE_PATH_TO_ENEMY:
		{
			break;
		}
		
		case TASK_ZOO_ANIMAL_MOVE_ON_PATH:
		{
			Vector vecDiff;

			vecDiff = GetLocalOrigin() - GetNavigator()->GetGoalPos();

			int		aiState = GetAIState();

			float dist		= 0.0f;

			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					ChangeIcon( ICON_ZOO_ANIMAL_ANGRY );
					dist = GetAIRange( AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY ).x;
					break;
				}
			}

			if( vecDiff.Length() <= dist )
			{
				TaskComplete();
			}
			break;
		}

		case TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY:
		{
			int currentSchedule = GetAISchedAct();

			while ( m_nCurrentAIAct < ZOO_ANIMAL_MAX_AI_ACTS &&
							( Activity )GetAIPreAct( currentSchedule, m_nCurrentAIAct ) == ACT_INVALID )
			{
				m_nCurrentAIAct++;
			}

			Activity activityToSet = ( Activity )GetAIPreAct( currentSchedule, m_nCurrentAIAct );

			if ( m_nCurrentAIAct < ZOO_ANIMAL_MAX_AI_ACTS && 
					 activityToSet != ACT_INVALID &&
					 GetActivity() != activityToSet )
			{		
				SetActivity( activityToSet );
				SetIdealActivity( activityToSet );
			}

			if ( m_nCurrentAIAct == ZOO_ANIMAL_MAX_AI_ACTS )
			{
				for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_ACTS; i++ )
				{
					LockAIPreAct( currentSchedule, i );
				}
				m_nCurrentAIAct = 0;
				TaskComplete();
			}
			else if ( GetActivity() == activityToSet &&
							  IsSequenceFinished() )
			{
					m_nCurrentAIAct++;
			}
			break;
		}

		case TASK_ZOO_ANIMAL_POST_SET_AND_WAIT_ACTIVITY:
		{
			int currentSchedule = GetAISchedAct();

			while ( m_nCurrentAIAct < ZOO_ANIMAL_MAX_AI_ACTS &&
							( Activity )GetAIPostAct( currentSchedule, m_nCurrentAIAct ) == ACT_INVALID )
			{
				m_nCurrentAIAct++;
			}

			Activity activityToSet = ( Activity )GetAIPostAct( currentSchedule, m_nCurrentAIAct );

			if ( m_nCurrentAIAct < ZOO_ANIMAL_MAX_AI_ACTS && 
					 activityToSet != ACT_INVALID &&
					 GetActivity() != activityToSet )
			{
				SetActivity( activityToSet );
			}

			if ( m_nCurrentAIAct == ZOO_ANIMAL_MAX_AI_ACTS )
			{
				for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_ACTS; i++ )
				{
					LockAIPostAct( currentSchedule, i );
				}
				m_nCurrentAIAct = 0;

				TaskComplete();
			}
			else if ( GetActivity() == activityToSet &&
							  IsSequenceFinished() )
			{
					m_nCurrentAIAct++;
			}
			break;
		}

		case TASK_ZOO_ANIMAL_MELEE_ATTACK:
		{
			if ( GetActivity() == m_currentMeleeAttackActivity && IsSequenceFinished() )
			{
				TaskComplete();
			}
			break;
		}

		case TASK_ZOO_ANIMAL_HURT:
		{
			Activity goalActivity = ( Activity )( ACT_HIT );

			if ( GetActivity() == goalActivity && IsSequenceFinished() )
			{
				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) );

				//ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearEnemyMemory();
				TaskComplete();
			}
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_WILDLY:
		{
			Activity goalActivity = ( Activity )( ACT_SHOCK );

			if ( GetActivity() == goalActivity && IsSequenceFinished() )
			{
				TaskComplete();
			}
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_WILDLY:
		{
			PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK );

			// This is crude/BAD...i dont remember the short hand way to do this
			// FIXME: Make sure you check that the random path chosen is a VALID path.

			string_t * ragePathList = m_pathList[ AI_PATH_TYPE_ZOO_ANIMAL_RAGE ];

			int * pRagePathList;
			pRagePathList = new int[ ZOO_ANIMAL_MAX_AI_PATHS ];

			int	numViablePaths = 0;

			for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
			{
				pRagePathList[ i ] = 0;

				if ( ragePathList[ i ] != NULL_STRING &&
						 gEntList.FindEntityByName( NULL, ragePathList[ i ] ) )
				{
					pRagePathList[ i ] = 1;
					numViablePaths++;
				}
			}

			if ( numViablePaths > 0 )
			{
				int randomInt = random->RandomInt( 1, numViablePaths );

				string_t randomPath = NULL_STRING;

				for ( int i = 0, j = 1; i < ZOO_ANIMAL_MAX_AI_PATHS; i++ )
				{
					if ( pRagePathList[i] == 1 && j++ == randomInt )
					{
						randomPath = ragePathList[i];
					}
				}

				if ( randomPath != NULL_STRING )
				{
					inputdata_t nullData;

					InputStartScripting( nullData );
					m_target						= randomPath;
					m_pPathCorner				= gEntList.FindEntityByName( NULL, m_target );
					
					if ( m_pPathCorner != NULL )
					{
						// Generate Path List

						const int MAX_CONNECTED_PATH_CORNERS = 128;

						string_t * pConnectedPathCornerList = new string_t[ MAX_CONNECTED_PATH_CORNERS ];

						int numConnectedPathCorners = 0;

						pConnectedPathCornerList[ 0 ] = randomPath;
						pConnectedPathCornerList[ 1 ] = m_pPathCorner->m_target;

						CBaseEntity * pCurrentPathCorner = gEntList.FindEntityByName( NULL, m_pPathCorner->m_target );

						numConnectedPathCorners = 2;

						while ( pCurrentPathCorner != NULL &&
										pCurrentPathCorner != m_pPathCorner && 
										numConnectedPathCorners < MAX_CONNECTED_PATH_CORNERS )
						{
							pCurrentPathCorner = gEntList.FindEntityByName( NULL, pCurrentPathCorner->m_target );
							numConnectedPathCorners += ( pCurrentPathCorner != NULL ) ? 1 : 0;
							pConnectedPathCornerList[ numConnectedPathCorners - 1 ] = ( pCurrentPathCorner != NULL ) ? pCurrentPathCorner->m_target : NULL_STRING;
						}

						// Find the Path Corner that is farthest away from the Player

						int closestPathCorner = -1;

						float closestPathCornerDist = -1.0f;

						for ( int i = 0; i <  numConnectedPathCorners; i++ )
						{
							const Vector &originZooAnimal = this->GetAbsOrigin();
							const Vector &originPathCorner = gEntList.FindEntityByName( NULL, pConnectedPathCornerList[ i ] )->GetAbsOrigin();

							float tempDist = ( originZooAnimal.AsVector2D() - originPathCorner.AsVector2D() ).LengthSqr();

							if ( closestPathCorner == -1 ||
									 closestPathCornerDist == -1 || 
									 tempDist <= closestPathCornerDist )
							{
								closestPathCorner			= i;
								closestPathCornerDist	= tempDist;
							}
						}

						m_target						= pConnectedPathCornerList[ closestPathCorner ];
						m_pPathCorner				= gEntList.FindEntityByName( NULL, m_target );

						ChangeIcon( ICON_ZOO_ANIMAL_FEAR );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
						SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );
						InputWake( nullData );
						SetIdealActivity( ACT_RUN );
						GetNavigator()->SetMovementActivity( ACT_RUN );
						//PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_FLEE );
						m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = true;
						TaskComplete();
					}
					else
					{
						TaskFail( FAIL_NO_GOAL );
					}
				}
				else
				{
					TaskFail( FAIL_NO_GOAL );
				}
			}
			else
			{
				TaskFail( FAIL_NO_GOAL );
			}
			break;
		}

		default:
		{
			BaseClass::RunTask( pTask );
		}
	}
}

//-----------------------------------------------------------------------------
int CBaseZooAnimal::CalcDamageInfo( CTakeDamageInfo *pInfo )
{
	CalculateMeleeDamageForce( pInfo, GetAbsVelocity(), GetAbsOrigin() );
	return pInfo->GetDamage();
}

//---------------------------------------------------------
//---------------------------------------------------------

void CBaseZooAnimal::MonkeyStateMachine()
{
	int aiState = GetAIState();

	switch ( aiState )
	{
		case AI_STATE_ZOO_ANIMAL_NEUTRAL:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{	
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is ready to engage the Player. If the npc is and
			// close enough to engage the Player, then engage the Player.

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_ALERT );

				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
				SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER );

				//UnLockAIPreAct( AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER, 0 );

				SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is currently on a path

			else if ( m_pPathCorner != NULL )
			{
				const Vector	&originZooAnimal	= this->GetAbsOrigin();
				const Vector	&originPathCorner	= m_pPathCorner->GetAbsOrigin();

				const float		NEAR_XY_SQ				= Square( 16.0f );

				// If the npc is near the referenced path corner on the path, set the npc to be 
				// ready to engage the Player.

				if ( (originZooAnimal.AsVector2D() - originPathCorner.AsVector2D()).LengthSqr() <= NEAR_XY_SQ )
				{
					m_target						= NULL_STRING;
					m_pPathCorner				= NULL;

					SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
					ToggleAllAIPreAct( false );
					ToggleAllAIPostAct( false );
				}
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is NOT performing a melee attack, is ready to perform
			// another defensive melee attack, and close enough to the Player, then
			// attempt to perform a defensive melee attack on the Player

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_ANGRY );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is done fleeing and it is ready to reutrn to its default path

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_FLEE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_PASSIVE );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );

				SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is NOT performing a melee attack and is ready to 
			// try running away from the Player.

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_START_FLEE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			}

			// Check if the npc should alternate its flee path

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) && 
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );
		
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is finished chasing the player and should return to its default path

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_CHASE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_PASSIVE );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );

				SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc should continue to chase the player

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ) )
			{
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE ) );
				SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );
			}

			// Check if the npc is NOT performing a melee attack, is ready to perform
			// another aggressive melee attack, and close enough to the Player, then
			// attempt to perform a aggressive melee attack on the Player

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE_MELEE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );

				SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER );
	
				SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_STUNNED:
		{
			// Check if the npc has recovered from being stun

			if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_STUNNED ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ResetHitCount();

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED );

				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}
			break;
		}
	}
}

void CBaseZooAnimal::BirdStateMachine()
{
	int aiState = GetAIState();

	switch ( aiState )
	{
		case AI_STATE_ZOO_ANIMAL_NEUTRAL:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{	
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is ready to start running away

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_START_FLEE ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_DEFENSIVE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				//UnLockAIPreAct( AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER, 0 );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is currently on a path

			else if ( m_pPathCorner != NULL )
			{
				const Vector	&originZooAnimal	= this->GetAbsOrigin();
				const Vector	&originPathCorner	= m_pPathCorner->GetAbsOrigin();

				const float		NEAR_XY_SQ				= Square( 16.0f );

				// If the npc is near the referenced path corner on the path, set the npc to be 
				// ready to engage the Player.

				if ( (originZooAnimal.AsVector2D() - originPathCorner.AsVector2D()).LengthSqr() <= NEAR_XY_SQ )
				{
					m_target						= NULL_STRING;
					m_pPathCorner				= NULL;

					SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
					ToggleAllAIPreAct( false );
					ToggleAllAIPostAct( false );
				}
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is NOT performing a melee attack, is ready to perform
			// another defensive melee attack, and close enough to the Player, then
			// attempt to perform a defensive melee attack on the Player

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_DEFENSIVE_MELEE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_ANGRY );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			}

			// Check if the npc is done running away and should return to its path			

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_FLEE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_PASSIVE );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );

				SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is NOT performing a melee attack and is ready to 
			// try running away from the Player.

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_START_FLEE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			}

			// Check if the npc should alternate its flee path

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) && 
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_CHANGE_FLEE_PATH ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );
		
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_STUNNED:
		{
			// Check if the npc has recovered from being stun

			if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_STUNNED ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ResetHitCount();

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED );

				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH ) );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE ) );

				SetCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );

				SetAIState( AI_STATE_ZOO_ANIMAL_DEFENSIVE );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}
			break;
		}
	}
}

void CBaseZooAnimal::WalrusStateMachine()
{
	int aiState = GetAIState();

	switch ( aiState )
	{
		case AI_STATE_ZOO_ANIMAL_NEUTRAL:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{	
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_START_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
				m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = false;
			}

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION ) &&
								EvalPlayerSelfProximity( GetAIRangeOffset( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ), 
																				 GetAIRange( AI_RANGE_ZOO_ANIMAL_AGGRESSIVE ),
																				 ZOO_ANIMAL_SPHERICAL_COLLISION ) )
			{
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE ) );

				SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
				SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );

				PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_ANGRY );

				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
			}

			// Check if the npc is currently on a path

			else if ( m_pPathCorner != NULL )
			{
				const Vector	&originZooAnimal	= this->GetAbsOrigin();
				const Vector	&originPathCorner	= m_pPathCorner->GetAbsOrigin();

				const float		NEAR_XY_SQ				= Square( 16.0f );

				// If the npc is near the referenced path corner on the path, set the npc to be 
				// ready to engage the Player.

				if ( (originZooAnimal.AsVector2D() - originPathCorner.AsVector2D()).LengthSqr() <= NEAR_XY_SQ )
				{
					m_target						= NULL_STRING;
					m_pPathCorner				= NULL;

					SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
					SetCondition( COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN );
					//SetIdealActivity( ACT_IDLE );
					//GetNavigator()->SetMovementActivity( ACT_IDLE );
					ToggleAllAIPreAct( false );
					ToggleAllAIPostAct( false );
					m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = false;

					PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_FLEE );
				}
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
		{
			// Check if the npc should be stunned.

			if ( IsStunned() )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_DAZED );

				m_bIsHurt = false;

				this->RemoveEffects( EF_NODRAW );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_FLEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHASE_EVALUATION );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_AGGRESSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_DEFENSIVE_MELEE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_CHANGE_FLEE_PATH );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE );

				SetCondition( COND_ZOO_ANIMAL_STUNNED );
				SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );

				SetAIState( AI_STATE_ZOO_ANIMAL_STUNNED );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
				m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = false;
			}

			// Check if the npc is finished chasing the player and should return to its default path

			else if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_RAGE ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_PASSIVE );

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE );
				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE_EVALUATION );
				SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );

				SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
				m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = false;
			}
			break;
		}

		case AI_STATE_ZOO_ANIMAL_STUNNED:
		{
			// Check if the npc has recovered from being stun

			if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_STUNNED ) )
			{
				ChangeIcon( ICON_ZOO_ANIMAL_FEAR );

				ResetHitCount();;

				ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED );

				SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );

				SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
				ToggleAllAIPreAct( false );
				ToggleAllAIPostAct( false );
				m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = false;
			}
			break;
		}
	}
}

void CBaseZooAnimal::GatherConditions( void )
{
	BaseClass::GatherConditions();

	TouchRange( GetPlayer() );

	if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_HURT ) )
	{
		m_bIsHurt = false;

		this->RemoveEffects( EF_NODRAW );

		ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT );
		ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE );
	}

	if ( m_bIsHurt && IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) )
	{
		if ( this->GetEffects() & EF_NODRAW )
		{
			this->RemoveEffects( EF_NODRAW );
		}
		else
		{
			this->AddEffects( EF_NODRAW );
		}
		SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) );
	}

	// Check if a Task has failed. If it has then "Reset" the Zoo Animal (i.e. set to NEUTRAL)
	// We still need to set a default schedule

	if ( HasCondition( COND_TASK_FAILED ))
	{			
		ClearCondition( COND_TASK_FAILED );
		ClearCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER );
		ClearCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );
		ClearCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER );
		ClearCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER );
		ClearCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );
		ClearCondition( COND_ZOO_ANIMAL_STUNNED );

		ClearEnemyMemory();

		for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_TIMERS; i++ )
		{
			SetAITimerWaitThinkTime( i, ZOO_ANIMAL_DEFAULT_AI_TIMER_THINK_TIME );
		}

		ResetHitCount();
		SetAIState( AI_STATE_ZOO_ANIMAL_NEUTRAL );
		SetCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );
	}	

	// Check if the npc's health/hitcount should be reset

	if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) )
	{
		ResetHitCount();
		ClearAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN );
	}

	switch ( m_nZooAnimalAIType )
	{
		case AI_TYPE_ZOO_ANIMAL_MONKEY:
			MonkeyStateMachine();
			break;
		case AI_TYPE_ZOO_ANIMAL_BIRD:
			BirdStateMachine();
			break;
		case AI_TYPE_ZOO_ANIMAL_WALRUS:
			WalrusStateMachine();
			break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::PrescheduleThink( void )
{
	BaseClass::PrescheduleThink();
}

bool CBaseZooAnimal::CanBeAnEnemyOf( CBaseEntity *pEnemy )
{
	return BaseClass::CanBeAnEnemyOf( pEnemy );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pTask - 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::StartTask( const Task_t *pTask )
{
	switch ( pTask->iTask )
	{
		// Start Task:  Zoo Animal Tasks

		case TASK_ZOO_ANIMAL_DEFENSIVE_START_GET_PATH_TO_FLEE:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_DEFENSIVE_END_GET_PATH_TO_FLEE:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_TO_PLAYER:
		{
			SetEnemy( GetPlayer() );
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_TO_PLAYER:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_ATTACK_PLAYER:
		{
			SetEnemy( GetPlayer() );
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_ATTACK_PLAYER:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_DEFENSIVE_START_ATTACK_PLAYER:
		{
			SetEnemy( GetPlayer() );
			break;
		}

		case TASK_ZOO_ANIMAL_DEFENSIVE_END_ATTACK_PLAYER:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_START_RETURN_TO_A_PATH:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_END_RETURN_TO_A_PATH:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_START_COOLDOWN:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_NEUTRAL_END_COOLDOWN:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_STUNNED_START:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_STUNNED_END:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_SET_TOLERANCE_DISTANCE:
		{
			GetNavigator()->SetGoalTolerance( GetAIRange( AI_RANGE_ZOO_ANIMAL_TOLERANCE_DISTANCE ).x	);
			TaskComplete();
			break;
		}

		case TASK_ZOO_ANIMAL_GET_CHASE_PATH_TO_ENEMY:
		{
			CBaseEntity *pEnemy = GetEnemy();

			if ( !pEnemy )
			{
				TaskFail( FAIL_NO_ROUTE );
				return;
			}

			if ( ( pEnemy->GetAbsOrigin() - GetEnemyLKP() ).LengthSqr() < Square( GetAIRange( AI_RANGE_ZOO_ANIMAL_CHASE_PATH_TO_ENEMY ).x ) )
			{
				ChainStartTask( TASK_GET_PATH_TO_ENEMY );
			}
			else
			{
				ChainStartTask( TASK_GET_PATH_TO_ENEMY_LKP );
			}

			if ( !TaskIsComplete() && !HasCondition( COND_TASK_FAILED ) )
			{
				TaskFail( FAIL_NO_ROUTE );
			}
			break;
		}

		case TASK_ZOO_ANIMAL_MOVE_ON_PATH:
		{
			Activity movementActivity = ( Activity )( ( int )pTask->flTaskData );

			if ( TranslateActivity( movementActivity ) != ACT_INVALID )
			{
				GetNavigator()->SetMovementActivity( movementActivity );
			}
			else
			{
				GetNavigator()->SetMovementActivity( ACT_IDLE );
			}
			break;
		}

		case TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_POST_SET_AND_WAIT_ACTIVITY:
		{
			break;
		}

		case TASK_ZOO_ANIMAL_MELEE_ATTACK:
		{
			m_currentMeleeAttackActivity = m_aiMeleeAttackActivity[ random->RandomInt( 0, ( ZOO_ANINAL_MAX_AI_MELEE_ATTACK_ACTIVITY - 1 ) ) ] ;

			if ( GetActivity() != m_currentMeleeAttackActivity )
			{
				PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_MELEE_ATTACK );
				SetIdealActivity( m_currentMeleeAttackActivity );
			}
			break;
		}

		case TASK_ZOO_ANIMAL_HURT:
		{
			Activity goalActivity = ( Activity )( ACT_HIT );

			if ( GetActivity() != goalActivity )
			{
				PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_HURT );
				SetIdealActivity( goalActivity );
			}
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_WILDLY:
		{
			Activity goalActivity = ( Activity )( ACT_SHOCK );

			if ( GetActivity() != goalActivity )
			{
				//PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_HURT );
				SetIdealActivity( goalActivity );

				//m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ] = true;
			}
			break;
		}

		case TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_WILDLY:
		{
			break;
		}

		default:
		{
			BaseClass::StartTask( pTask );
		}
	}
}

//------------------------------------------------------------------------------
// Purpose:
// Input  :
//------------------------------------------------------------------------------
void CBaseZooAnimal::Touch( CBaseEntity *pOther )
{ 
	/*
	if ( GetPlayer() == pOther )
	{
		// HACK for now
		Vector forward, right, up;
   	AngleVectors( GetPlayer()->GetLocalAngles(), &forward, &right, &up );
		GetPlayer()->ApplyAbsVelocityImpulse( ( forward * GetTouchForceOnPlayer( AI_TOUCH_FORCE_PLAYER_FORWARD ) ) + 
																					( right * GetTouchForceOnPlayer( AI_TOUCH_FORCE_PLAYER_RIGHT ) ) +
																					( up * GetTouchForceOnPlayer( AI_TOUCH_FORCE_PLAYER_UP ) ) );
	}
	*/
	BaseClass::Touch(pOther);
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pevInflictor - 
//			pevAttacker - 
//			flDamage - 
//			bitsDamageType - 
// Output : 
//-----------------------------------------------------------------------------
int CBaseZooAnimal::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
	CTakeDamageInfo info = inputInfo;

	if ( m_bIsHurt )
	{
		return 0;
	}	

	// Check for hit from the Sack

	// Check for hit from Bag Level 1

	if ( info.GetDamageType() & DMG_CLUB )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( MELEE_HIT );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ) );

						m_bIsHurt = true;

						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) );
						SetCondition( COND_ZOO_ANIMAL_HURT );
					}
					break;
				}

				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from Bag Level 2

	if ( info.GetDamageType() & DMG_SLASH )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( SPECIAL1 );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ) );

						m_bIsHurt = true;

						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) );
						SetCondition( COND_ZOO_ANIMAL_HURT );
					}
					break;
				}

				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from Bag Level 3

	if ( info.GetDamageType() & DMG_BURN )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( SPECIAL2 );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ) );

						m_bIsHurt = true;

						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) );
						SetCondition( COND_ZOO_ANIMAL_HURT );
					}
					break;
				}
			
				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from the Trap

	if ( info.GetDamageType() & DMG_BLAST )
	{
		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ) );

						m_bIsHurt = true;

						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HURT_FLICKER_RATE ) );
						SetCondition( COND_ZOO_ANIMAL_HURT );
					}
					break;
				}
			}
		}
	}

	// Check for hit from the "Capture"
	
	if ( info.GetDamageType() & DMG_SHOCK )
	{
		int aiState = GetAIState();

		switch ( aiState )
		{
			case AI_STATE_ZOO_ANIMAL_STUNNED:
			{
				m_OnDeath.FireOutput( GetPlayer(), this );

				inputdata_t nullData;
				InputKill( nullData );
				break;
			}
		}
	}
	
	//return CAI_BaseNPC::OnTakeDamage_Alive( info );
	return 0;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseZooAnimal::ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut )
{
	// Assumes the headcrab mass is 5kg (100 feet per second)
	float MAX_HEADCRAB_RAGDOLL_SPEED = 100.0f * 12.0f * 5.0f;

	Vector vecClampedForce; 
	BaseClass::ClampRagdollForce( vecForceIn, &vecClampedForce );

	// Copy the force to vecForceOut, in case we don't change it.
	*vecForceOut = vecClampedForce;

	float speed = VectorNormalize( vecClampedForce );
	if( speed > MAX_HEADCRAB_RAGDOLL_SPEED )
	{
		// Don't let the ragdoll go as fast as it was going to.
		vecClampedForce *= MAX_HEADCRAB_RAGDOLL_SPEED;
		*vecForceOut = vecClampedForce;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : Type - 
//-----------------------------------------------------------------------------
int CBaseZooAnimal::TranslateSchedule( int scheduleType )
{
	switch( scheduleType )
	{
		case SCHED_ALERT_FACE:
			return SCHED_ZOO_ANIMAL_ALERT_FACE;

		case SCHED_ALERT_FACE_BESTSOUND:
			return SCHED_ZOO_ANIMAL_ALERT_FACE_BESTSOUND;

		case SCHED_ALERT_REACT_TO_COMBAT_SOUND:
			return SCHED_ZOO_ANIMAL_ALERT_REACT_TO_COMBAT_SOUND;

		case SCHED_ALERT_SCAN:
			return SCHED_ZOO_ANIMAL_ALERT_SCAN;

		case SCHED_ALERT_STAND:
			return SCHED_ZOO_ANIMAL_ALERT_STAND;

		case SCHED_ALERT_WALK:
			return SCHED_ZOO_ANIMAL_ALERT_WALK;
	}

	return BaseClass::TranslateSchedule( scheduleType );
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CBaseZooAnimal::SelectSchedule( void )
{
	// Check if the Zoo Animal is near the player
	
	if ( HasCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );
		return SCHED_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER;
	}
	
	if ( HasCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER );
		return SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER );
		return SCHED_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER );
		return SCHED_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
		return SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );
		return SCHED_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN );
		return SCHED_ZOO_ANIMAL_NEUTRAL_COOLDOWN;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_STUNNED ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_STUNNED );
		return SCHED_ZOO_ANIMAL_STUNNED;
	}

	if ( HasCondition( COND_ZOO_ANIMAL_HURT ) )
	{
		ClearCondition( COND_ZOO_ANIMAL_HURT );
		return SCHED_ZOO_ANIMAL_HURT;
	}
	int nSchedule = BaseClass::SelectSchedule();

	return nSchedule;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseZooAnimal::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode )
{
	return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode );
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
//			&vecDir - 
//			*ptr - 
//-----------------------------------------------------------------------------
void CBaseZooAnimal::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	BaseClass::TraceAttack( info, vecDir, ptr );
}

//-----------------------------------------------------------------------------
// Purpose:  This is a generic function (to be implemented by sub-classes) to
//			 handle specific interactions between different types of characters
//			 (For example the barnacle grabbing an NPC)
// Input  :  Constant for the type of interaction
// Output :	 true  - if sub-class has a response for the interaction
//			 false - if sub-class has no response
//-----------------------------------------------------------------------------
bool CBaseZooAnimal::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt)
{
	return BaseClass::HandleInteraction( interactionType, data, sourceEnt );
}

//-----------------------------------------------------------------------------
// Purpose: Allows for modification of the interrupt mask for the current schedule.
//			In the most cases the base implementation should be called first.
//-----------------------------------------------------------------------------
void CBaseZooAnimal::BuildScheduleTestBits( void )
{
	// Setting the condition to Interrupt the Zoo Animals fear so the 
	// Zoo Animal will chose another path

		SetCustomInterruptCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_HURT );
		SetCustomInterruptCondition( COND_ZOO_ANIMAL_STUNNED );
}

//-----------------------------------------------------------------------------
//
// Schedules
//
//-----------------------------------------------------------------------------

AI_BEGIN_CUSTOM_NPC( npc_zoo_animal_00, CBaseZooAnimal )

	// Declaring Zoo Animal Tasks

	DECLARE_TASK( TASK_ZOO_ANIMAL_DEFENSIVE_START_GET_PATH_TO_FLEE )
	DECLARE_TASK( TASK_ZOO_ANIMAL_DEFENSIVE_END_GET_PATH_TO_FLEE )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_TO_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_TO_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_START_ATTACK_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_END_ATTACK_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_WILDLY )
	DECLARE_TASK( TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_WILDLY )
	DECLARE_TASK( TASK_ZOO_ANIMAL_DEFENSIVE_START_ATTACK_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_DEFENSIVE_END_ATTACK_PLAYER )
	DECLARE_TASK( TASK_ZOO_ANIMAL_NEUTRAL_START_RETURN_TO_A_PATH )
	DECLARE_TASK( TASK_ZOO_ANIMAL_NEUTRAL_END_RETURN_TO_A_PATH )
	DECLARE_TASK( TASK_ZOO_ANIMAL_NEUTRAL_START_COOLDOWN )
	DECLARE_TASK( TASK_ZOO_ANIMAL_NEUTRAL_END_COOLDOWN )
	DECLARE_TASK( TASK_ZOO_ANIMAL_STUNNED_START )
	DECLARE_TASK( TASK_ZOO_ANIMAL_STUNNED_END )
	DECLARE_TASK( TASK_ZOO_ANIMAL_SET_TOLERANCE_DISTANCE )
	DECLARE_TASK( TASK_ZOO_ANIMAL_GET_CHASE_PATH_TO_ENEMY )
	DECLARE_TASK( TASK_ZOO_ANIMAL_MOVE_ON_PATH )
	DECLARE_TASK( TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY )
	DECLARE_TASK( TASK_ZOO_ANIMAL_POST_SET_AND_WAIT_ACTIVITY )
	DECLARE_TASK( TASK_ZOO_ANIMAL_MELEE_ATTACK )
	DECLARE_TASK( TASK_ZOO_ANIMAL_HURT )
	
	DECLARE_ACTIVITY( ACT_DAZE );
	DECLARE_ACTIVITY( ACT_MAD );
	DECLARE_ACTIVITY( ACT_SHOCK );
	
	// Declaring Zoo Animal Conditions

	DECLARE_CONDITION( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_PLAYER )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_PLAYER )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_AGGRESSIVE_NEAR_ATTACK_PLAYER )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_DEFENSIVE_NEAR_ATTACK_PLAYER )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_NEUTRAL_COOLDOWN )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_STUNNED )
	DECLARE_CONDITION( COND_ZOO_ANIMAL_HURT )
	
	DECLARE_INTERACTION( g_interactionZooAnimalMelee );

	//==================================================
	// Have the Zoo Animal ( NEUTRAL ) return to a random path
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH,
	"	Tasks"
	"   TASK_STOP_MOVING									0"
	"		TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY		0"
	"		TASK_ZOO_ANIMAL_NEUTRAL_START_RETURN_TO_A_PATH	0"
	"		TASK_ZOO_ANIMAL_NEUTRAL_END_RETURN_TO_A_PATH	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal ( NEUTRAL ) cooldown
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_NEUTRAL_COOLDOWN,
	"	Tasks"
	"   TASK_STOP_MOVING								0"
	"   TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY		0"
	"		TASK_ZOO_ANIMAL_NEUTRAL_START_COOLDOWN		0"
	"		TASK_ZOO_ANIMAL_NEUTRAL_END_COOLDOWN		0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal ( DEFENSIVE ) attack the player
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_DEFENSIVE_ATTACK_PLAYER,
	"	Tasks"
	"		TASK_ZOO_ANIMAL_DEFENSIVE_START_ATTACK_PLAYER		0"
	"   TASK_STOP_MOVING										0"
	"		TASK_FACE_PLAYER									0"
	"		TASK_ZOO_ANIMAL_MELEE_ATTACK						0" 
	"		TASK_ZOO_ANIMAL_DEFENSIVE_END_ATTACK_PLAYER			0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal ( AGGRESSIVE ) attack the player
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_AGGRESSIVE_ATTACK_PLAYER,
	"	Tasks"
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_START_ATTACK_PLAYER		0"
	"		TASK_STOP_MOVING									0"
	"		TASK_FACE_PLAYER									0"
	"		TASK_ZOO_ANIMAL_MELEE_ATTACK						0" 
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_END_ATTACK_PLAYER		0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal ( AGGRESSIVE ) run to the player
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER,
	"	Tasks"
	"		TASK_STOP_MOVING									0"
	"		TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY			0"
	"		TASK_ZOO_ANIMAL_SET_TOLERANCE_DISTANCE				0"
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_TO_PLAYER		0"
	"		TASK_FACE_PLAYER									0"
	"		TASK_GET_PATH_TO_PLAYER								0"
	"		TASK_ZOO_ANIMAL_MOVE_ON_PATH						ACTIVITY:ACT_RUN"
	"		TASK_WAIT_FOR_MOVEMENT								0"
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_TO_PLAYER		0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal ( AGGRESSIVE ) run wildly
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY,
	"	Tasks"
	"		TASK_STOP_MOVING							0"
	"		TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY	0"
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_START_RUN_WILDLY	0"
	"		TASK_ZOO_ANIMAL_AGGRESSIVE_END_RUN_WILDLY	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)
	
	//==================================================
	// Have the Zoo Animal ( DEFENSIVE ) run away from the Player
	//==================================================

	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER,

	"	Tasks"
	"		TASK_STOP_MOVING									0"
	"		TASK_ZOO_ANIMAL_PRE_SET_AND_WAIT_ACTIVITY			0"
	"		TASK_ZOO_ANIMAL_DEFENSIVE_START_GET_PATH_TO_FLEE	0"
	"		TASK_ZOO_ANIMAL_DEFENSIVE_END_GET_PATH_TO_FLEE		0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)
	//==================================================
	// Have the Zoo Animal ( STUNNED ) remain idle for some time
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_STUNNED,

	"	Tasks"
	"		TASK_STOP_MOVING					0"
	"		TASK_ZOO_ANIMAL_STUNNED_START		0"
	"		TASK_ZOO_ANIMAL_STUNNED_END			0"
	"		TASK_SET_ACTIVITY					ACTIVITY:ACT_DAZE"
	"		TASK_WAIT_INDEFINITE				0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Have the Zoo Animal visually get HURT by the Player
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_HURT,

	"	Tasks"
	"		TASK_STOP_MOVING		0"
	"		TASK_ZOO_ANIMAL_HURT	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Overriding Default SCHED_ALERT_FACE for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_FACE,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Overriding Default SCHED_ALERT_FACE_BESTSOUND for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_FACE_BESTSOUND,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)
	
	//==================================================
	// Overriding Default SCHED_ALERT_REACT_TO_COMBAT_SOUND for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_REACT_TO_COMBAT_SOUND,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Overriding Default SCHED_ALERT_REACT_TO_COMBAT_SOUND for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_SCAN,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Overriding Default SCHED_ALERT_REACT_TO_COMBAT_SOUND for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_STAND,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

	//==================================================
	// Overriding Default SCHED_ALERT_REACT_TO_COMBAT_SOUND for Zoo Animal
	//==================================================
	DEFINE_SCHEDULE
	(
	SCHED_ZOO_ANIMAL_ALERT_WALK,

	"	Tasks"
	"		TASK_STOP_MOVING	0"
	""
	"	Interrupts"
	"		COND_TASK_FAILED"
	)

AI_END_CUSTOM_NPC()

// Monkey

CBSG_Monkey::CBSG_Monkey()
{
	m_nZooAnimalAIType = AI_TYPE_ZOO_ANIMAL_MONKEY;

	m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ] = true;

	m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER ][ 0 ]		= ( int )ACT_SHOCK;

	m_aiLockPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_TO_PLAYER ][ 0 ]	= false;
}

CBSG_Monkey::~CBSG_Monkey()
{
}

AI_BEGIN_CUSTOM_NPC( npc_zoo_animal_01, CBSG_Monkey )

AI_END_CUSTOM_NPC()

// Bird

CBSG_Bird::CBSG_Bird()
{
	m_nZooAnimalAIType = AI_TYPE_ZOO_ANIMAL_BIRD;

	m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ] = true;

	m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER ][ 0 ]		= ( int )ACT_SHOCK;

	m_aiLockPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_DEFENSIVE_RUN_AWAY_FROM_PLAYER ][ 0 ]	= false;

	m_aiMeleeAttackActivity[ AI_ATTACK_ACTIVITY_ZOO_ANIMAL_MELEE_ATTACK_2 ] = ACT_MELEE_ATTACK_SWING_GESTURE;
}

CBSG_Bird::~CBSG_Bird()
{
}

AI_BEGIN_CUSTOM_NPC( npc_zoo_animal_02, CBSG_Bird )

AI_END_CUSTOM_NPC()

// Walrus

CBSG_Walrus::CBSG_Walrus()
{
	m_nZooAnimalAIType = AI_TYPE_ZOO_ANIMAL_WALRUS;
	
	for ( int i = 0; i < ZOO_ANIMAL_MAX_AI_STATES; i++ )
	{
		m_pAIPlayerStateDamage[ i ][ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ] = false;
	}

	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_NEUTRAL ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ]		= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_DEFENSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_AGGRESSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_STUNNED ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ]		= true;

	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_NEUTRAL ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ]		= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_DEFENSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_AGGRESSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_STUNNED ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ]		= true;

	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_NEUTRAL ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ]		= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_DEFENSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_AGGRESSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_STUNNED ][ PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ]		= true;

	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_AGGRESSIVE ][ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ]	= true;
	m_pAIPlayerStateDamage[ AI_STATE_ZOO_ANIMAL_STUNNED ][ PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ]		= true;
	
	m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_COOLDOWN ][ 0 ] = ( int )ACT_MELEE_ATTACK_SWING_GESTURE; 
	m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_COOLDOWN ][ 1 ] = ( int )ACT_IDLE;

	m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY ][ 0 ]			= ( int )ACT_BUSY_LEAN_BACK;
	//m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY ][ 1 ]			= ( int )ACT_SHOCK;
	//m_aiPreActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY ][ 2 ]			= ( int )ACT_RUN;

	m_aiPostActivity[ AI_SCHED_ACT_ZOO_ANIMAL_AGGRESSIVE_RUN_WILDLY ][ 0 ]			= ( int )ACT_RUN;

	m_aiPostActivity[ AI_SCHED_ACT_ZOO_ANIMAL_NEUTRAL_RETURN_TO_A_PATH ][ 0 ]		= ( int )ACT_RUN;

	m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_PROXIMITY ]	= true;
	m_activeTouchForceOnPlayer[ AI_TOUCH_FORCE_PLAYER_TYPE_RAGE ]		= false;
}

CBSG_Walrus::~CBSG_Walrus()
{
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pevInflictor - 
//			pevAttacker - 
//			flDamage - 
//			bitsDamageType - 
// Output : 
//-----------------------------------------------------------------------------

int CBSG_Walrus::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
	CTakeDamageInfo info = inputInfo;

	// Check for hit from the Sack

	// Check for hit from Bag Level 1

	if ( info.GetDamageType() & DMG_CLUB )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( MELEE_HIT );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ) );

						SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
						SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );

						ToggleAllAIPreAct( false );
						ToggleAllAIPostAct( false );

						PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_ANGRY );
					}
					break;
				}
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_1 ) ); 
					}
					break;
				}

				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from Bag Level 2

	if ( info.GetDamageType() & DMG_SLASH )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( SPECIAL1 );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ) );

						SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
						SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );

						ToggleAllAIPreAct( false );
						ToggleAllAIPostAct( false );

						PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_ANGRY );
					}
					break;
				}
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_2 ) );
					}
					break;
				}

				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from Bag Level 3

	if ( info.GetDamageType() & DMG_BURN )
	{
		//ToBasePlayer( GetPlayer() )->GetActiveWeapon()->WeaponSound( SPECIAL2 );

		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_RAGE ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ) );

						SetCondition( COND_ZOO_ANIMAL_AGGRESSIVE_HIT_BY_PLAYER );
						SetAIState( AI_STATE_ZOO_ANIMAL_AGGRESSIVE );

						ToggleAllAIPreAct( false );
						ToggleAllAIPostAct( false );

						PlayZooAnimalSound( AI_SOUND_ZOO_ANIMAL_ANGRY );
					}
					break;
				}
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_MELEE ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_BAG_3 ) );
					}
					break;
				}
			
				case AI_STATE_ZOO_ANIMAL_STUNNED:
				{
					SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_STUNNED ) );
					break;
				}
			}
		}
	}

	// Check for hit from the Trap

	if ( info.GetDamageType() & DMG_BLAST )
	{
		int aiState = GetAIState();

		if ( GetAIPlayerStateDamage( aiState, PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ) )
		{
			switch ( aiState )
			{
				case AI_STATE_ZOO_ANIMAL_NEUTRAL:
				{
					break;
				}
				case AI_STATE_ZOO_ANIMAL_DEFENSIVE:
				case AI_STATE_ZOO_ANIMAL_AGGRESSIVE:
				{
					if ( IsAITimerWaitThinkTimeFinished( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ) )
					{
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_PLAYER_TRAP ) );
						SetAITimerWaitThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN, GetAITimerThinkTime( AI_TIMER_ZOO_ANIMAL_HEALTH_REGEN ) );
						DecrementHitCount( GetAIPlayerDamage( PLAYER_DAMAGE_ZOO_ANIMAL_TRAP ) );
					}
					break;
				}
			}
		}
	}

	// Check for hit from the "Capture"
	
	if ( info.GetDamageType() & DMG_SHOCK )
	{
		int aiState = GetAIState();

		switch ( aiState )
		{
			case AI_STATE_ZOO_ANIMAL_STUNNED:
			{
				m_OnDeath.FireOutput( GetPlayer(), this );

				inputdata_t nullData;
				InputKill( nullData );
				break;
			}
		}
	}
	
	return 0;
}

//-----------------------------------------------------------------------------
// Purpose: Catches the monster-specific messages that occur when tagged
//			animation frames are played.
// Input  : *pEvent - 
//-----------------------------------------------------------------------------
void CBSG_Walrus::HandleAnimEvent( animevent_t *pEvent )
{
}

AI_BEGIN_CUSTOM_NPC( npc_zoo_animal_03, CBSG_Walrus )

AI_END_CUSTOM_NPC()

//-----------------------------------------------------------------------------