/*
*
*   This program is free software; you can redistribute it and/or modify it
*   under the terms of the GNU General Public License as published by the
*   Free Software Foundation; either version 2 of the License, or (at
*   your option) any later version.
*
*   This program is distributed in the hope that it will be useful, but
*   WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program; if not, write to the Free Software Foundation,
*   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*   In addition, as a special exception, the author gives permission to
*   link the code of this program with the Half-Life Game Engine ("HL
*   Engine") and Modified Game Libraries ("MODs") developed by Valve,
*   L.L.C ("Valve").  You must obey the GNU General Public License in all
*   respects for all of the code used other than the HL Engine and MODs
*   from Valve.  If you modify this file, you may extend this exception
*   to your version of the file, but you are not obligated to do so.  If
*   you do not wish to do so, delete this exception statement from your
*   version.
*
*/

#ifndef CS_BOT_H
#define CS_BOT_H
#ifdef _WIN32
#pragma once
#endif

#include "bot/cs_gamestate.h"
#include "bot/cs_bot_manager.h"
#include "bot/cs_bot_chatter.h"

#define CSBOT_VERSION_MAJOR		1
#define CSBOT_VERSION_MINOR		50

#define FLAG_PROGRESS_DRAW		0x0	// draw status bar progress
#define FLAG_PROGRESS_START		0x1	// init status bar progress
#define FLAG_PROGRESS_HIDE		0x2	// hide status bar progress

#ifdef HOOK_GAMEDLL

#define _navAreaCount (*pnavAreaCount)
#define _currentIndex (*pcurrentIndex)

#endif // HOOK_GAMEDLL

extern int _navAreaCount;
extern int _currentIndex;

class CCSBot;
class BotChatterInterface;

/* <3327a8> ../cstrike/dlls/bot/cs_bot.h:44 */
class BotState
{
public:
	virtual void OnEnter(CCSBot *me) {}
	virtual void OnUpdate(CCSBot *me) {}
	virtual void OnExit(CCSBot *me) {}
	virtual const char *GetName(void) const = 0;

};/* size: 4, cachelines: 1, members: 1 */

/* <3328b8> ../cstrike/dlls/bot/cs_bot.h:53 */
class IdleState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Idle";
	}

};/* size: 4, cachelines: 1, members: 1 */

/* <3328d9> ../cstrike/dlls/bot/cs_bot.h:61 */
class HuntState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Hunt";
	}
	void ClearHuntArea(void)
	{
		m_huntArea = NULL;
	}
private:
	CNavArea *m_huntArea;

};/* size: 8, cachelines: 1, members: 2 */

/* <3328fb> ../cstrike/dlls/bot/cs_bot.h:75 */
class AttackState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Attack";
	}

	void SetCrouchAndHold(bool crouch)
	{
		m_crouchAndHold = crouch;
	}
	void StopAttacking(CCSBot *me);

protected:
	enum DodgeStateType
	{
		STEADY_ON,
		SLIDE_LEFT,
		SLIDE_RIGHT,
		JUMP,
		NUM_ATTACK_STATES
	} m_dodgeState;

	float m_nextDodgeStateTimestamp;
	CountdownTimer m_repathTimer;
	float m_scopeTimestamp;
	bool m_haveSeenEnemy;
	bool m_isEnemyHidden;
	float m_reacquireTimestamp;
	float m_shieldToggleTimestamp;
	bool m_shieldForceOpen;
	float m_pinnedDownTimestamp;
	bool m_crouchAndHold;
	bool m_didAmbushCheck;
	bool m_dodge;
	bool m_firstDodge;
	bool m_isCoward;
	CountdownTimer m_retreatTimer;

};/* size: 60, cachelines: 1, members: 17 */

/* <332922> ../cstrike/dlls/bot/cs_bot.h:120 */
class InvestigateNoiseState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "InvestigateNoise";
	}
private:
	NOBODY void AttendCurrentNoise(CCSBot *me);
	Vector m_checkNoisePosition;

};/* size: 16, cachelines: 1, members: 2 */

/* <332949> ../cstrike/dlls/bot/cs_bot.h:133 */
class BuyState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Buy";
	}
private:
	bool m_isInitialDelay;
	int m_prefRetries;
	int m_prefIndex;
	int m_retries;
	bool m_doneBuying;
	bool m_buyDefuseKit;
	bool m_buyGrenade;
	bool m_buyShield;
	bool m_buyPistol;

};/* size: 28, cachelines: 1, members: 10 */

/* <332970> ../cstrike/dlls/bot/cs_bot.h:154 */
class MoveToState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "MoveTo";
	}
	void SetGoalPosition(const Vector &pos)
	{
		m_goalPosition = pos;
	}
	void SetRouteType(RouteType route)
	{
		m_routeType = route;
	}
private:
	Vector m_goalPosition;
	RouteType m_routeType;
	bool m_radioedPlan;
	bool m_askedForCover;

};/* size: 24, cachelines: 1, members: 5 */

/* <332997> ../cstrike/dlls/bot/cs_bot.h:171 */
class FetchBombState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "FetchBomb";
	}

};/* size: 4, cachelines: 1, members: 1 */

/* <3329be> ../cstrike/dlls/bot/cs_bot.h:179 */
class PlantBombState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "PlantBomb";

		// TODO: ??
		//return &statement.m_next[3];
	}

};/* size: 4, cachelines: 1, members: 1 */

/* <3329e5> ../cstrike/dlls/bot/cs_bot.h:188 */
class DefuseBombState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "DefuseBomb";
	}

};/* size: 4, cachelines: 1, members: 1 */

/* <332a0c> ../cstrike/dlls/bot/cs_bot.h:197 */
class HideState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Hide";
	}
	void SetHidingSpot(const Vector &pos)
	{
		m_hidingSpot = pos;
	}
	const Vector &GetHidingSpot(void) const
	{
		return m_hidingSpot;
	}
	void SetSearchArea(CNavArea *area)
	{
		m_searchFromArea = area;
	}
	void SetSearchRange(float range)
	{
		m_range = range;
	}
	void SetDuration(float time)
	{
		m_duration = time;
	}
	void SetHoldPosition(bool hold)
	{
		m_isHoldingPosition = hold;
	}
	bool IsAtSpot(void) const
	{
		return m_isAtSpot;
	}
private:
	CNavArea *m_searchFromArea;
	float m_range;

	Vector m_hidingSpot;
	bool m_isAtSpot;
	float m_duration;
	bool m_isHoldingPosition;
	float m_holdPositionTime;
	bool m_heardEnemy;

	float m_firstHeardEnemyTime;
	int m_retry;
	Vector m_leaderAnchorPos;

};/* size: 64, cachelines: 1, members: 12 */

/* <332a33> ../cstrike/dlls/bot/cs_bot.h:234 */
class EscapeFromBombState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "EscapeFromBomb";
	}

};/* size: 4, cachelines: 1, members: 1 */

/* <332a5a> ../cstrike/dlls/bot/cs_bot.h:243 */
class FollowState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "Follow";
	}
	void SetLeader(CBaseEntity *leader)
	{
		m_leader = leader;
	}
private:
	NOBODY void ComputeLeaderMotionState(float leaderSpeed);
private:
	EHANDLE m_leader;
	Vector m_lastLeaderPos;
	bool m_isStopped;
	float m_stoppedTimestamp;

	enum LeaderMotionStateType
	{
		INVALID,
		STOPPED,
		WALKING,
		RUNNING
	} m_leaderMotionState;
	IntervalTimer m_leaderMotionStateTime;

	bool m_isSneaking;
	float m_lastSawLeaderTime;
	CountdownTimer m_repathInterval;

	IntervalTimer m_walkTime;
	bool m_isAtWalkSpeed;

	float m_waitTime;
	CountdownTimer m_idleTimer;

};/* size: 76, cachelines: 2, members: 14 */

/* <332a81> ../cstrike/dlls/bot/cs_bot.h:282 */
class UseEntityState: public BotState
{
public:
	NOBODY virtual void OnEnter(CCSBot *me);
	NOBODY virtual void OnUpdate(CCSBot *me);
	NOBODY virtual void OnExit(CCSBot *me);
	virtual const char *GetName(void) const
	{
		return "UseEntity";
	}
	void SetEntity(CBaseEntity *entity)
	{
		m_entity = entity;
	}
private:
	EHANDLE m_entity;

};/* size: 12, cachelines: 1, members: 2 */

/* <32b267> ../cstrike/dlls/bot/cs_bot.h:300 */
class CCSBot: public CBot
{
public:
	CCSBot(void)
	{
	};

public:
	NOBODY virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
	NOBODY virtual void Killed(entvars_t *pevAttacker, int iGib);
	NOBODY virtual void RoundRespawn(void);
	NOBODY virtual void Blind(float duration, float holdTime, float fadeTime, int alpha = 255);
	NOBODY virtual void OnTouchingWeapon(CWeaponBox *box);
	NOBODY virtual bool Initialize(const BotProfile *profile);

	NOBODY virtual void SpawnBot(void);
	virtual void Upkeep(void);

	NOBODY virtual void Update(void);
	NOBODY virtual void Walk(void);
	NOBODY virtual bool Jump(bool mustJump = false);

	NOBODY virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL);

	// TODO: change both places?
	NOBODY virtual bool IsVisible(const Vector *pos, bool testFOV = false) const;
	NOBODY virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const;

	virtual bool IsEnemyPartVisible(VisiblePartType part) const;

#ifdef HOOK_GAMEDLL

	bool Initialize_(const BotProfile *profile);
	void SpawnBot_(void);
	void Upkeep_(void);
	void Update_(void);
	void Walk_(void);
	bool Jump_(bool mustJump);
	void Blind_(float duration, float holdTime, float fadeTime, int alpha);
	int TakeDamage_(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
	void Killed_(entvars_t *pevAttacker, int iGib);
	void OnTouchingWeapon_(CWeaponBox *box);
	void OnEvent_(GameEventType event, CBaseEntity *entity, CBaseEntity *other);
	bool IsVisible_(const Vector *pos, bool testFOV) const;
	bool IsVisible_(CBasePlayer *player, bool testFOV, unsigned char *visParts) const;
	bool IsEnemyPartVisible_(VisiblePartType part) const;
	void RoundRespawn_(void);

#endif // HOOK_GAMEDLL

public:
	void Disconnect(void);
	float GetCombatRange(void) const
	{
		return m_combatRange;
	}
	bool IsRogue(void)const;
	void SetRogue(bool rogue)
	{
		m_isRogue = rogue;
	}
	NOBODY bool IsHurrying(void) const;
	void Hurry(float duration)
	{
		m_hurryTimer.Start(duration);
	}
	NOBODY bool IsSafe(void) const;
	NOBODY bool IsWellPastSafe(void) const;
	NOBODY bool IsEndOfSafeTime(void) const;

	NOBODY float GetSafeTimeRemaining(void) const;
	float GetSafeTime(void) const
	{
		return m_safeTime;
	}
	NOBODY bool IsUnhealthy(void);
	void Idle(void);

	NOBODY void Hide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false);
	NOBODY void Hide(const Vector *hidingSpot = NULL, float duration = -1.0f, bool holdPosition = false);

	NOBODY bool TryToHide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false, bool useNearest = false);
	NOBODY bool TryToRetreat(void);

	bool IsHiding(void) const;
	bool IsAtHidingSpot(void) const;
	NOBODY void Hunt(void);
	NOBODY bool IsHunting(void) const;
	NOBODY void Attack(CBasePlayer *victim);
	NOBODY void FireWeaponAtEnemy(void);
	void StopAttacking(void);
	bool IsAttacking(void) const;
	NOBODY void MoveTo(const Vector *pos, RouteType route = SAFEST_ROUTE);
	NOBODY bool IsMovingTo(void) const;
	NOBODY void PlantBomb(void);
	NOBODY void FetchBomb(void);
	NOBODY bool NoticeLooseBomb(void) const;
	NOBODY bool CanSeeLooseBomb(void) const;
	bool IsCarryingBomb(void)
	{
		//TODO: unsure
		//return (m_bomber.Get() != NULL);
		return false;
	}
	NOBODY void DefuseBomb(void);
	bool IsDefusingBomb(void) const;
	NOBODY bool CanSeePlantedBomb(void) const;
	NOBODY void EscapeFromBomb(void);
	NOBODY bool IsEscapingFromBomb(void) const;
	NOBODY void RescueHostages(void);
	NOBODY void UseEntity(CBaseEntity *entity);
	bool IsBuying(void) const;
	NOBODY void Panic(CBasePlayer *enemy);
	NOBODY void Follow(CBasePlayer *player);
	NOBODY void ContinueFollowing(void);
	NOBODY void StopFollowing(void);
	bool IsFollowing(void) const
	{
		return m_isFollowing;
	}
	CBasePlayer *GetFollowLeader(void)
	{
		CBaseEntity *entity = (CBaseEntity *)m_leader;
		return (CBasePlayer *)entity;
	}
	float GetFollowDuration(void) const
	{
		return (gpGlobals->time - m_followTimestamp);
	}
	bool CanAutoFollow(void) const
	{
		return (gpGlobals->time > m_allowAutoFollowTime);
	}
	NOBODY bool IsNotMoving(void);
	void AimAtEnemy(void)
	{
		m_isAimingAtEnemy = true;
	}
	void StopAiming(void)
	{
		m_isAimingAtEnemy = false;
	}
	bool IsAimingAtEnemy(void) const
	{
		return m_isAimingAtEnemy;
	}
	bool IsSurprised(void) const
	{
		return (gpGlobals->time - this->m_surpriseTimestamp >= 5.0f);
	}
	float GetSurpriseDelay(void) const
	{
		return m_surpriseDelay;
	}
	void ClearSurpriseDelay(void)
	{
		m_surpriseDelay = 0.0f;
	}
	float GetStateTimestamp(void) const
	{
		return m_stateTimestamp;
	}
	NOBODY bool IsDoingScenario(void);
	CSGameState *GetGameState(void)
	{
		return &m_gameState;
	}
	const CSGameState *GetGameState(void) const
	{
		return &m_gameState;
	}
	bool IsAtBombsite(void) const
	{
		UNTESTED
		// TODO: return true if we are in a bomb planting zone
		return GetGameState()->IsAtPlantedBombsite();
	}
	NOBODY bool GuardRandomZone(float range = 500.0f);
	bool IsBusy(void) const;

	enum TaskType
	{
		SEEK_AND_DESTROY = 0,
		PLANT_BOMB,
		FIND_TICKING_BOMB,
		DEFUSE_BOMB,
		GUARD_TICKING_BOMB,
		GUARD_BOMB_DEFUSER,
		GUARD_LOOSE_BOMB,
		GUARD_BOMB_ZONE,
		ESCAPE_FROM_BOMB,
		HOLD_POSITION,
		FOLLOW,
		VIP_ESCAPE,
		GUARD_VIP_ESCAPE_ZONE,
		COLLECT_HOSTAGES,
		RESCUE_HOSTAGES,
		GUARD_HOSTAGES,
		GUARD_HOSTAGE_RESCUE_ZONE,
		MOVE_TO_LAST_KNOWN_ENEMY_POSITION,
		MOVE_TO_SNIPER_SPOT,
		SNIPING,
	};

	void SetTask(TaskType task, CBaseEntity *entity = NULL)
	{
		m_task = task;
		m_taskEntity = entity;
	}
	TaskType GetTask(void) const
	{
		return m_task;
	}
	CBaseEntity *GetTaskEntity(void)
	{
		return m_taskEntity;
	}

	enum DispositionType
	{
		ENGAGE_AND_INVESTIGATE,
		OPPORTUNITY_FIRE,
		SELF_DEFENSE,
		IGNORE_ENEMIES,
	};

	NOBODY void SetDisposition(DispositionType disposition);
	DispositionType GetDisposition(void) const;
	NOBODY void IgnoreEnemies(float duration);

	enum MoraleType
	{
		TERRIBLE = -3,
		BAD = -2,
		NEGATIVE = -1,
		NEUTRAL = 0,
		POSITIVE = 1,
		GOOD = 2,
		EXCELLENT = 3,
	};
	MoraleType GetMorale(void) const
	{
		return m_morale;
	}
	NOBODY void IncreaseMorale(void);
	void DecreaseMorale(void);
	bool IsNoiseHeard(void) const
	{
		if (m_noiseTimestamp <= 0.0f)
			return false;

		if (gpGlobals->time - m_noiseTimestamp >= GetProfile()->GetReactionTime())
			return true;

		return false;
	}
	NOBODY bool ShouldInvestigateNoise(float *retNoiseDist);
	NOBODY void InvestigateNoise(void);
	NOBODY const Vector *GetNoisePosition(void);
	CNavArea *GetNoiseArea(void) const
	{
		return m_noiseArea;
	}
	void ForgetNoise(void)
	{
		m_noiseTimestamp = 0;
	}
	NOBODY bool CanSeeNoisePosition(void);
	NOBODY float GetNoiseRange(void) const
	{
		return 0.0f;
	}
	NOBODY bool CanHearNearbyEnemyGunfire(float range = -1.0f);
	PriorityType GetNoisePriority(void) const
	{
		return m_noisePriority;
	}
	NOBODY void SendRadioMessage(GameEventType event);
	BotChatterInterface *GetChatter(void)
	{
		return &m_chatter;
	}
	NOBODY bool RespondToHelpRequest(CBasePlayer *them, Place place, float maxRange = -1.0f);
	NOBODY void StartVoiceFeedback(float duration);
	bool IsUsingVoice(void) const
	{
		return (m_voiceFeedbackEndTimestamp != 0.0f);	//return (m_voiceFeedbackEndTimestamp > gpGlobals->time);
	}
	void SetEnemy(CBasePlayer *enemy);
	CBasePlayer *GetEnemy(void)
	{
		return GetClassPtr((CBasePlayer *)m_enemy->pev);
	}
	int GetNearbyEnemyCount(void) const
	{
		return Q_min(GetEnemiesRemaining(), m_nearbyEnemyCount);
	}
	unsigned int GetEnemyPlace(void) const
	{
		return m_enemyPlace;
	}
	NOBODY bool CanSeeBomber(void);
	CBasePlayer *GetBomber(void) const
	{
		return GetClassPtr((CBasePlayer *)m_bomber->pev);
	}
	int GetNearbyFriendCount(void) const
	{
		return Q_min(GetFriendsRemaining(), m_nearbyFriendCount);
	}
	CBasePlayer *GetClosestVisibleFriend(void) const
	{
		return GetClassPtr((CBasePlayer *)m_closestVisibleFriend->pev);
	}
	CBasePlayer *GetClosestVisibleHumanFriend(void) const
	{
		return GetClassPtr((CBasePlayer *)m_closestVisibleHumanFriend->pev);
	}
	NOBODY bool IsOutnumbered(void);
	NOBODY int OutnumberedCount(void);
	NOBODY CBasePlayer *GetImportantEnemy(bool checkVisibility);
	NOBODY void UpdateReactionQueue(void);
	CBasePlayer *GetRecognizedEnemy(void);
	NOBODY bool IsRecognizedEnemyReloading(void);
	NOBODY bool IsRecognizedEnemyProtectedByShield(void);
	NOBODY float GetRangeToNearestRecognizedEnemy(void);
	NOBODY CBasePlayer *GetAttacker(void);
	float GetTimeSinceAttacked(void) const
	{
		return gpGlobals->time - m_attackedTimestamp;
	}
	NOBODY float GetFirstSawEnemyTimestamp(void);
	float GetLastSawEnemyTimestamp(void) const
	{
		return m_lastSawEnemyTimestamp;
	}
	float GetTimeSinceLastSawEnemy(void) const
	{
		return gpGlobals->time - m_lastSawEnemyTimestamp;
	}
	float GetTimeSinceAcquiredCurrentEnemy(void) const
	{
		return (gpGlobals->time - m_currentEnemyAcquireTimestamp);
	}
	NOBODY bool HasNotSeenEnemyForLongTime(void) const;
	const Vector &GetLastKnownEnemyPosition(void) const
	{
		return m_lastEnemyPosition;
	}
	bool IsEnemyVisible(void) const
	{
		return m_isEnemyVisible;
	}
	float GetEnemyDeathTimestamp(void) const
	{
		return m_enemyDeathTimestamp;
	}
	NOBODY bool IsFriendInLineOfFire(void);
	NOBODY bool IsAwareOfEnemyDeath(void) const;
	int GetLastVictimID(void) const
	{
		return m_lastVictimID;
	}
	bool HasPath(void) const
	{
		return m_pathLength != 0;
	}
	void DestroyPath(void)
	{
		m_pathLength = 0;
		m_pathLadder = NULL;
	}
	float GetFeetZ(void) const
	{
		const Vector crouch = VEC_DUCK_HULL_MIN_Z;
		const Vector stand = VEC_HULL_MIN_Z;

		return (IsCrouching()) ? (pev->origin + crouch).z : (pev->origin + stand).z;
	}

	enum PathResult
	{
		PROGRESSING,
		END_OF_PATH,
		PATH_FAILURE,
	};
	NOBODY PathResult UpdatePathMovement(bool allowSpeedChange);
	//bool AStarSearch(CNavArea *startArea); // NOXREF Not implemented
	NOBODY bool ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route);
	NOBODY bool StayOnNavMesh(void);
	CNavArea *GetLastKnownArea(void) const
	{
		return m_lastKnownArea;
	}
	const Vector &GetPathEndpoint(void) const
	{
		return m_path[ m_pathLength - 1 ].pos;
	}
	NOBODY float GetPathDistanceRemaining(void);
	NOBODY void ResetStuckMonitor(void);
	//bool IsAreaVisible(CNavArea *area); // NOXREF Not implemented
	const Vector &GetPathPosition(int numpath) const
	{
		return m_path[ numpath ].pos;
	}
	NOBODY bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal);
	NOBODY Place GetPlace(void);
	bool IsUsingLadder(void) const
	{
		return (m_pathLadder != NULL);
	}
	NOBODY void GetOffLadder(void);
	void SetGoalEntity(CBaseEntity *entity)
	{
		m_goalEntity = entity;
	}
	CBaseEntity *GetGoalEntity(void)
	{
		return m_goalEntity;
	}
	NOBODY bool IsNearJump(void);
	NOBODY float GetApproximateFallDamage(float height);
	void ForceRun(float duration)
	{
		Run();
		m_mustRunTimer.Start(duration);
	}
	NOBODY void Wiggle(void);
	NOBODY bool IsFriendInTheWay(Vector *goalPos);
	NOBODY void FeelerReflexAdjustment(Vector *goalPosition);
	void SetLookAngles(float yaw, float pitch)
	{
		m_lookYaw = yaw;
		m_lookPitch = pitch;
	}
	void UpdateLookAngles(void);

	NOBODY void UpdateLookAround(bool updateNow);
	NOBODY void InhibitLookAround(float duration);
	void SetForwardAngle(float angle)
	{
		m_forwardAngle = angle;
	}
	void SetLookAheadAngle(float angle)
	{
		m_lookAheadAngle = angle;
	}
	void SetLookAt(const char *desc, const Vector *pos, PriorityType pri, float duration = -1.0f, bool clearIfClose = false, float angleTolerance = 5.0f);

	void ClearLookAt(void)
	{
		m_lookAtSpotState = NOT_LOOKING_AT_SPOT;
		m_lookAtDesc = NULL;
	}
	bool IsLookingAtSpot(PriorityType pri) const
	{
		if (m_lookAtSpotState != NOT_LOOKING_AT_SPOT && m_lookAtSpotPriority >= pri)
			return true;

		return false;
	}
	bool IsViewMoving(float angleVelThreshold) const
	{
		if (m_lookYawVel < angleVelThreshold && m_lookYawVel > -angleVelThreshold &&
			m_lookPitchVel < angleVelThreshold && m_lookPitchVel > -angleVelThreshold)
		{
			return false;
		}
		return true;
	}
	NOBODY const Vector *GetEyePosition(void) const;
	NOBODY float ComputeWeaponSightRange(void);
	NOBODY void ComputeApproachPoints(void);
	NOBODY void UpdateApproachPoints(void);
	void ClearApproachPoints(void)
	{
		m_approachPointCount = 0;
	}
	NOBODY void DrawApproachPoints(void);
	NOBODY float GetHidingSpotCheckTimestamp(HidingSpot *spot);
	NOBODY void SetHidingSpotCheckTimestamp(HidingSpot *spot);
	NOBODY void EquipBestWeapon(bool mustEquip);
	NOBODY void EquipPistol(void);
	NOBODY void EquipKnife(void);
	NOBODY bool EquipGrenade(bool noSmoke);
	bool IsUsingKnife(void);
	bool IsUsingPistol(void);
	bool IsUsingGrenade(void);
	bool IsUsingSniperRifle(void);
	bool IsUsingAWP(void);
	NOBODY bool IsSniper(void);
	bool IsSniping(void) const;
	bool IsUsingShotgun(void);
	bool IsUsingMachinegun(void);
	void ThrowGrenade(const Vector *target);
	bool IsThrowingGrenade(void) const
	{
		return m_isWaitingToTossGrenade;
	}
	NOBODY bool HasGrenade(void);
	NOBODY bool DoesActiveWeaponHaveSilencer(void);
	NOBODY bool IsUsingHEGrenade(void);
	NOBODY void StartRapidFire(void);
	NOBODY void StopRapidFire(void);
	NOBODY bool IsRapidFiring(void);

	enum ZoomType
	{
		NO_ZOOM = 0,
		LOW_ZOOM,
		HIGH_ZOOM,
	};
	ZoomType GetZoomLevel(void)
	{
		if (m_iFOV > 60.0f)
			return NO_ZOOM;

		if (m_iFOV > 25.0f)
			return LOW_ZOOM;

		return HIGH_ZOOM;
	}
	NOBODY bool AdjustZoom(float range);
	NOBODY bool IsPrimaryWeaponEmpty(void);
	NOBODY bool IsPistolEmpty(void);
	NOBODY int GetHostageEscortCount(void);
	NOBODY void IncreaseHostageEscortCount(void);
	NOBODY float GetRangeToFarthestEscortedHostage(void);
	NOBODY void ResetWaitForHostagePatience(void);
	NOBODY void ResetValues(void);
	NOBODY void BotDeathThink(void);
	NOBODY CBasePlayer *FindNearbyPlayer(void);
	void AdjustSafeTime(void);
	void SetState(BotState *state);
	NOBODY void MoveTowardsPosition(const Vector *pos);
	NOBODY void MoveAwayFromPosition(const Vector *pos);
	NOBODY void StrafeAwayFromPosition(const Vector *pos);
	NOBODY void StuckCheck(void);
	NOBODY void BuildTrivialPath(const Vector *goal);
	NOBODY bool ComputePathPositions(void);
	NOBODY void SetupLadderMovement(void);
	NOBODY void SetPathIndex(int newIndex);
	NOBODY void DrawPath(void);
	NOBODY int FindOurPositionOnPath(Vector *close, bool local);
	NOBODY int FindPathPoint(float aheadRange, Vector *point, int *prevIndex);
	NOBODY bool FindClosestPointOnPath(Vector *worldPos, int startIndex, int endIndex, Vector *close);
	NOBODY bool IsStraightLinePathWalkable(Vector *goal);
	NOBODY bool DiscontinuityJump(float ground, bool onlyJumpDown, bool mustJump);
	NOBODY bool UpdateLadderMovement(void);
	NOBODY void ComputeLadderEndpoint(bool isAscending);
	NOBODY void UpdateHostageEscortCount(void);
	NOBODY bool UpdateLookAtNoise(void);
	void UpdateLookAt(void);
	NOBODY void UpdatePeripheralVision(void);
	NOBODY bool BendLineOfSight(Vector *eye, const Vector *point, Vector *bend);
	NOBODY bool FindApproachPointNearestPath(const Vector *pos);
	NOBODY bool FindGrenadeTossPathTarget(const Vector *pos);
	void SetAimOffset(float accuracy);
	void UpdateAimOffset(void);
	NOBODY bool DoEquip(CBasePlayerWeapon *gun);
	NOBODY void ReloadCheck(void);
	NOBODY void SilencerCheck(void);
	NOBODY CBasePlayer *FindMostDangerousThreat(void);
	NOBODY void RespondToRadioCommands(void);
	NOBODY bool IsRadioCommand(GameEventType event);
	void EndVoiceFeedback(bool force = true);
	NOBODY CNavNode *AddNode(const Vector *destPos, const Vector *normal, NavDirType dir, CNavNode *source);
	NOBODY void StartLearnProcess(void);
	NOBODY void UpdateLearnProcess(void);
	NOBODY bool LearnStep(void);
	NOBODY void StartAnalyzeAlphaProcess(void);
	NOBODY void UpdateAnalyzeAlphaProcess(void);
	NOBODY bool AnalyzeAlphaStep(void);
	NOBODY void StartAnalyzeBetaProcess(void);
	NOBODY void UpdateAnalyzeBetaProcess(void);
	NOBODY bool AnalyzeBetaStep(void);
	NOBODY void StartSaveProcess(void);
	NOBODY void UpdateSaveProcess(void);
	void StartNormalProcess(void);
	NOBODY void BotTouch(CBaseEntity *other);
private:
	friend class CCSBotManager;
	friend class AttackState;
	friend class BuyState;

	char m_name[64];
	float m_combatRange;
	mutable bool m_isRogue;
	mutable CountdownTimer m_rogueTimer;
	MoraleType m_morale;
	bool m_diedLastRound;
	float m_safeTime;
	bool m_wasSafe;
	NavRelativeDirType m_blindMoveDir;
	bool m_blindFire;
	float m_surpriseDelay;
	float m_surpriseTimestamp;
	bool m_isFollowing;
	EHANDLE m_leader;
	float m_followTimestamp;
	float m_allowAutoFollowTime;
	CountdownTimer m_hurryTimer;
	IdleState m_idleState;
	HuntState m_huntState;
	AttackState m_attackState;
	InvestigateNoiseState m_investigateNoiseState;
	BuyState m_buyState;
	MoveToState m_moveToState;
	FetchBombState m_fetchBombState;
	PlantBombState m_plantBombState;
	DefuseBombState m_defuseBombState;
	HideState m_hideState;
	EscapeFromBombState m_escapeFromBombState;
	FollowState m_followState;
	UseEntityState m_useEntityState;
	BotState *m_state;
	float m_stateTimestamp;
	bool m_isAttacking;
	TaskType m_task;
	EHANDLE m_taskEntity;
	Vector m_goalPosition;
	EHANDLE m_goalEntity;
	CNavArea *m_currentArea;
	CNavArea *m_lastKnownArea;
	EHANDLE m_avoid;
	float m_avoidTimestamp;
	bool m_isJumpCrouching;
	bool m_isJumpCrouched;
	float m_jumpCrouchTimestamp;

	enum { 	MAX_PATH_LENGTH = 256 };

	struct ConnectInfo
	{
		CNavArea *area;
		NavTraverseType how;
		Vector pos;
		const CNavLadder *ladder;
	} m_path[MAX_PATH_LENGTH];
	/* size: 24, cachelines: 1, members: 4 */

	int m_pathLength;
	int m_pathIndex;
	float m_areaEnteredTimestamp;
	CountdownTimer m_repathTimer;
	mutable CountdownTimer m_avoidFriendTimer;
	mutable bool m_isFriendInTheWay;
	CountdownTimer m_politeTimer;
	bool m_isWaitingBehindFriend;

	enum LadderNavState
	{
		APPROACH_ASCENDING_LADDER,
		APPROACH_DESCENDING_LADDER,
		FACE_ASCENDING_LADDER,
		FACE_DESCENDING_LADDER,
		MOUNT_ASCENDING_LADDER,
		MOUNT_DESCENDING_LADDER,
		ASCEND_LADDER,
		DESCEND_LADDER,
		DISMOUNT_ASCENDING_LADDER,
		DISMOUNT_DESCENDING_LADDER,
		MOVE_TO_DESTINATION,
	}
	m_pathLadderState;
	bool m_pathLadderFaceIn;
	CNavLadder *m_pathLadder;			// 9260
	NavRelativeDirType m_pathLadderDismountDir;
	float m_pathLadderDismountTimestamp;
	float m_pathLadderEnd;
	float m_pathLadderTimestamp;
	class CountdownTimer m_mustRunTimer;
	CSGameState m_gameState;
	byte m_hostageEscortCount;
	float m_hostageEscortCountTimestamp;
	bool m_isWaitingForHostage;
	CountdownTimer m_inhibitWaitingForHostageTimer;
	CountdownTimer m_waitForHostageTimer;
	Vector m_noisePosition;
	float m_noiseTimestamp;
	CNavArea *m_noiseArea;
	float m_noiseCheckTimestamp;
	PriorityType m_noisePriority;
	bool m_isNoiseTravelRangeChecked;
	float m_lookAroundStateTimestamp;
	float m_lookAheadAngle;
	float m_forwardAngle;
	float m_inhibitLookAroundTimestamp;

	enum LookAtSpotState
	{
		NOT_LOOKING_AT_SPOT = 0,
		LOOK_TOWARDS_SPOT,
		LOOK_AT_SPOT,
		NUM_LOOK_AT_SPOT_STATES,
	}
	m_lookAtSpotState;
	Vector m_lookAtSpot;

	PriorityType m_lookAtSpotPriority;
	float m_lookAtSpotDuration;
	float m_lookAtSpotTimestamp;
	float m_lookAtSpotAngleTolerance;
	bool m_lookAtSpotClearIfClose;
	const char *m_lookAtDesc;
	float m_peripheralTimestamp;

	enum { MAX_APPROACH_POINTS = 16 };
	Vector m_approachPoint[MAX_APPROACH_POINTS];
	unsigned char m_approachPointCount;
	Vector m_approachPointViewPosition;

	bool m_isWaitingToTossGrenade;
	CountdownTimer m_tossGrenadeTimer;
	SpotEncounter *m_spotEncounter;
	float m_spotCheckTimestamp;

	enum { MAX_CHECKED_SPOTS = 64 };
	struct HidingSpotCheckInfo
	{
		HidingSpot *spot;
		float timestamp;
	}/* size: 8, cachelines: 1, members: 2 */
	m_checkedHidingSpot[MAX_CHECKED_SPOTS];
	int m_checkedHidingSpotCount;

	float m_lookPitch;			// 10500
	float m_lookPitchVel;
	float m_lookYaw;
	float m_lookYawVel;
	Vector m_eyePos;
	Vector m_aimOffset;
	Vector m_aimOffsetGoal;
	float m_aimOffsetTimestamp;
	float m_aimSpreadTimestamp;
	Vector m_aimSpot;
	DispositionType m_disposition;
	CountdownTimer m_ignoreEnemiesTimer;
	mutable EHANDLE m_enemy;
	bool m_isEnemyVisible;
	unsigned char m_visibleEnemyParts;
	Vector m_lastEnemyPosition;
	float m_lastSawEnemyTimestamp;
	float m_firstSawEnemyTimestamp;
	float m_currentEnemyAcquireTimestamp;
	float m_enemyDeathTimestamp;
	bool m_isLastEnemyDead;
	int m_nearbyEnemyCount;
	unsigned int m_enemyPlace;

	struct WatchInfo
	{
		float timestamp;
		bool isEnemy;
	}/* size: 8, cachelines: 1, members: 2 */
	m_watchInfo[32];

	mutable EHANDLE m_bomber;
	int m_nearbyFriendCount;
	mutable EHANDLE m_closestVisibleFriend;
	mutable EHANDLE m_closestVisibleHumanFriend;
	CBasePlayer *m_attacker;
	float m_attackedTimestamp;
	int m_lastVictimID;
	bool m_isAimingAtEnemy;
	bool m_isRapidFiring;
	IntervalTimer m_equipTimer;
	float m_fireWeaponTimestamp;

	enum { MAX_ENEMY_QUEUE = 20 };
	struct ReactionState
	{
		EHANDLE player;
		bool isReloading;
		bool isProtectedByShield;
	} m_enemyQueue[MAX_ENEMY_QUEUE];
	/* size: 12, cachelines: 1, members: 3 */

	byte m_enemyQueueIndex;
	byte m_enemyQueueCount;
	byte m_enemyQueueAttendIndex;
	bool m_isStuck;
	float m_stuckTimestamp;
	Vector m_stuckSpot;
	NavRelativeDirType m_wiggleDirection;
	float m_wiggleTimestamp;
	float m_stuckJumpTimestamp;

	enum { MAX_VEL_SAMPLES = 5 };

	float m_avgVel[MAX_VEL_SAMPLES];
	int m_avgVelIndex;
	int m_avgVelCount;
	Vector m_lastOrigin;

	GameEventType m_lastRadioCommand;
	float m_lastRadioRecievedTimestamp;
	float m_lastRadioSentTimestamp;
	EHANDLE m_radioSubject;
	Vector m_radioPosition;
	float m_voiceFeedbackStartTimestamp;
	float m_voiceFeedbackEndTimestamp;
	BotChatterInterface m_chatter;
	CNavNode *m_navNodeList;
	CNavNode *m_currentNode;
	NavDirType m_generationDir;
	NavAreaList::iterator m_analyzeIter;		// TODO: //iterator m_analyzeIter;

	enum ProcessType
	{
		PROCESS_NORMAL = 0,
		PROCESS_LEARN,
		PROCESS_ANALYZE_ALPHA,
		PROCESS_ANALYZE_BETA,
		PROCESS_SAVE,
	}
	m_processMode;
	CountdownTimer m_mumbleTimer;
	CountdownTimer m_booTimer;
	CountdownTimer m_relocateTimer;

};/* size: 11424, cachelines: 179, members: 161 */

/* <2e8465> ../cstrike/dlls/bot/cs_bot.cpp:1004 */
class CollectRetreatSpotsFunctor
{
public:
	CollectRetreatSpotsFunctor(CCSBot *me, float range)
	{
		m_me = me;
		m_count = 0;
		m_range = range;
	}

	enum { MAX_SPOTS = 256 };

	bool operator()(CNavArea *area)
	{
		// collect all the hiding spots in this area
		const HidingSpotList *list = area->GetHidingSpotList();

		for (HidingSpotList::const_iterator iter = list->begin(); iter != list->end() && m_count < MAX_SPOTS; ++iter)
		{
			const HidingSpot *spot = *iter;

			// make sure hiding spot is in range
			if (m_range > 0.0f)
				if ((*spot->GetPosition() - m_me->pev->origin).IsLengthGreaterThan(m_range))
					continue;

			// if a Player is using this hiding spot, don't consider it
			if (IsSpotOccupied(m_me, spot->GetPosition()))
			{
				// player is in hiding spot
				/// @todo Check if player is moving or sitting still
				continue;
			}

			// don't select spot if an enemy can see it
			if (UTIL_IsVisibleToTeam(*spot->GetPosition() + Vector(0, 0, HalfHumanHeight), OtherTeam(m_me->m_iTeam )))
				continue;

			// don't select spot if it is closest to an enemy
			CBasePlayer *owner = UTIL_GetClosestPlayer(spot->GetPosition());
			if (owner && m_me->m_iTeam != owner->m_iTeam)
				continue;

			m_spot[ m_count++ ] = spot->GetPosition();
		}

		// if we've filled up, stop searching
		if (m_count == MAX_SPOTS)
			return false;

		return true;
	}
private:

	CCSBot *m_me;
	float m_range;

	const Vector *m_spot[ MAX_SPOTS ];
	int m_count;

};/* size: 1036, cachelines: 17, members: 4 */

/* <2e7f9f> ../cstrike/dlls/bot/cs_bot.cpp:1088 */
class FarthestHostage
{
public:
	FarthestHostage(CCSBot *me)//, float range)
	{
		m_me = me;
		//m_farRange = range;
	}
	bool operator()(CHostage *hostage)
	{
		//TODO: untested

		if (!hostage->IsFollowing(m_me))
			return false;

		return true;
	}
private:
	const CCSBot *m_me;
	float m_farRange;

};/* size: 8, cachelines: 1, members: 2 */

/* <5a0af3> ../cstrike/dlls/bot/cs_bot.h:1114 */
class PathCost
{
public:
	PathCost(CCSBot *bot, RouteType route = SAFEST_ROUTE)
	{
		m_bot = bot;
		m_route = route;
	}
	float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder)
	{
		/*#define NAV_MESH_JUMP 0x0002

		float baseDangerFactor = 100.0f;
		float dangerFactor = (1.0f - (0.95f * m_bot->GetProfile()->GetAggression())) * baseDangerFactor;

		if (fromArea == NULL)
		{
			if (m_route == FASTEST_ROUTE)
				return 0.0f;
			return dangerFactor * area->GetDanger(m_bot->m_iTeam);
		}
		else if ((fromArea->GetAttributes() & NAV_MESH_JUMP) && (area->GetAttributes() & NAV_MESH_JUMP))
		{
			return -1.0f;
		}
		else
		{
			float dist;
			if (ladder)
			{
				const float ladderPenalty = 1.0f;
				dist = ladderPenalty * ladder->m_length;

				//if (m_bot->GetHostageEscortCount())
				//	dist *= 100.0f;
			}
			else
			{
				dist = (area->GetCenter() - fromArea->GetCenter()).Length();
			}
			float cost = dist + fromArea->GetCostSoFar();
			if (cv_bot_zombie.value)
				return cost;

			if (!area->IsUnderwater() && area->IsConnected(fromArea, NUM_DIRECTIONS) == false)
			{
				float fallDistance = -fromArea->ComputeHeightChange(area);
				if (ladder && ladder->m_bottom.z < fromArea->GetCenter().z && ladder->m_bottom.z > area->GetCenter().z)
				{
					fallDistance = ladder->m_bottom.z - area->GetCenter().z;
				}
				float fallDamage = m_bot->GetApproximateFallDamage(fallDistance);
				if (fallDamage > 0.0f)
				{
					const float deathFallMargin = 10.0f;
					if (fallDamage + deathFallMargin >= m_bot->pev->health)
						return -1.0f;
					const float painTolerance = 15.0f * m_bot->GetProfile()->GetAggression() + 10.0f;
					if (m_route != FASTEST_ROUTE || fallDamage > painTolerance)
					{
						cost += 100.0f * fallDamage * fallDamage;
					}
				}
			}
			if (area->GetAttributes() & (NAV_MESH_CROUCH | NAV_MESH_WALK))
			{
				float penalty = (m_route == FASTEST_ROUTE) ? 20.0f : 5.0f;
				cost += penalty * dist;
			}
			if (area->GetAttributes() & NAV_MESH_JUMP)
			{
				const float jumpPenalty = 1.0f;
				cost += jumpPenalty * dist;
			}
			if (area->GetAttributes() & NAV_MESH_AVOID)
			{
				const float avoidPenalty = 20.0f;
				cost += avoidPenalty * dist;
			}
			if (m_route == SAFEST_ROUTE)
			{
				cost += dist * dangerFactor * area->GetDanger(m_bot->GetTeamNumber());
			}
			if (!m_bot->IsAttacking())
			{
				float size = (area->GetSizeX() + area->GetSizeY()) / 2.0f;
				if (size >= 1.0f)
				{
					const float costPerFriendPerUnit = 50000.0f;
					cost += costPerFriendPerUnit * (float)area->GetPlayerCount(m_bot->GetTeamNumber()) / size;
				}
			}
			return cost;
		}*/

		return 0.0f;
	}

private:
	CCSBot *m_bot;
	RouteType m_route;

};/* size: 8, cachelines: 1, members: 2 */

/* <568fae> ../cstrike/dlls/bot/states/cs_bot_follow.cpp:95 */
class FollowTargetCollector
{
public:
	FollowTargetCollector(CBasePlayer *player)
	{
		m_player = player;

		Vector playerVel = player->pev->velocity;

		m_forward.x = playerVel.x;
		m_forward.y = playerVel.y;

		float speed = m_forward.NormalizeInPlace();

		Vector playerOrigin = player->pev->origin;

		const float walkSpeed = 100.0f;
		if (speed < walkSpeed)
		{
			m_cutoff.x = playerOrigin.x;
			m_cutoff.y = playerOrigin.y;

			m_forward.x = 0.0f;
			m_forward.y = 0.0f;
		}
		else
		{
			const float k = 1.5f; // 2.0f;
			float trimSpeed = (speed < 200.0f) ? speed : 200.0f;

			m_cutoff.x = playerOrigin.x + k * trimSpeed * m_forward.x;
			m_cutoff.y = playerOrigin.y + k * trimSpeed * m_forward.y;
		}

		m_targetAreaCount = 0;
	}

	enum { MAX_TARGET_AREAS = 128 };

	/* <568dc3> ../cstrike/dlls/bot/states/cs_bot_follow.cpp:124 */
	bool operator()(CNavArea *area)
	{
		if (m_targetAreaCount >= MAX_TARGET_AREAS)
			return false;

		// only use two-way connections
		if (!area->GetParent() || area->IsConnected(area->GetParent(), NUM_DIRECTIONS))
		{
			if (m_forward.IsZero())
			{
				m_targetArea[ m_targetAreaCount++ ] = area;
			}
			else
			{
				// collect areas in the direction of the player's forward motion
				Vector2D to(((*area->GetCenter()).x - m_cutoff.x), (*area->GetCenter()).y - m_cutoff.y);
				to.NormalizeInPlace();

				//if (DotProduct(to, m_forward) > 0.7071f)
				if ((to.x * m_forward.x + to.y * m_forward.y) > 0.7071f)
					m_targetArea[ m_targetAreaCount++ ] = area;
			}
		}

		return (m_targetAreaCount < MAX_TARGET_AREAS);
	}

	CBasePlayer *m_player;
	Vector2D m_forward;
	Vector2D m_cutoff;
	CNavArea *m_targetArea[ MAX_TARGET_AREAS ];
	int m_targetAreaCount;

};/* size: 536, cachelines: 9, members: 5 */

#ifdef HOOK_GAMEDLL

//typedef bool (CCSBot::*IS_VISIBLE_VECTOR)(Vector *, bool);
//typedef bool (CCSBot::*IS_VISIBLE_CBASEPLAYER)(CBasePlayer *, bool, unsigned char *);

typedef void (CCSBot::*HIDE_NAV_AREA)(CNavArea *, float, float, bool);
typedef void (CCSBot::*HIDE_VECTOR)(const Vector *, float, bool);

typedef const CSGameState *(CCSBot::*GETGAMESTATE_CONST)(void) const;
typedef CSGameState *(CCSBot::*GETGAMESTATE_NOTCONST)(void);

#endif // HOOK_GAMEDLL

NOBODY void InstallBotControl(void);
void Bot_ServerCommand(void);
void Bot_RegisterCvars(void);
NOBODY int GetBotFollowCount(CBasePlayer *leader);
NOBODY const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange);

NOXREF void drawProgressMeter(float progress, char *title);
NOXREF void startProgressMeter(const char *title);
NOXREF void hideProgressMeter(void);

bool isSniperRifle(CBasePlayerItem *item);
float StayOnLadderLine(CCSBot *me, const CNavLadder *ladder);

// refs

extern void (*pCCSBot__UpdateLookAngles)(void);
extern void (*pCCSBot__Update)(void);
extern void (*pCCSBot__ResetValues)(void);

#endif // CS_BOT_H