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

===== player.cpp ========================================================

  functions dealing with the player

*/

#include "extdll.h"
#include "util.h"

#include "cbase.h"
//added by harSens
#include "effects.h"
#include "aura.h"
#include "classes.h"
#include "candy.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "magicattack.h"
#include "powerstruggle.h"
#include "explodingattack.h"
#include "player.h"
#include "pm_shared.h"
#include <string.h>
/* removed by harSens
#include "trains.h"
*/
#include "nodes.h"
#include "weapons.h"
#include "soundent.h"
#include "monsters.h"
#include "shake.h"
#include "decals.h"
#include "gamerules.h"
#include "game.h"
#include "hltv.h"
// Addeded by Pcjoe
#include "blob.h"
#include "shield.h"

// added by Rick
#include "../bot/bot.h"
#include "../bot/bot_chat.h"
#include "../bot/bot_util.h"
#include "talkmonster.h"
#include "buddy_aura.h"
#include "buddy.h"
extern CChatClass ChatClass;
// end add by Rick

// #define DUCKFIX

extern DLL_GLOBAL ULONG		g_ulModelIndexPlayer;
extern DLL_GLOBAL BOOL		g_fGameOver;
extern DLL_GLOBAL	BOOL	g_fDrawLines;
int gEvilImpulse101;
extern DLL_GLOBAL int		g_iSkillLevel, gDisplayTitle;
//added by harSens
extern Vector g_vecAuraColor[];
// Added by Pcjoe
extern cvar_t laydowntime;
extern cvar_t nomeleehittime;
extern cvar_t melee_wallstick_canstick;
extern cvar_t melee_wallstick_mintime;
extern cvar_t melee_wallstick_maxtime;
extern cvar_t spawn_invulnerable_time;
extern cvar_t melee_swoop_minstrugtime;
extern cvar_t charge_turbo_time;
extern cvar_t charge_turbo_hold_time;
extern cvar_t charge_turbo_use_time;
extern cvar_t charge_turbo_multi_top;


BOOL gInitHUD = TRUE;

extern void CopyToBodyQue(entvars_t* pev);
extern void respawn(entvars_t *pev, BOOL fCopyCorpse);
extern Vector VecBModelOrigin(entvars_t *pevBModel );
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );

// the world node graph
extern CGraph	WorldGraph;

#define TRAIN_ACTIVE	0x80 
#define TRAIN_NEW		0xc0
#define TRAIN_OFF		0x00
#define TRAIN_NEUTRAL	0x01
#define TRAIN_SLOW		0x02
#define TRAIN_MEDIUM	0x03
#define TRAIN_FAST		0x04 
#define TRAIN_BACK		0x05

#define	FLASH_DRAIN_TIME	 1.2 //100 units/3 minutes
#define	FLASH_CHARGE_TIME	 0.2 // 100 units/20 seconds  (seconds per unit)

//added by harSens
#define POWERLEVEL_INCREASE				600
#define	KI_INCREASE_RATE				3.5
#define	STAMINA_INCREASE_RATE			25*KI_UPDATE_TIME
#define EXHAUST_STAMINA					100
#define HEALTHY_STAMINA					350
#define EXHAUST_TIME					2.0

#define FLY_KI_COST						  1			//cost of flying per ki-update
#define TURBO_KI_COST					  2			//cost of turbo per ki-update
#define TELEPORT_KI_COST				150			//cost of a teleport 
#define TELEPORT_MAXSTAMINA_COST		400			//max cost of a teleport 
//#define ASCEND_KI_COST					100		//cost of ascending
#define JUMP_KI_COST					 20
#define SUPER_JUMP_KI_COST				 50
#define	POWERUP_KI_INCREASE_RATE		 70
#define	POWERUP_STAMINA_INCREASE_RATE	 50*KI_UPDATE_TIME
#define TELEPORT_DISTANCE				267
#define BLOCKSTRUGGLE_KI_COST			  5
#define KI_UPDATE_TIME					  0.20
#define BLOCKSTRUGGLE_TIME				  0.20	
#define MAX_SENSUBEAN					  5			//max amount of senzubeans to be hold
#define TURBO_SPEED_MULTIPLIER			  2
//#define MELEE_SWOOP_COST				 12		//cost of swoop per ki-update(using same time)
//#define MELEE_DASH_COST					  8
#define MELEE_TOSS_SLOWDOWN				  1.075
#define MELEE_TOSS_MINSPEED				600
#define MELEE_MAX_ROLL_SPEED			725
#define TELEPORTFX_FADETIME				1.5
#define MELEE_WALLSTICK_RECOVER_COST	100
#define TELEPORT_DELAY					  0.13

// Pcjoe: Temp cvar for testers
extern cvar_t ki_cost_swoop;
extern cvar_t ki_cost_dash;

// --- General stuff
#define DEEP_IDLE_TIME					  5
#define	FALLAPART_TIME					  1.5
#define PL_GAIN_MULTI_MELEE				  2
// Global Savedata for player
TYPEDESCRIPTION	CBasePlayer::m_playerSaveData[] = 
{	/* removed by harSens
	DEFINE_FIELD( CBasePlayer, m_flFlashLightTime, FIELD_TIME ),
	DEFINE_FIELD( CBasePlayer, m_iFlashBattery, FIELD_INTEGER ),
	*/

	DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ),

	DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS) ,
	DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ),

	DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ),
	DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ),
	DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ),
//	DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ),
	DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ),

	DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ),
	DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ),
	DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ),
	DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ),
	DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ),
	DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ),

	DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ),
	DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ),
	DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ),
	
	/*disabled by harSens
	DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ),
	*/
	DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ),

	DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ),
	DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ),
	DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ),
	DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ),

	DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ),
	DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ),
	DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ),
	
	//DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games
	//DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games
	//DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ),
	DEFINE_FIELD( CBasePlayer, m_fKnownItem, FIELD_INTEGER ), // reset to zero on load
	//DEFINE_FIELD( CBasePlayer, m_iPlayerSound, FIELD_INTEGER ),	// Don't restore, set in Precache()
	//DEFINE_FIELD( CBasePlayer, m_pentSndLast, FIELD_EDICT ),	// Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_flSndRoomtype, FIELD_FLOAT ),	// Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_flSndRange, FIELD_FLOAT ),	// Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_fNewAmmo, FIELD_INTEGER ), // Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_flgeigerRange, FIELD_FLOAT ),	// Don't restore, reset in Precache()
	//DEFINE_FIELD( CBasePlayer, m_flgeigerDelay, FIELD_FLOAT ),	// Don't restore, reset in Precache()
	//DEFINE_FIELD( CBasePlayer, m_igeigerRangePrev, FIELD_FLOAT ),	// Don't restore, reset in Precache()
	//DEFINE_FIELD( CBasePlayer, m_iStepLeft, FIELD_INTEGER ), // Don't need to restore
	//DEFINE_ARRAY( CBasePlayer, m_szTextureName, FIELD_CHARACTER, CBTEXTURENAMEMAX ), // Don't need to restore
	//DEFINE_FIELD( CBasePlayer, m_chTextureType, FIELD_CHARACTER ), // Don't need to restore
	//DEFINE_FIELD( CBasePlayer, m_fNoPlayerSound, FIELD_BOOLEAN ), // Don't need to restore, debug
	//DEFINE_FIELD( CBasePlayer, m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore
	//DEFINE_FIELD( CBasePlayer, m_iClientHealth, FIELD_INTEGER ), // Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_fWeapon, FIELD_BOOLEAN ),  // Don't restore, client needs reset
	//DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't restore, depends on server message after spawning and only matters in multiplayer
	//DEFINE_FIELD( CBasePlayer, m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed
	//DEFINE_ARRAY( CBasePlayer, m_rgAmmoLast, FIELD_INTEGER, MAX_AMMO_SLOTS ), // Don't need to restore
	//DEFINE_FIELD( CBasePlayer, m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore
	//DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't need to restore
	
};	


int giPrecacheGrunt = 0;
int gmsgShake = 0;
int gmsgFade = 0;
/*disabled by harSens
int gmsgSelAmmo = 0;
int gmsgFlashlight = 0;
int gmsgFlashBattery = 0;
*/
int gmsgResetHUD = 0;
int gmsgInitHUD = 0;
/* removed by harSens
int gmsgShowGameTitle = 0;
*/
int gmsgCurWeapon = 0;
int gmsgHealth = 0;
/*disabled by harSens
int gmsgDamage = 0;
int gmsgBattery = 0;
/* disabled by harSens
int gmsgTrain = 0;
*/
int gmsgLogo = 0;
int gmsgWeaponList = 0;
/* disabled by harSens
int gmsgAmmoX = 0;
*/
int gmsgHudText = 0;
int gmsgDeathMsg = 0;
int gmsgScoreInfo = 0;
int gmsgTeamInfo = 0;
int gmsgTeamScore = 0;
int gmsgGameMode = 0;
int gmsgMOTD = 0;
int gmsgServerName = 0;
/*
int gmsgAmmoPickup = 0;
*/
/* disabled by harSens
int gmsgWeapPickup = 0;
int gmsgItemPickup = 0;
int gmsgSetCurWeap = 0;
*/
int gmsgHideWeapon = 0;
int gmsgSayText = 0;
int gmsgTextMsg = 0;
int gmsgSetFOV = 0;
int gmsgShowMenu = 0;
/* removed by harSens
int gmsgGeigerRange = 0;
*/
int gmsgTeamNames = 0;

/* removed by harSens
int gmsgStatusText = 0;
int gmsgStatusValue = 0; 
*/
//added by harSens
// Removed by Pcjoe
//int gmsgSpeed = 0;
int gmsgChangeView = 0; 
int gmsgVGUIMenu = 0;
int gmsgCharge = 0;
int gmsgMaxHealth = 0;
int gmsgPowerLevel = 0;
int gmsgExplosion = 0;
int gmsgPowerStruggle = 0;
int gmsgBlockStruggle = 0;
int gmsgAddEffect = 0;
int gmsgRemoveEffect = 0;
int gmsgUpdateEffect = 0;
//int gmsgChargeSB = 0;
//int gmsgStopSBCharge = 0;
int gmsgSensuBean = 0;
int gmsgSBCTrail = 0;
int gmsgEntEntTrail = 0;
int gmsgFlare = 0;
int gmsgBall = 0;
int gmsgKillTrail = 0;
int gmsgDragonBallEnt = 0;
int gmsgAllowSpec = 0;
int gmsgSpectator = 0;
int gmsgPowerupFX = 0;
int gmsgStopPowerupFX = 0;
int gmsgTransform = 0;
/* experimental shell chrome by harSens
int gmsgSetShellChrome = 0;
*/
int gmsgDetachTrail = 0;
int gmsgBoundingBox = 0;
int gmsgFog = 0;
int gmsgWeaponUpdate = 0;
// Added by Pcjoe
int gmsgInitHUDMap = 0;
int gmsgTransformFX = 0;
int gmsgStopTransformFX = 0;
int gmsgMeleeFX	= 0;
int gmsgBlobStart = 0;
int gmsgBlobUpdate = 0;
int gmsgBlobKill = 0;
int gmsgManipModel = 0;
int gmsgMeleeAtkHud = 0;
int gmsgMeleeTxtHud = 0;
int gmsgAfterFX = 0;
int gmsgCustomModel = 0;
// Added by Rick
int gmsgBotVGUI = 0;
//added by harSens
int gmsgStamina = 0;

// ADDED BY IAN:: msgs in relation to your buddy
//
// this will include
//  BuddyHealth
//  BuddyKI
//
// if the values are negative then your buddy died (this way we only use 1 msg)
int gmsgBuddyUpdate = 0;
int gmsgBuddyStatus = 0;
// ADDED BY IAN:: msgs in relation to your buddy

void LinkUserMessages( void )
{
	// Already taken care of?
	/* modified by harSens
	if ( gmsgSelAmmo )
	{
		return;
	}
	*/
	if ( gmsgCurWeapon )
	{
		return;
	}
	

	/* disabled by harSens
	gmsgSelAmmo = REG_USER_MSG("SelAmmo", sizeof(SelAmmo));
	*/
	gmsgCurWeapon = REG_USER_MSG("CurWeapon", 3);

	/* disabled by harSens
	gmsgGeigerRange = REG_USER_MSG("Geiger", 1);
	gmsgFlashlight = REG_USER_MSG("Flashlight", 2);
	gmsgFlashBattery = REG_USER_MSG("FlashBat", 1);
	*/
	gmsgHealth = REG_USER_MSG( "Health", 1 );
	/*disabled by harSens
	gmsgDamage = REG_USER_MSG( "Damage", 12 );
	gmsgBattery = REG_USER_MSG( "Battery", 2);	
	gmsgTrain = REG_USER_MSG( "Train", 1);
	*/
	gmsgHudText = REG_USER_MSG( "HudText", -1 );
	gmsgSayText = REG_USER_MSG( "SayText", -1 );
	gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
	gmsgWeaponList = REG_USER_MSG("WeaponList", -1);
	gmsgResetHUD = REG_USER_MSG("ResetHUD", 1);		// called every respawn
	gmsgInitHUD = REG_USER_MSG("InitHUD", 0 );		// called every time a new player joins the server
	/*
	gmsgShowGameTitle = REG_USER_MSG("GameTitle", 1);
	*/
	gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 );
	gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 13 );
	gmsgTeamInfo = REG_USER_MSG( "TeamInfo", -1 );  // sets the name of a player's team
	gmsgTeamScore = REG_USER_MSG( "TeamScore", -1 );  // sets the score of a team on the scoreboard
	/* modified by harSens
	gmsgGameMode = REG_USER_MSG( "GameMode", 1 );
	*/
	gmsgGameMode = REG_USER_MSG( "GameMode", 2 );
	
	gmsgMOTD = REG_USER_MSG( "MOTD", -1 );
	gmsgServerName = REG_USER_MSG( "ServerName", -1 );
	/* disabled by harSens
	gmsgAmmoPickup = REG_USER_MSG( "AmmoPickup", 2 );
	gmsgWeapPickup = REG_USER_MSG( "WeapPickup", 1 );
	gmsgItemPickup = REG_USER_MSG( "ItemPickup", -1 );
	*/
	gmsgHideWeapon = REG_USER_MSG( "HideWeapon", 1 );
	gmsgSetFOV = REG_USER_MSG( "SetFOV", 1 );
	gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 );
	gmsgShake = REG_USER_MSG("ScreenShake", sizeof(ScreenShake));
	gmsgFade = REG_USER_MSG("ScreenFade", sizeof(ScreenFade));
	/* disabled by harSens
	gmsgAmmoX = REG_USER_MSG("AmmoX", 2);
	*/
	gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 );

	//added by harSens
	gmsgVGUIMenu = REG_USER_MSG("VGUIMenu", 1);
	gmsgChangeView = REG_USER_MSG("ChangeView", 2);
	gmsgCharge = REG_USER_MSG("Charge", 1);
	gmsgMaxHealth = REG_USER_MSG("MaxHealth", 1);
	gmsgPowerLevel = REG_USER_MSG("PowerLevel", 5);	
	gmsgExplosion = REG_USER_MSG("Explosion", 11);
	gmsgPowerStruggle = REG_USER_MSG("PowerStrug",1);
	gmsgBlockStruggle = REG_USER_MSG("BlockStrug",4);
	gmsgWeaponUpdate = REG_USER_MSG("WeapUpdate",1);
	gmsgSpectator = REG_USER_MSG( "Spectator", 2 );
	gmsgAllowSpec = REG_USER_MSG("AllowSpec",1);	
	gmsgAddEffect = REG_USER_MSG("AddEffect",-1);
	gmsgRemoveEffect = REG_USER_MSG("RemEffect",-1);
	gmsgUpdateEffect = REG_USER_MSG("UpdEffect",-1);
	gmsgSensuBean = REG_USER_MSG("SensuBean",1);
	gmsgSBCTrail = REG_USER_MSG("SBCTrail",20);
	gmsgEntEntTrail = REG_USER_MSG("EETrail",27);
	gmsgFlare = REG_USER_MSG("Flare",20);
	gmsgBall = REG_USER_MSG("Ball",6);
	gmsgKillTrail = REG_USER_MSG("KillTrail",4);	
	gmsgDragonBallEnt = REG_USER_MSG("DBEnt",3);
	gmsgPowerupFX = REG_USER_MSG("Powerup",4);
	gmsgStopPowerupFX = REG_USER_MSG("StopPowerup",1);
	gmsgTransform = REG_USER_MSG("Transform",5);
	/* experimental shell chrome by harSens
	gmsgSetShellChrome = REG_USER_MSG("SetChrome",2);
	*/
	gmsgDetachTrail = REG_USER_MSG("DetachTrail",4);
	gmsgBoundingBox = REG_USER_MSG("BoundingBox",4);
	gmsgFog = REG_USER_MSG("Fog", 7);

	// Added by Pcjoe
	gmsgTransformFX = REG_USER_MSG("TransformFX",3);
	gmsgStopTransformFX = REG_USER_MSG("StopTransFX",1);
	gmsgMeleeFX = REG_USER_MSG("MeleeFX", 2);
	gmsgBlobStart = REG_USER_MSG("BlobStart", 11);
	gmsgBlobUpdate = REG_USER_MSG("BlobUpdate", 4);
	gmsgBlobKill = REG_USER_MSG("BlobKill", 4);
	gmsgManipModel = REG_USER_MSG("ManipModel", -1);
	gmsgMeleeAtkHud = REG_USER_MSG("MeleeAtkHud", -1);
	gmsgMeleeTxtHud = REG_USER_MSG("MeleeTxtHud", 2);
	gmsgAfterFX = REG_USER_MSG("AfterFX", 7);
	gmsgInitHUDMap = REG_USER_MSG("InitHUDMap", 0 ); // called every time a new map is loaded
	gmsgCustomModel = REG_USER_MSG("CustomModel", -1);
	/* removed by harSens
	gmsgStatusText = REG_USER_MSG("StatusText", -1);
	gmsgStatusValue = REG_USER_MSG("StatusValue", 3); 
	*/

	// ADDED BY IAN:: msgs in relation to your buddy
	gmsgBuddyUpdate = REG_USER_MSG("BuddyUpdate", 8);
	gmsgBuddyStatus = REG_USER_MSG("BuddyStatus", 18);
	// ADDED BY IAN:: msgs in relation to your buddy

	// Added by Rick
	gmsgBotVGUI = REG_USER_MSG("BotVGUI", -1);

	//added by harSens
	gmsgStamina =REG_USER_MSG("Stamina", 4);
}

LINK_ENTITY_TO_CLASS( player, CBasePlayer );

class CAfterImage : public CBaseEntity
{
public:
	void Spawn();
	void EXPORT FadeOutThink();
private:
	float m_flSpawnTime;
};
LINK_ENTITY_TO_CLASS( afterimage, CAfterImage );

void CAfterImage::FadeOutThink()
{
	float flTimeDelta = (gpGlobals->time-m_flSpawnTime)/TELEPORTFX_FADETIME;
	if(flTimeDelta > 0 && flTimeDelta < 1)
	{	pev->renderamt = (1.0-flTimeDelta)*255;
		pev->nextthink = gpGlobals->time+TELEPORTFX_FADETIME/25;		
	}
	else
	{	UTIL_Remove(this);	
	}
}
void CAfterImage::Spawn()
{
	pev->renderfx = kRenderFxTeleportAfterImage;	
	pev->rendermode = kRenderTransTexture;
	pev->renderamt = 255;
	pev->classname = MAKE_STRING("afterimage");
	m_flSpawnTime = gpGlobals->time;
	SetThink(&CAfterImage::FadeOutThink);
	SetTouch(NULL);
	pev->nextthink = gpGlobals->time + 0.1;
}

/**
* Bag containing dead players items (only sensubeans for now)
* @version 25-9-2001
* @author Herwin 'harSens' van Welbergen
*/
class CPlayerBag : public CBaseEntity
{	
public:
	/**
	* Precaches models
	*/
	void Precache( void );

	/**
	* Spawn the bag
	*/
	void Spawn( void );

	/**
	* touch function
	* @param CBaseEntity *pOther: item that touches it
	*/
	void Touch( CBaseEntity *pOther );
	
	/**
	* Creates a bag
	*/
	static CPlayerBag *CreateBag(int beans, CBasePlayer *pl);
	int m_iSensuBeans;
};

void CPlayerBag::Precache()
{	PRECACHE_MODEL("models/w_sensubeanbag.mdl");
}

void CPlayerBag::Spawn()
{	Precache();
	SET_MODEL(ENT(pev),"models/w_sensubeanbag.mdl");
	pev->movetype = MOVETYPE_TOSS;
	pev->solid = SOLID_TRIGGER;
	UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));	
}

void CPlayerBag::Touch(CBaseEntity *pOther)
{	if (pOther->IsPlayer())
	{	((CBasePlayer*)pOther)->GiveBean(m_iSensuBeans);
		UTIL_Remove(this);
	}
}

CPlayerBag *CPlayerBag::CreateBag(int beans, CBasePlayer *pl)
{	CPlayerBag *pPlayerBag = GetClassPtr( (CPlayerBag *)NULL );
	pPlayerBag->Spawn();
	
	pPlayerBag->pev->origin = pl->pev->origin;
	UTIL_SetOrigin(pPlayerBag->pev,pPlayerBag->pev->origin);

	pPlayerBag->pev->velocity = pl->pev->velocity;
	pPlayerBag->m_iSensuBeans = beans;

	return pPlayerBag;
}
void CBasePlayer :: Pain( void )
{	/* modified by harSens
	float	flRndSound;//sound randomizer

	flRndSound = RANDOM_FLOAT ( 0 , 1 ); 
	
	if ( flRndSound <= 0.33 )
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM);
	else if ( flRndSound <= 0.66 )	
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM);
	else
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM);
	*/
	if(!m_Melee.InAdvMeleeBattle())
	{	int iRndSound = RANDOM_LONG(1,4);
		char pPainSound[255];
		sprintf(pPainSound,"pain%d.wav",iRndSound);
		EmitClassSound(pPainSound);
	}
}

/* 
 *
 */
Vector VecVelocityForDamage(float flDamage)
{
	Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300));

	if (flDamage > -50)
		vec = vec * 0.7;
	else if (flDamage > -200)
		vec = vec * 2;
	else
		vec = vec * 10;
	
	return vec;
}

#if 0 /*
static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage)
{
	edict_t *pentNew = CREATE_ENTITY();
	entvars_t *pevNew = VARS(pentNew);

	pevNew->origin = pev->origin;
	SET_MODEL(ENT(pevNew), szGibModel);
	UTIL_SetSize(pevNew, g_vecZero, g_vecZero);

	pevNew->velocity		= VecVelocityForDamage(flDamage);
	pevNew->movetype		= MOVETYPE_BOUNCE;
	pevNew->solid			= SOLID_NOT;
	pevNew->avelocity.x		= RANDOM_FLOAT(0,600);
	pevNew->avelocity.y		= RANDOM_FLOAT(0,600);
	pevNew->avelocity.z		= RANDOM_FLOAT(0,600);
	CHANGE_METHOD(ENT(pevNew), em_think, SUB_Remove);
	pevNew->ltime		= gpGlobals->time;
	pevNew->nextthink	= gpGlobals->time + RANDOM_FLOAT(10,20);
	pevNew->frame		= 0;
	pevNew->flags		= 0;
}
	
	
static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage)
{
	SET_MODEL(ENT(pev), szGibModel);
	pev->frame			= 0;
	pev->nextthink		= -1;
	pev->movetype		= MOVETYPE_BOUNCE;
	pev->takedamage		= DAMAGE_NO;
	pev->solid			= SOLID_NOT;
	pev->view_ofs		= Vector(0,0,8);
	UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56));
	pev->velocity		= VecVelocityForDamage(flDamage);
	pev->avelocity		= RANDOM_FLOAT(-1,1) * Vector(0,600,0);
	pev->origin.z -= 24;
	ClearBits(pev->flags, FL_ONGROUND);
}


*/ 
#endif

int TrainSpeed(int iSpeed, int iMax)
{
	float fSpeed, fMax;
	int iRet = 0;

	fMax = (float)iMax;
	fSpeed = iSpeed;

	fSpeed = fSpeed/fMax;

	if (iSpeed < 0)
		iRet = TRAIN_BACK;
	else if (iSpeed == 0)
		iRet = TRAIN_NEUTRAL;
	else if (fSpeed < 0.33)
		iRet = TRAIN_SLOW;
	else if (fSpeed < 0.66)
		iRet = TRAIN_MEDIUM;
	else
		iRet = TRAIN_FAST;

	return iRet;
}

// Find the next client in the game for this player to spectate
void CBasePlayer::Spectator_FindNextPlayer( bool bReverse )
{
	// MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching
	//only a subset of the players. e.g. Make it check the target's team.
	int iStart;
	if ( m_hSpectatorTarget )
	{	
		iStart = ENTINDEX( m_hSpectatorTarget->edict() );
	}
	else
	{
		iStart = ENTINDEX( edict() );
	}
	int iCurrent = iStart;
	m_hSpectatorTarget = NULL;
	int iDir = bReverse ? -1 : 1; 
	do
	{
		iCurrent += iDir;
		// Loop through the clients
		if (iCurrent > gpGlobals->maxClients)
		{	iCurrent = 1;
		}
		if (iCurrent < 1)
		{	iCurrent = gpGlobals->maxClients;
		}
		CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent );
		if ( !pEnt )
		{	continue;
		}
		if ( pEnt == this )
		{	continue;
		}
		// Don't spec observers or invisible players
		if ( ((CBasePlayer*)pEnt)->IsSpectator() || (pEnt->pev->effects & EF_NODRAW) )
		{	continue;
		}
		// MOD AUTHORS: Add checks on target here.
		m_hSpectatorTarget = pEnt;
		break;
	} while ( iCurrent != iStart );
	// Did we find a target?
	if ( m_hSpectatorTarget )
	{
		// Store the target in pev so the physics DLL can get to it
		pev->iuser2 = ENTINDEX( m_hSpectatorTarget->edict() );
		// Move to the target
		UTIL_SetOrigin( pev, m_hSpectatorTarget->pev->origin );

		ALERT( at_console, "Now Tracking %s\n", STRING( m_hSpectatorTarget->pev->netname ) );
	}
	else
	{
		ALERT( at_console, "No observer targets.\n" );
	}
}

// Handle buttons in observer mode
void CBasePlayer::Spectator_HandleButtons()
{
	// Slow down mouse clicks
	if ( m_flNextSpectatorInput > gpGlobals->time )
		return;

	// Jump changes from modes: Chase to Roaming
	if ( m_afButtonPressed & IN_JUMP )
	{
		if ( pev->iuser1 == OBS_CHASE_LOCKED )
		{	Spectator_SetMode( OBS_CHASE_FREE );
		}
		else if ( pev->iuser1 == OBS_CHASE_FREE )
		{	Spectator_SetMode( OBS_ROAMING );
		}
		else if ( pev->iuser1 == OBS_ROAMING )
		{	Spectator_SetMode( OBS_IN_EYE );
		}
		else if ( pev->iuser1 == OBS_IN_EYE )
		{	Spectator_SetMode( OBS_MAP_FREE );
		}
		else if ( pev->iuser1 == OBS_MAP_FREE )
		{	Spectator_SetMode( OBS_MAP_CHASE );
		}
		else
		{	Spectator_SetMode( OBS_CHASE_LOCKED ); // don't use OBS_CHASE_LOCKED anymore
		}
		m_flNextSpectatorInput = gpGlobals->time + 0.2;
	}

	// Attack moves to the next player
	if ( m_afButtonPressed & IN_ATTACK && pev->iuser1 != OBS_ROAMING )
	{	Spectator_FindNextPlayer( false );
		m_flNextSpectatorInput = gpGlobals->time + 0.2;
	}

	// Attack2 moves to the prev player
	if ( m_afButtonPressed & IN_ATTACK2 && pev->iuser1 != OBS_ROAMING )
	{	Spectator_FindNextPlayer( true );
		m_flNextSpectatorInput = gpGlobals->time + 0.2;
	}
}

// Attempt to change the observer mode: Tour of Duty tutorial
void CBasePlayer::Spectator_SetMode( int iMode )
{
	// Just abort if we're changing to the mode we're already in
	if ( iMode == pev->iuser1 )
		return;

	// is valid mode ?
	if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_MAP_CHASE )
	{
		iMode = OBS_IN_EYE; // now it is
	}

	// if we are not roaming, we need a valid target to track
	if ( (iMode != OBS_ROAMING && iMode != OBS_MAP_FREE) && (m_hSpectatorTarget == NULL) )
	{
		Spectator_FindNextPlayer( false );

		// if we didn't find a valid target switch to roaming
		if (m_hSpectatorTarget == NULL)
		{
			ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" );
			iMode = OBS_ROAMING;
		}
	}

	// set spectator mode
	pev->iuser1 = iMode;

	// set target if not roaming
	if (iMode == OBS_ROAMING || iMode == OBS_MAP_FREE)
	{
		pev->iuser2 = 0;
	}
	else
	{
		pev->iuser2 = ENTINDEX( m_hSpectatorTarget->edict() );
	}
}

void CBasePlayer::EmitClassSound(const char *sound)
{
	EMIT_SOUND(ENT(pev), CHAN_VOICE, UTIL_VarArgs("%s/%s",m_pClass->GetSoundDir(),sound), 1.0, ATTN_NORM);
}
/*
* harSens: wait to become candy
*/
void CBasePlayer::WaitToBecomeCandy(CBasePlayer *Attacker)
{
	// Modified by Rick : Check for m_pBuddyCandyVictim
	if (!Attacker->m_pCandyVictim && !Attacker->m_pBuddyCandyVictim && !m_fBecomeCandy)
	{	//send candy menu to attacker
		MESSAGE_BEGIN(MSG_ONE, gmsgVGUIMenu, NULL, Attacker->edict());
			WRITE_BYTE( 32 );			//show candy menu
		MESSAGE_END();
	
		//give the attacker his info
		Attacker->m_pCandyVictim = this;
		Attacker->m_flCandyCounter = gpGlobals->time;

		//freeze controls
		pev->flags |= FL_FROZEN;
		m_fBecomeCandy = true;
	}
}

void CBasePlayer::ReleaseCandy()
{	//unfreeze controls
	pev->flags &= ~FL_FROZEN;
	m_fBecomeCandy = false;
}
/*
* harSens: become candy
*/
BOOL CBasePlayer::MakeCandy(const char *candy)
{	//do we have a candy victim?
	// Modified by Rick : Check for m_pBuddyCandyVictim aswell
	if (!m_pCandyVictim && !m_pBuddyCandyVictim)
	{	return false;
	}
	
	// Added/Modified by Rick : Buddies need to be candified aswell
	// Are we candifying a player?
	if (m_pCandyVictim)
	{
		//is the candy victim still about to be candified?
		if (!m_pCandyVictim->m_fBecomeCandy)
		{	m_pCandyVictim = NULL;
			return false;
		}

		BOOL fCandy = m_pCandyVictim->BecomeCandy(candy,this);
		if (fCandy)
		{	m_pCandyVictim = NULL;
		}
		return fCandy;
	}
	else if (m_pBuddyCandyVictim)
	{
		//is the candy victim still about to be candified?
		if (!m_pBuddyCandyVictim->m_bBecomeCandy)
		{	m_pBuddyCandyVictim = NULL;
			return false;
		}

		BOOL fCandy = m_pBuddyCandyVictim->BecomeCandy(candy,this);
		if (fCandy)
		{	m_pBuddyCandyVictim = NULL;
		}
		return fCandy;
	}

	return false;
}

BOOL CBasePlayer::BecomeCandy(const char *candy, CBaseEntity *attacker)
{	if (!strcmp(candy,"cookie"))
	{	CCookie::CreateCookie(GetGunPosition(), pev);
	}
	else if (!strcmp(candy,"chocolate"))
	{	CChocolate::CreateChocolate(GetGunPosition(), pev);
	}
	else if (!strcmp(candy,"donut"))
	{	CDonut::CreateDonut(GetGunPosition(), pev);
	}
	else
	{	return false;
	}
	EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/candypop.wav", 1.0, ATTN_NORM);
	pev->effects |= EF_NODRAW;
	int damageFlags = DMG_GENERIC;
	damageFlags |= DMG_NEVERGIB;
	
	TakeDamage( attacker->pev, attacker->pev, 900, damageFlags );

	pev->flags &= ~FL_FROZEN;
	m_fBecomeCandy = false;
	return true;
}

/*
* harSens:Teleport
*/
void CBasePlayer::Teleport()
{	// Added by Pcjoe
	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;

	// Pcjoe: Teleport delay
	float flDelay = gpGlobals->time-m_flLastTeleport;
	int iStaminaCost = 0;
	if(flDelay < m_pClass->GetTeleportDelay())
	{
		//ALERT(at_console,"Delay %f\n",flDelay);
		iStaminaCost = TELEPORT_MAXSTAMINA_COST*(m_pClass->GetTeleportDelay()-flDelay)/m_pClass->GetTeleportDelay();		
	}
	if(!m_fStrangled && !m_fBecomeCandy && !m_fObserverFlag && IsAlive() &&!m_fControl && !(m_fCharging && !m_pClass->CanTeleportWhileCharging()) && !m_fHoldDisc && !m_fMelee && !m_fBlock && !m_fShield && !m_fPowerUp && !m_fAscending && !m_ChargedTurbo.isChargeTurboActive()	)
	{	if (HasKi(TELEPORT_KI_COST)&&HasStamina(iStaminaCost))
		{				
			UseKi(TELEPORT_KI_COST);
			UseStamina(iStaminaCost);
			EMIT_SOUND(ENT(pev), CHAN_AUTO, "weapons/teleport.wav", 1, ATTN_NORM);
			
			/*
			//create after image entity
			CAfterImage *pAfterImage = GetClassPtr( (CAfterImage *)NULL );
			pAfterImage->Spawn();
			pAfterImage->pev->rendercolor.x = entindex();
			pAfterImage->pev->angles = pev->angles;
			
			pAfterImage->pev->model		= pev->model;
			pAfterImage->pev->modelindex= pev->modelindex;
			pAfterImage->pev->movetype	= MOVETYPE_FLY;
			pAfterImage->pev->solid		= SOLID_NOT;
			pAfterImage->pev->velocity	= Vector(0,0,0);
			
			pAfterImage->pev->sequence = pev->sequence;
			pAfterImage->pev->animtime = pev->animtime;
			pAfterImage->pev->frame		= pev->frame;			
			
			UTIL_SetOrigin(pAfterImage->pev,pev->origin);
			UTIL_SetSize(pAfterImage->pev, pev->mins, pev->maxs);					
			*/
			AddClientAfterFX();
			
			//move
			Vector vecEnd = pev->origin + pev->velocity.Normalize() * TELEPORT_DISTANCE;
			TraceResult tr;
			UTIL_TraceHull(pev->origin, vecEnd, dont_ignore_monsters, human_hull, ENT(pev), &tr);
			UTIL_SetOrigin(pev,tr.vecEndPos);

			// Added by Pcjoe
			m_flLastTeleport = gpGlobals->time;
		}		
	}
}

/*
* harSens:Start to fly
*/
void CBasePlayer::StartFly()
{	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;
	if (!m_fFlying && IsAlive() && !m_fObserverFlag && (m_fMelee ? m_Melee.m_fPowerhit : true) && !m_fControl && !m_fBlockStruggling)
	{	if (m_fBlock)
		{	StopBlock();
		}
		m_fFlying = true;
		pev->gravity = 0.0000001;
		pev->movetype = MOVETYPE_PLAYERFLY;
	}
}

/*
* harSens:Stop flying
*/
void CBasePlayer::StopFly()
{//	if (m_fFlying && !m_fPowerUp && !m_fControl && !m_fAscending && !m_fBlockStruggling)
	if (!m_fStrangled && !m_fBecomeCandy && m_fFlying && !m_fPowerUp && (m_fMelee ? m_Melee.m_fPowerhit : true) && !m_fControl && !m_fAscending && !m_fBlockStruggling && !m_fShield && !m_ChargedTurbo.isChargeTurboActive())
	{	//can't fall while blocking
		if (m_fBlock)
		{	StopBlock();
		}
		m_fFlying = false;
		pev->gravity = 1;
		pev->movetype = MOVETYPE_WALK;
		// Removed by Pcjoe
	/*	if (m_pAura)
		{	m_pAura->pev->body = 0;
		}*/
	}
}


/*
* harSens:Start turbo
*/
void CBasePlayer::StartTurbo ( void )
{	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;
	
	if (!m_fStrangled && !m_fBecomeCandy && !m_fTurbo && !m_fObserverFlag && IsAlive() && !m_fCharging && !m_fHoldDisc &&!m_fAscending&&!m_fMelee)
	{	m_fTurbo = true;
		if (!m_pAura)
		{	m_pAura = CAura::Create(this);
		}
	}
	
}

/*
* harSens:Stops turbo
*/
void CBasePlayer::StopTurbo ( void )
{	// Added by Pcjoe, dont mess with turbo When in Melee is active
	if (!m_fMelee)
    {	if (m_fTurbo)
	    {	m_fTurbo = false;
			m_ChargedTurbo.disableChargedTurbo();
			m_ChargedTurbo.updateSettle();

			if(m_pAura)
		    {	m_pAura->Destroy();
		 	    m_pAura = NULL;
		    }
	    }
    }	
}

/*
* harSens:Starts observing for class/team select menu's
*/
void CBasePlayer:: StartObserving( void ) 
{	if (m_fObserverFlag)
		return;

	//unblind player
	if (m_fBlinded)
	{	UTIL_ScreenFade	( this, Vector (255,255,255), 0, 0, 255, FFADE_IN );
	}
	
	//disable special modes
	if (m_fAscending)
	{	Descend( true );
	}
	if (m_fPowerUp)
	{	StopPowerUp();
	}
	if (m_fBlock)
	{	StopBlock();
	}
	if (m_fFlying)
	{	StopFly();
	}
	if (m_fTurbo)
	{	StopTurbo();
	}		
	// added by Pcjoe
	if (m_fMelee)
	{	m_fMelee = false;
	}
	
	m_fObserverFlag = TRUE;
	pev->effects |= EF_NODRAW;
	

	EnableControl(FALSE);

	RemoveAllItems( TRUE );
		
	//set 1st person camera
	MESSAGE_BEGIN( MSG_ONE, gmsgChangeView, NULL, pev ); 
		WRITE_BYTE( 1 );	//1st person
		WRITE_BYTE( 1 );	//lock camera
	MESSAGE_END(); 
	
	
	edict_t *pSpot, *pNewSpot;
	int iRand;
	
	pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); 
	if ( !FNullEnt( pSpot ) )
	{	// at least one intermission spot in the world.
		iRand = RANDOM_LONG( 0, 3 );
		while ( iRand > 0 )
		{	pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission");
			if ( pNewSpot )
			{	pSpot = pNewSpot;
			}
			iRand--;
		}
		StartObserver( pSpot->v.origin, pSpot->v.v_angle );
	}
	else
	{	// no intermission spot. Push them up in the air, looking down at their corpse
		TraceResult tr;
		UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr );
		StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) );
	}
}

/*
* harSens:Stops observing for class/team select menu's
*/
void CBasePlayer::StopObserving( void ) 
{	if (!m_fObserverFlag)
		return;
	
	//set 3rd person camera
	MESSAGE_BEGIN( MSG_ONE, gmsgChangeView, NULL, pev ); 
		WRITE_BYTE( 3 );	//3rd person
		WRITE_BYTE( 0 );	//unlock camera
	MESSAGE_END(); 
	

	m_fObserverFlag = true;
	
	m_afPhysicsFlags |= PFLAG_OBSERVER;

	EnableControl(TRUE);
	pev->effects &= ~EF_NODRAW;
	m_fObserverFlag = FALSE;
	m_afPhysicsFlags &= ~PFLAG_OBSERVER;

	pev->button = 0;
	m_iRespawnFrames = 0;
	
	respawn(pev, false );
	
	pev->nextthink = -1;
}


// harSens: Leave observer mode 
void CBasePlayer::StopSpectator( void )
{
	// Turn off spectator
	if ( pev->iuser1 || pev->iuser2 )
	{
		// Tell all clients this player is not a spectator anymore
		MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );  
			WRITE_BYTE( ENTINDEX( edict() ) );
			WRITE_BYTE( 0 );
		MESSAGE_END();
		pev->iuser1 = pev->iuser2 = 0; 
		m_hSpectatorTarget = NULL;

		m_iHideHUD &= ~(HIDEHUD_HEALTH|HIDEHUD_WEAPONS);
	}
}

/*
* Pcjoe: TransformFX
*/
void CBasePlayer::TransformFX( float flTime )
{	MESSAGE_BEGIN( MSG_ALL, gmsgTransformFX, pev->origin);
		WRITE_BYTE(entindex());				//Index of Player
		WRITE_COORD(flTime);		//Ascend Time
	MESSAGE_END();
}

/*
* harSens:Starts transform in the next class
*/
void CBasePlayer::StartAscend(void)
{	
	// Added by Ian
	// we will let the character class handle the ascension, if it returns true we can return	
	//spectators can't transform
	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;	

	//can't ascend if your health is too low
	if (pev->health<PLDROP_HEALTH)
		return;

	
	//not doing something special?
	if (m_fStrangled || m_fBecomeCandy || m_fBecomeCandy || m_fCharging 
		|| m_fPowerUp || m_fTurbo || m_fBlock || m_fHoldDisc || 
		m_fAscending || m_fMelee || m_Melee.m_fPowerhit || m_fShield || 
		!IsAlive() || (m_fControl && !m_fPowerStruggling) || m_fSpawnInvulnerable) //phew
	{	return;
	}

	//enough ki to ascend?
	if (pev->fuser4<ASCEND_KI_COST)
	{	return;
	}

	float flTransFromPL = m_pClass->GetTransFormPowerLevel();

	//only transform if powerlevel is high enough
	if (m_iPowerLevel >= flTransFromPL)
	{	
		if (m_pClass->GetTransformType() == transNormal)
		{
			m_pNextClass = m_pClass->GetAscendedClass();
			if (m_pNextClass)
			{	// Added by Pcjoe
				Vector col = g_vecAuraColor[m_pClass->GetAuraSkin()];
				float flNextTransFormPL = m_pNextClass->GetTransFormPowerLevel();
				// Edited by Pcjoe. always make people that can only transform once play the same sequence
				//	if (m_iPowerLevel > flNextTransFormPL)
				if (m_iPowerLevel >= flNextTransFormPL && m_pNextClass->CanDescend())
				{	//powerlevel is high enough to transform twice. casual transform
					Ascend();
					// Send ascend message to client (perfect transform)
					TransformFX(-1);
					// Send quick animation
					m_Melee.SetAnimPriority(ANIM_PRIORITY_MEDIUM_HIGH, 
					m_Melee.AddAnimation(false, gpGlobals->time, 1, "change_finish"));
				}
				else
				{	//dramatic transform
					m_fAscending = true;
			
					//stay in the air, if falling down
					if (!(pev->flags&FL_ONGROUND))
					{	if (!m_fFlying)
						{	StartFly();
						}
					}

					m_flSlowDown = 0.0;		
					m_flAscendTime = TRANSFORM_TIME * (flNextTransFormPL - m_iPowerLevel)/(flNextTransFormPL - flTransFromPL);

					// Added by Pcjoe, If the transformation is over 9 seconds, make it 10 ( For the scripted transformation event )
					// Edited - Made so that people who cannot descend will transform at the full time
					if(m_flAscendTime >= TRANSFORM_TIME-1 || !m_pNextClass->CanDescend() || m_eTransStatus == TRANS_NEVER)
					{	
						m_flAscendTime = TRANSFORM_TIME;

						if(m_eTransStatus == TRANS_NEVER)
							m_eTransStatus = TRANS_FIRST;

						// If the guy is transforming while controlling a beam, play the looping animation
						// Instead of the long scripted one
						if(m_fControl)
							m_iTransformStatus = TRANS_NORM;
						else
							m_iTransformStatus = TRANS_LONG;

					}
					else if(m_flAscendTime > 0 && m_flAscendTime <= 1)
					{
						m_flAscendTime = 1;
						m_iTransformStatus = TRANS_SHORT;
					}
					else if(m_flAscendTime > 1 && m_flAscendTime < TRANSFORM_TIME-1)
					{
						m_iTransformStatus = TRANS_NORM;
					}
					else
					{
						m_iTransformStatus = TRANS_NONE;
					}
				
					// Send ascend message to client
					TransformFX(m_flAscendTime);
	
					// Remove all animations
					m_Melee.RemoveAllAnims();

					// Fix model angles
					Vector vecAngles = pev->angles;
					vecAngles.x = 0;
					UTIL_Model_FixAngles(entindex(), vecAngles);
					// end of add by Pcjoe

					m_flAscendTime += gpGlobals->time;		
				}
			}
		}
		else
		{	
			// we already have/had a buddy
			if ((m_hBuddy) || (m_bHadBuddy == true)) return;

			m_bHadBuddy = true;

			// buddy transformation
			//
			// for right now we are just going to create the buddy and let the player be
			// on their way -- if later we are going to add some custom animation put it here
	        UTIL_MakeVectors(Vector(0,this->pev->v_angle.y,0));
			this->m_hBuddy = (CBuddy*)this->Create("player_buddy", this->pev->origin + gpGlobals->v_forward * 128 + gpGlobals->v_up * 28, this->pev->angles, this->edict());		

			//this->m_flAscendTime += TRANSFORM_TIME + gpGlobals->time;
		}
	}
}

/*
* harSens:Transforms in the next class
*/
void CBasePlayer::StopAscending(void)
{	if (m_fAscending)
	{	m_fAscending = false;
		// Edited by Pcjoe, dont return slowdown to normal if your controlling a beam
		// m_flSlowDown = 1.0;
		if(!m_fControl)
		{	m_flSlowDown = 1.0;
			UTIL_Model_RemoveAll( entindex() );
		}
		
		//Done by Joe: disable transform fx
		MESSAGE_BEGIN( MSG_ALL, gmsgStopTransformFX, pev->origin);
			WRITE_BYTE(entindex());		// Index of Player
		MESSAGE_END();
		/* moved up by harSens
		// Added by Pcjoe: Disable model lock
		UTIL_Model_RemoveAll( entindex() );
		*/
	}
	
}

/*
* harSens:Transforms in the next class
*/
void CBasePlayer::Ascend(void)
{	StopAscending();
	
	if (this->m_hBuddy) return;	

	delete m_pClass;
	m_pClass = m_pNextClass;

	pev->fuser4-=ASCEND_KI_COST;
	if(pev->fuser4<0)
	{	pev->fuser4 = 0;
	}

	//add new/remove old attacks
	// Edited by Pcjoe, only replace weapons when player isnt controlling a beam
	if(m_fControl)
	{	m_fAddWepAfterTrans = TRUE;
	}
	else
	{	// Remove all attacks + readd new attacks
		RemoveAllWeapons(false);
		m_pClass->AddAllAttacks();
	}
	
	m_flPowerLevelMultiplier*=m_pClass->GetTransFromPLMultiplier();
	int iMaxPowerLevel = m_iMaxPowerLevel * m_pClass->GetTransFromPLMultiplier();
	SetMaxPowerLevel(iMaxPowerLevel);
	SetPowerLevel(iMaxPowerLevel);		

	float flHealthRatio = (float)pev->health/(float)m_iMaxHealth;
	m_iMaxHealth = m_pClass->GetStartHealth();
	SetMaxHealth(m_iMaxHealth);
	int iHealth = m_iMaxHealth * flHealthRatio;
	
	if(iHealth<=0)
	{	pev->health=1;
	}
	else 
	{	pev->health = iHealth;
	}

	m_iMaxSpeed = m_pClass->GetStartSpeed();

	MESSAGE_BEGIN( MSG_ONE, gmsgTransform, NULL, pev );
		WRITE_BYTE(m_pClass->GetClassID());
		WRITE_LONG(m_pClass->GetTransFormPowerLevel());
	MESSAGE_END();
	
	m_pClass->SetModel();
	
	//added by harSens: restarts running animations
	pev->sequence = 0;	
	m_Activity = ACT_RESET;
	PlayAnimation();

	if(m_pAura)
	{
		m_pAura->SetColor();
	}

	// Added by Pcjoe
	if(m_eTransStatus == TRANS_FIRST)
		m_eTransStatus = TRANS_FIRST_DONE;

	// Update last recover time for melee
	m_Melee.m_flLastRecoverTime = gpGlobals->time;

	// DragonDude: update class on scoreboard
	pev->playerclass = m_pClass->Classify();	
	MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo);
		WRITE_BYTE(entindex());
		WRITE_SHORT(pev->frags);
		WRITE_SHORT(m_iDeaths);
		WRITE_SHORT(m_iWishes);
		WRITE_SHORT(pev->playerclass);
		WRITE_SHORT(g_pGameRules->GetTeamIndex(m_szTeamName) + 1);
		WRITE_SHORT(m_pClass->ScoreboardName());
	MESSAGE_END();
	//end DragonDude add
}

/*
* harSens:Transforms in the previous class
*/
void CBasePlayer::Descend( bool blRemoveWeapons )
{	
	if (m_fAscending)
	{	StopAscending();

		// Reset the transformation status
		if(m_eTransStatus == TRANS_FIRST)
			m_eTransStatus = TRANS_NEVER;

		if (m_hBuddy) // if we had a buddy he must die!
		{
			m_hBuddy->Die(NULL, NULL);
		}

		return;
	}

	CBaseClass *pNextClass = m_pClass->GetDescendedClass();
	if (pNextClass)
	{	// Hars, You did it again god dammit >.< 
		// hehe, just copy the code, it looks clean now i think :)
		if (!m_pClass->CanDescend() && !m_fAscending)
		{
			return;
		}
		CBaseClass *pPreviousClass = m_pClass;
		m_pClass = pNextClass;
		
		
		if (blRemoveWeapons)
		{
			if(m_fControl)
			{
				m_fAddWepAfterTrans = TRUE;
			}
			else
			{	
				RemoveAllWeapons(false);
				m_pClass->AddAllAttacks();
				// Added by Pcjoe, select old weapon
				SelectLastItem();
			}
		}
		m_pClass->SetModel();
	
		int iMaxPowerLevel = m_iMaxPowerLevel/pPreviousClass->GetTransFromPLMultiplier();
		SetMaxPowerLevel(iMaxPowerLevel);
		if (pev->health>PLDROP_HEALTH||m_iPowerLevel>iMaxPowerLevel)
		{	SetPowerLevel(iMaxPowerLevel);
		}
		m_flPowerLevelMultiplier /= pPreviousClass->GetTransFromPLMultiplier();
		

		float flHealthRatio = (float)pev->health/(float)m_iMaxHealth;
		m_iMaxHealth = m_pClass->GetStartHealth();
		SetMaxHealth(m_iMaxHealth);
		int iHealth = m_iMaxHealth * flHealthRatio;
		
		if(iHealth<=0)
		{	pev->health=1;
		}
		else 
		{	pev->health = iHealth;
		}

		m_iMaxSpeed = m_pClass->GetStartSpeed();

		g_pGameRules->UpdatePlayerStats();

		MESSAGE_BEGIN( MSG_ONE, gmsgTransform, NULL, pev );
			WRITE_BYTE(m_pClass->GetClassID());
			WRITE_LONG(m_pClass->GetTransFormPowerLevel());
		MESSAGE_END();

		EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/descend.wav", 1.0, ATTN_NORM);

		if(m_pAura)
		{
			m_pAura->SetColor();
		}

		// Added by Pcjoe, if player descends while powering up, make sure to change the color.
		if(m_fPowerUp)
		{	Vector col = g_vecAuraColor[m_pClass->GetAuraSkin()];
			MESSAGE_BEGIN( MSG_PVS, gmsgPowerupFX, pev->origin);
				WRITE_BYTE(entindex());
				WRITE_BYTE(col.x);
				WRITE_BYTE(col.y);
				WRITE_BYTE(col.z);
			MESSAGE_END();	
		}
		delete pPreviousClass;
	}

	// DragonDude: update class on scoreboard
	pev->playerclass = m_pClass->Classify();	
	MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo);
		WRITE_BYTE(entindex());
		WRITE_SHORT(pev->frags);
		WRITE_SHORT(m_iDeaths);
		WRITE_SHORT(m_iWishes);
		WRITE_SHORT(pev->playerclass);
		WRITE_SHORT(g_pGameRules->GetTeamIndex(m_szTeamName) + 1);
		WRITE_SHORT(m_pClass->ScoreboardName());
	MESSAGE_END();
	//end DragonDude add
}
/*
* harSens/pcJoe:Changes class
*/
BOOL CBasePlayer::ChangeClass(const char *pClassName)
{	int iPreviousClass = m_pClass->Classify();

	CBaseClass *pNewClass;
	if ( FStrEq(pClassName, "goku"))
	{	//m_fRandomClass = false;
		pNewClass = new CGoku(this);
	}
	else if ( FStrEq(pClassName, "piccolo"))
	{	//m_fRandomClass = false;
		pNewClass = new CPiccolo(this);
	}
	else if ( FStrEq(pClassName, "krillin"))
	{	//m_fRandomClass = false;
		pNewClass = new CKrillin(this);
	}
	else if ( FStrEq(pClassName, "vegeta"))
	{	//m_fRandomClass = false;
		pNewClass = new CVegeta(this);
	}
	else if ( FStrEq(pClassName, "trunks"))
	{	//m_fRandomClass = false;
		pNewClass = new CTrunks(this);
	}
	else if ( FStrEq(pClassName, "frieza"))
	{	//m_fRandomClass = false;
		pNewClass = new CFrieza(this);
	}
	else if ( FStrEq(pClassName, "cell"))
	{	//m_fRandomClass = false;
		pNewClass = new CCell(this);
	}
	else if ( FStrEq(pClassName, "buu"))
	{	//m_fRandomClass = false;
		pNewClass = new CBuu(this);
	}
	else if ( FStrEq(pClassName, "gohan"))
	{	//m_fRandomClass = false;
		pNewClass = new CGohan(this);
	}
	else if ( FStrEq(pClassName, "ginyu"))
	{	//m_fRandomClass = false;
		pNewClass = new CGinyu(this);
	}
	else if ( FStrEq(pClassName, "a18"))
	{	//m_fRandomClass = false;
		pNewClass = new CAndroid18(this);
	}
	else if ( FStrEq(pClassName, "randompc"))
	{	char pName[255];
		//find a valid class
		do
		{	strcpy(pName,CBaseClass::GetName(RANDOM_LONG(1,PC_LAST-1)));			
		}
		while(!g_pGameRules->IsValidClass(pName,this));
		ChangeClass(pName);						
		//m_fRandomClass = true;		
		return true;
	}
	else
	{	return false;
	}

	if (g_pGameRules->IsTeamplay() && pev->team == 0)
	{
		ALERT(at_console,"Spectators have to pick a team first\n");
		delete pNewClass;
		return true;
	}

	if(!g_pGameRules->IsValidClass(pClassName,this))
	{	//gamerules don't allow to change into this class, return
		ALERT(at_console,"Invalid class\n");
		delete pNewClass;
		return true;
	}

	// Added by Pcjoe: Don't allow change class while in advanced melee
	// Modified by Rick: Added m_pBuddyCandyVictim check
	// added by harSens added ps
	if(m_Melee.InAdvMeleeBattle() || m_fStrangled || m_fBecomeCandy || m_pCandyVictim || m_pBuddyCandyVictim || m_fBlockStruggling|| m_fPowerStruggling)
	{	delete pNewClass;
		return false;
	}

	// we've chosen a class, stop spectating
	int fSpectate = false;
	if (IsSpectator())
	{	StopSpectator();
		fSpectate = true;		
	}

	//stop immortality
	m_fInvulnerable = false;
	m_fSpawnInvulnerable = false;

	int iMaxPowerLevel;
	int iMaxBasePowerLevel;	
	
	// one frag penalty for changing class, except when dead, or previously spectating
	if (iPreviousClass != PC_BASE && !fSpectate)
	{	if(gpGlobals->time < m_flLastClassChange+CLASS_CHANGE_DELAY)
		{	//can't change, we changed shortly before
			delete pNewClass;
			return false;
		}
		iMaxPowerLevel = m_iMaxPowerLevel;
		iMaxBasePowerLevel = iMaxPowerLevel/m_flPowerLevelMultiplier;
		/*
		in realteam mode, we should undo observer here, 
		so you can get killed
		*/
		if (m_fObserverFlag)
		{	StopObserving();
		}	
		if( IsAlive())
		{	int damageFlags = DMG_GENERIC;
			damageFlags |= DMG_NEVERGIB;
			entvars_t *pevWorld = VARS( INDEXENT(0) );
			TakeDamage( pevWorld, pev, 900, damageFlags );
		}		
	}
	else
	{	iMaxPowerLevel = pNewClass->GetStartPowerLevel();
		iMaxBasePowerLevel = iMaxPowerLevel/m_flPowerLevelMultiplier;
	}	

	int iStartPowerLevel = m_pClass->GetStartPowerLevel()/m_flPowerLevelMultiplier;
	
	//new class
	delete m_pClass;
	m_pClass = pNewClass;
	
	if (fSpectate)
	{	respawn(pev,false);
	}

	if (iMaxBasePowerLevel)
	{	float flChangeRatio = (float)m_pClass->GetStartPowerLevel()/(float)iStartPowerLevel;
		if(flChangeRatio > CHANGEPL_RATIO)
			flChangeRatio = CHANGEPL_RATIO;

		//decrease pl a bit, as a penalty for changing
		if (iMaxBasePowerLevel * flChangeRatio < m_pClass->GetStartPowerLevel())
		{	iMaxPowerLevel = m_pClass->GetStartPowerLevel();
		}
		else
		{	iMaxPowerLevel = iMaxBasePowerLevel * flChangeRatio;
		}
	}
	SetPowerLevel(iMaxPowerLevel);
	SetMaxPowerLevel(iMaxPowerLevel);

	m_iMaxHealth = m_pClass->GetStartHealth();
	SetMaxHealth(m_iMaxHealth);
	m_iMaxSpeed = m_pClass->GetStartSpeed();
	pev->health = m_pClass->GetStartHealth();
	pev->playerclass = m_pClass->Classify();
	m_pClass->SetModel();

	// Pcjoe: Set custom model if one is specified (or clear if one isn't), and notify all clients
	if(CMD_ARGC()>=2)
	{	strcpy(m_szCustomModel,CMD_ARGV(1));
		// Notify all clients
		MESSAGE_BEGIN( MSG_ALL, gmsgCustomModel );
			WRITE_BYTE( entindex() );
			WRITE_STRING( m_szCustomModel );
		MESSAGE_END();
	}
	else
	{	if(stricmp(m_szCustomModel,""))
		{	strcpy(m_szCustomModel,"");
			// Notify all clients
			MESSAGE_BEGIN( MSG_ALL, gmsgCustomModel );
				WRITE_BYTE( entindex() );
				WRITE_STRING( "" );
			MESSAGE_END();
		}
	}

	//inform all players of class change
	MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
		WRITE_BYTE( ENTINDEX(edict()) );
		WRITE_SHORT( pev->frags );
		WRITE_SHORT( m_iDeaths );
		WRITE_SHORT( m_iWishes);
		WRITE_SHORT( pev->playerclass );
		WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 );
		WRITE_SHORT(m_pClass->ScoreboardName());
	MESSAGE_END();

	if (m_fObserverFlag)
	{	//disable observer mode
		StopObserving();
	}
	//send class change to the hud
	MESSAGE_BEGIN( MSG_ONE, gmsgTransform, NULL, pev );
		WRITE_BYTE(m_pClass->GetClassID());
		WRITE_LONG(m_pClass->GetTransFormPowerLevel());
	MESSAGE_END();

	m_flPowerLevelMultiplier = m_pClass->GetTransFromPLMultiplier();

	// Added by Pcjoe
	m_eTransStatus = TRANS_NEVER;

	m_flLastClassChange = gpGlobals->time;

	return true;
}

/*
* harSens:Starts blocking
*/
void CBasePlayer :: StartBlock( void )
{	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;	

	// Pcjoe: allow block to stop swoop/dashes midway
	if(m_Swoop.m_fSwoop)
	{	m_Swoop.StopSwoop();
	}

	// Edited by Pcjoe
//	if (!m_fBlock && !m_fCharging && !m_fControl && !m_fObserverFlag && IsAlive() && !m_fHoldDisc &&!m_fAscending)
	if (!m_fBlock && !m_fCharging && !m_fControl && !m_fObserverFlag && IsAlive() && !m_fHoldDisc &&!m_fAscending && !m_fMelee && !m_Melee.m_fPowerhit && !m_fShield && !m_ChargedTurbo.isChargeTurboActive())
	{	if (m_fPowerUp)
		{	StopPowerUp();
		}
		m_flSlowDown = 0.0;
		m_fBlock = true;
		m_flNextBlockStruggle = gpGlobals->time;
	}
}

/*
* harSens:Stops blocking
*/
void CBasePlayer :: StopBlock( void )
{	if (m_fBlock)
	{	if (m_fBlockStruggling)
		{	m_pBlockStruggler = NULL;
			m_fBlockStruggling = false;

			//restore movetype
			if (m_fFlying)
			{	pev->movetype = MOVETYPE_PLAYERFLY;
			}
			else
			{	pev->movetype = MOVETYPE_WALK;
			}
		}
		m_fSwat = false;
		m_flSlowDown = 1.0;
		m_iBlockPoints = 0;		
		m_fBlock = false;
	}
}

/*
* harSens:Starts powerup
*/
void CBasePlayer :: StartPowerUp ( void )
{	if (FBitSet(pev->flags, FL_SPECTATOR))
		return;

	// Pcjoe: allow powerup to stop swoop/dashes midway
	if(m_Swoop.m_fSwoop)
	{	m_Swoop.StopSwoop();
	}

	// Edited by Pcjoe
//	if (!m_fPowerUp && !m_fCharging && !m_fControl && IsAlive() && !m_fObserverFlag && !m_fHoldDisc && !m_fAscending)
	if (!m_fBecomeCandy && !m_fPowerUp && !m_fCharging && !m_fControl && IsAlive() && !m_fObserverFlag && !m_fHoldDisc && !m_fAscending && !m_fMelee && !m_Melee.m_fPowerhit && !m_fShield && !m_ChargedTurbo.isChargeTurboActive())
	{	if (m_fBlock)
		{	StopBlock();
		}
		if (m_fTurbo)
		{	StopTurbo();
		}
		//stay in the air, if falling down
		if (!(pev->flags&FL_ONGROUND))
		{	if (!m_fFlying)
			{	StartFly();
			}
		}
		m_flSlowDown = 0.0;
		m_fPowerUp = true;

		Vector col = g_vecAuraColor[m_pClass->GetAuraSkin()];
		MESSAGE_BEGIN( MSG_ALL, gmsgPowerupFX, pev->origin);
			WRITE_BYTE(entindex());
			WRITE_BYTE(col.x);
			WRITE_BYTE(col.y);
			WRITE_BYTE(col.z);
		MESSAGE_END();
	}
}

/*
* harSens:Stops powerup
*/
void CBasePlayer :: StopPowerUp ( void )
{	if (m_fPowerUp)
	{	m_flSlowDown = 1.0;
		m_fPowerUp = false;
		MESSAGE_BEGIN( MSG_ALL, gmsgStopPowerupFX, pev->origin);
			WRITE_BYTE(entindex());
		MESSAGE_END();
	}
}

/*
harSens: updates max pl
*/
void CBasePlayer::SetMaxPowerLevel(int pl)
{	int iMaxPl = MAXPL/m_ChargedTurbo.getTurboMultiplier();
	m_iMaxPowerLevel = pl;
	if(m_iMaxPowerLevel>iMaxPl)
	{	m_iMaxPowerLevel = iMaxPl;
	}	
	if (m_iMaxPowerLevel<0)
	{	ALERT(at_console,"negative MaxPowerLevel\n");
		m_iMaxPowerLevel = 0;
	}
	g_pGameRules->UpdatePlayerStats();
}

/*
harSens updates pl
*/
void CBasePlayer::SetPowerLevel(int pl)
{	int iMaxPl = MAXPL/m_ChargedTurbo.getTurboMultiplier();
	m_iPowerLevel = pl;
	if(m_iPowerLevel>iMaxPl)
	{	m_iPowerLevel = iMaxPl;
	}
	if (m_iPowerLevel<0)
	{	ALERT(at_console,"negative PowerLevel\n");
		m_iPowerLevel = 0;
	}	
}

/*
* harSens:increases pl
*/
void CBasePlayer::IncreasePL(int increase)
{	SetPowerLevel(m_iPowerLevel+increase);
	SetMaxPowerLevel(m_iMaxPowerLevel+increase);	
}

int CBasePlayer::GetPotentialPL()
{
	int iPotentialPL = m_iMaxPowerLevel;
	CBaseClass *pAscendedClass = m_pClass->GetAscendedClass();
	CBaseClass *pPrevClass;
	int iTransformPL = m_pClass->GetTransFormPowerLevel();
	while (iPotentialPL>iTransformPL && pAscendedClass)
	{
		iPotentialPL *= pAscendedClass->GetTransFromPLMultiplier();
		iTransformPL = pAscendedClass->GetTransFormPowerLevel();
		pPrevClass = pAscendedClass;
		pAscendedClass = pAscendedClass->GetAscendedClass();
		delete pPrevClass;
	}
	if(pAscendedClass)
	{
		delete pAscendedClass;
	}
	return iPotentialPL;
}
/*
* harSens:increases strength
*/
void CBasePlayer :: IncreaseStrength(CBasePlayer *pVictim, int damage)
{	// don't gain exp for hurting yourself :)
	if (pVictim == this)
		return;

	float flPlIncrease = (float)pVictim->m_iMaxPowerLevel / (float)m_iMaxPowerLevel;
	
	
	if (flPlIncrease < 1.0)
	{	//You hit someone weak, you meanie! We gonna give you a cap
		flPlIncrease *= flPlIncrease;
	}

	flPlIncrease *= POWERLEVEL_INCREASE * damage;
	IncreasePL(flPlIncrease);	
}

//Added by Rick:Used when hurting a buddy
void CBasePlayer :: IncreaseStrength(CBuddy *pVictim, int damage)
{	// don't gain exp for hurting your own buddies :)
	if (pVictim->pev->owner == edict())
		return;

	float flPlIncrease = (float)pVictim->m_iMaxPowerLevel / (float)m_iMaxPowerLevel;
	
	
	if (flPlIncrease < 1.0)
	{	//You hit someone weak, you meanie! We gonna give you a cap
		flPlIncrease *= flPlIncrease;
	}

	flPlIncrease *= POWERLEVEL_INCREASE * damage;
	IncreasePL(flPlIncrease);	
}
//end add by Rick
void CBasePlayer :: DeathSound( void )
{
	// water death sounds
	/*
	if (pev->waterlevel == 3)
	{
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE);
		return;
	}
	*/

	/*modified by harSens
	// temporarily using pain sounds for death sounds
	switch (RANDOM_LONG(1,5)) 
	{
	case 1: 
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM);
		break;
	case 2: 
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM);
		break;
	case 3: 
		EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM);
		break;
	}

	// play one of the suit death alarms
	EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD");
	*/
	EmitClassSound("death.wav");	
}

// override takehealth
// bitsDamageType indicates type of damage healed. 

int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType )
{
	return CBaseMonster :: TakeHealth (flHealth, bitsDamageType);

}

Vector CBasePlayer :: GetGunPosition( )
{
//	UTIL_MakeVectors(pev->v_angle);
//	m_HackedGunPos = pev->view_ofs;
	Vector origin;
	
	origin = pev->origin + pev->view_ofs;
	// Added by Pcjoe: HACK HACK, lower the gun pos a litle more, its too high
	// Hars, you will probably want remove this, too ugly of a hack :-)
	// harSens: ya... you should have modified the pev->view_ofs somewhere. But i'm too lazy to figure out where :P
	origin.z -= 3;

	return origin;
}

//=========================================================
// TraceAttack
//=========================================================
void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
	if ( pev->takedamage )
	{
		m_LastHitGroup = ptr->iHitgroup;

		/* disabled by harSens
		switch ( ptr->iHitgroup )
		{
		case HITGROUP_GENERIC:
			break;
		case HITGROUP_HEAD:
			flDamage *= gSkillData.plrHead;
			break;
		case HITGROUP_CHEST:
			flDamage *= gSkillData.plrChest;
			break;
		case HITGROUP_STOMACH:
			flDamage *= gSkillData.plrStomach;
			break;
		case HITGROUP_LEFTARM:
		case HITGROUP_RIGHTARM:
			flDamage *= gSkillData.plrArm;
			break;
		case HITGROUP_LEFTLEG:
		case HITGROUP_RIGHTLEG:
			flDamage *= gSkillData.plrLeg;
			break;
		default:
			break;
		}
		*/

		SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
		TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
		AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
	}
}

/*
	Take some damage.  
	NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage
	type will cause the damage time countdown to be reset.  Thus the ongoing effects of poison, radiation
	etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC.
*/

#define ARMOR_RATIO	 0.2	// Armor Takes 80% of the damage
#define ARMOR_BONUS  0.5	// Each Point of Armor is work 1/x points of health

int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
	// have suit diagnose the problem - ie: report damage type
	int bitsDamage = bitsDamageType;
	int ffound = TRUE;
	int fmajor;
	int fcritical;
	int fTookDamage;
	int ftrivial;
	/* disabled by harSens
	float flRatio;
	float flBonus;
	*/
	float flHealthPrev = pev->health;

	/* disabled by harSens
	flBonus = ARMOR_BONUS;
	flRatio = ARMOR_RATIO;

	if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() )
	{
		// blasts damage armor more.
		flBonus *= 2;
	}*/

	// Already dead
	if ( !IsAlive() )
		return 0;
	// go take the damage first

	//added by harSens:
	CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor);
	
	CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker);

	if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) )
	{
		// Refuse the damage
		return 0;
	}

	// added by harSens: no damage when invulnerable
	if (m_fInvulnerable)
	{	return 0;
	}

	// Added by Pcjoe, if we're in advanced melee, dont take external damage
	if ( m_Melee.InAdvMeleeBattle() )
	{	// Only melee attacks can harm you in a melee battle
		if( !((bitsDamageType & DMG_MELEE) || (bitsDamageType & DMG_KICK)) )
		{	return 0;
		}
		// Check damage sources
		if(m_Melee.IsAttacker())
		{	if(pevAttacker != m_Melee.GetDefender()->pev)
			{	return 0;
			}
		}
		if(m_Melee.IsDefender())
		{	if(pevAttacker != m_Melee.GetAttackerOther()->pev)
			{	return 0;
			}
		}
	}

	// Added by Pcjoe, adv melee invulnerability
	if(!m_Melee.CanInflictDamage((CBasePlayer*)pInflictor, bitsDamageType))
	{	return 0;
	}

	//added by harSens: attacked with a disc?
	BOOL fDisc = false;
	if (pInflictor->Classify()==CLASS_DISCATTACK)
	{	fDisc = true;		
	}
	
	//reduced damage while blockstruggling
	if (m_fBlockStruggleAttacker)
	{	//flDamage *= 0.02;
		return 0;
	}

	if (m_fBlockStruggling && m_pBlockStruggler != pInflictor)
	{	//flDamage *= 0.02;
		return 0;
	}

	//reduce damage while powerstruggling, if the attack that hits us is not in the struggle
	if(m_fPowerStruggling && m_pPowerStruggle)
	{	if(!m_pPowerStruggle->InStruggle(pevInflictor))
		{	//flDamage *= 0.02;
			return 0;
		}
	}
	// keep track of amount of damage last sustained
	m_lastDamageAmount = flDamage;

	// turbo reduces damage
	if (m_fTurbo)
	{	flDamage *= 0.75;	
	}

	// Added by Pcjoe, 1/2 damage when transforming
	if (m_fAscending)
	{	flDamage *= 0.5;
	}

	int iMyYaw = ( (int)pev->v_angle.y + 360)%360;
	int iInflictorYaw = ( (int)pevInflictor->angles.y + 540)%360;	

	//block reduces damage, if performed to the right dir
	BOOL fBlocked=false;
	if (m_fBlock)
	{	if(iInflictorYaw < iMyYaw + PLAYER_BLOCKANGLE)
		{	if (iInflictorYaw > iMyYaw - PLAYER_BLOCKANGLE)
			{	flDamage *= 0.25;
				fBlocked = true;
			}
		}				
	}

	if (bitsDamageType&DMG_CANDY)
	{	//killed by a candy attack
		if (pAttacker->IsPlayer() && flDamage >= pev->health && pAttacker != this)
		{	WaitToBecomeCandy((CBasePlayer *)pAttacker);
			return 0;
		}
	}
	
	// give the attacker some higher stats
	if (pAttacker->IsPlayer())
	{	if (fDisc)
		{	((CBasePlayer *)pAttacker)->IncreaseStrength(this,10);
		}
		else if((bitsDamageType & DMG_MELEE) || (bitsDamageType & DMG_KICK))
		{	if (flDamage<pev->health)
			{	((CBasePlayer *)pAttacker)->IncreaseStrength(this,flDamage*PL_GAIN_MULTI_MELEE);
			}
			else
			{	((CBasePlayer *)pAttacker)->IncreaseStrength(this,pev->health*PL_GAIN_MULTI_MELEE);
			}
		}
		else
		{	if (flDamage<pev->health)
			{	((CBasePlayer *)pAttacker)->IncreaseStrength(this,flDamage);
			}
			else
			{	((CBasePlayer *)pAttacker)->IncreaseStrength(this,pev->health);
			}
		}
	}
	// Added by Rick : Lets increase the stats of a buddy aswell
	else if (FStrEq(STRING(pAttacker->pev->classname), "player_buddy"))
	{	if (fDisc)
		{	((CBuddy *)pAttacker)->IncreaseStrength(this,10);
		}
		else if((bitsDamageType & DMG_MELEE) || (bitsDamageType & DMG_KICK))
		{	if (flDamage<pev->health)
			{	((CBuddy *)pAttacker)->IncreaseStrength(this,flDamage*2);
			}
			else
			{	((CBuddy *)pAttacker)->IncreaseStrength(this,pev->health*2);
			}
		}
		else
		{	if (flDamage<pev->health)
			{	((CBuddy *)pAttacker)->IncreaseStrength(this,flDamage);
			}
			else
			{	((CBuddy *)pAttacker)->IncreaseStrength(this,pev->health);
			}
		}
	}
	// End add by Rick

	//non directional blind
	if (!m_fBlinded && bitsDamageType & DMG_BLIND)
	{	UTIL_ScreenFade	( this, Vector (255,255,255),  BURNINGATTACK_BLIND_TIME/3, BURNINGATTACK_BLIND_TIME*2/3  , 255, FFADE_IN );	
		m_fBlinded = true;
		m_flBlindedTime = gpGlobals->time + BURNINGATTACK_BLIND_TIME; 
	}

	//can't flash yourself
	if (pAttacker == this && bitsDamageType & DMG_FLASH)
	{	return 0;
	}
	
	//flashed by solarflare?
	int iAttackerYaw = ( (int)pevAttacker->v_angle.y + 540)%360;
	if (!m_fBlinded)
	{	if(bitsDamageType & DMG_FLASH)
		{	//not blinded if we turn our back to the attacker
			if(iAttackerYaw < iMyYaw + 75)
			{	if (iAttackerYaw > iMyYaw - 75)
				{	UTIL_ScreenFade	( this, Vector (255,255,255),  SOLARFLARE_BLIND_TIME/3, SOLARFLARE_BLIND_TIME*2/3  , 255, FFADE_IN );	
					m_fBlinded = true;
					m_flBlindedTime = gpGlobals->time + SOLARFLARE_BLIND_TIME;
					pev->flags|=FL_GODMODE;
				}
			}
		}
	}

	//hit animations
	if(bitsDamageType&DMG_KICK||bitsDamageType&DMG_PUNCH)
	{	if(fBlocked)
		{	//move attacker backward
			UTIL_MakeVectors(pevInflictor->angles);
			if (bitsDamageType&DMG_PUNCH)
			{	
				// Added by Rick: buddies handle velocity different
				if (FStrEq(STRING(pInflictor->pev->classname), "player_buddy"))
				{
					CBuddy *pB = (CBuddy *)pInflictor;
					pB->ApplyVelocity(-gpGlobals->v_forward, 75, 1.0f);
				}
				else
					pevInflictor->velocity=pevInflictor->velocity-gpGlobals->v_forward * 75;
			}
			else
			{	
				// Added by Rick: don't move buddies
				if (!FStrEq(STRING(pInflictor->pev->classname), "player_buddy"))
					pevInflictor->velocity=pevInflictor->velocity-gpGlobals->v_forward * 250;
			}
		}
		else
		{	UTIL_MakeVectors(pevInflictor->angles);
			pev->velocity=pev->velocity+gpGlobals->v_forward * 50;
		}
	}
	//end harSens add
	// Armor. 
	/*removed by harSens no armor in esforces mod :-)
	if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage!
	{
		float flNew = flDamage * flRatio;

		float flArmor;

		flArmor = (flDamage - flNew) * flBonus;

		// Does this use more armor than we have?
		if (flArmor > pev->armorvalue)
		{
			flArmor = pev->armorvalue;
			flArmor *= (1/flBonus);
			flNew = flDamage - flArmor;
			pev->armorvalue = 0;
		}
		else
			pev->armorvalue -= flArmor;
		
		flDamage = flNew;
	}*/

	// this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that
	// as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc)
	fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, (int)flDamage, bitsDamageType);

	//added by harSens: play pain sounds
	if (fTookDamage && flDamage>=1)
	{	Pain();
	}
	// reset damage time countdown for each type of time based damage player just sustained
	/* disabled by harSens

	{
		for (int i = 0; i < CDMG_TIMEBASED; i++)
			if (bitsDamageType & (DMG_PARALYZE << i))
				m_rgbTimeBasedDamage[i] = 0;
	}
	*/
	// tell director about it
	
	MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR );
		/* disabled by harSens
		 */	
		WRITE_BYTE ( 9 );	// command length in bytes
		WRITE_BYTE ( DRC_CMD_EVENT );	// take damage event
		WRITE_SHORT( ENTINDEX(this->edict()) );	// index number of primary entity
		WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) );	// index number of secondary entity
		WRITE_LONG( 5 );   // eventflags (priority and flags)
	MESSAGE_END();
	

	// how bad is it, doc?

	ftrivial = (pev->health > 75 || m_lastDamageAmount < 5);
	fmajor = (m_lastDamageAmount > 25);
	fcritical = (pev->health < 30);
	/* disabled by harSens
	// handle all bits set in this damage message,
	// let the suit give player the diagnosis

	// UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash )

	// UNDONE: still need to record damage and heal messages for the following types

		// DMG_BURN	
		// DMG_FREEZE
		// DMG_BLAST
		// DMG_SHOCK

	m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client
	m_bitsHUDDamage = -1;  // make sure the damage bits get resent

	while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage)
	{
		ffound = FALSE;

		if (bitsDamage & DMG_CLUB)
		{
			if (fmajor)
				SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC);	// minor fracture
			bitsDamage &= ~DMG_CLUB;
			ffound = TRUE;
		}
		if (bitsDamage & (DMG_FALL | DMG_CRUSH))
		{
			if (fmajor)
				SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC);	// major fracture
			else
				SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC);	// minor fracture
	
			bitsDamage &= ~(DMG_FALL | DMG_CRUSH);
			ffound = TRUE;
		}
		
		if (bitsDamage & DMG_BULLET)
		{
			if (m_lastDamageAmount > 5)
				SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC);	// blood loss detected
			//else
			//	SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC);	// minor laceration
			
			bitsDamage &= ~DMG_BULLET;
			ffound = TRUE;
		}

		if (bitsDamage & DMG_SLASH)
		{
			if (fmajor)
				SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC);	// major laceration
			else
				SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC);	// minor laceration

			bitsDamage &= ~DMG_SLASH;
			ffound = TRUE;
		}
		
		if (bitsDamage & DMG_SONIC)
		{
			if (fmajor)
				SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN);	// internal bleeding
			bitsDamage &= ~DMG_SONIC;
			ffound = TRUE;
		}

		if (bitsDamage & (DMG_POISON | DMG_PARALYZE))
		{
			SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN);	// blood toxins detected
			bitsDamage &= ~(DMG_POISON | DMG_PARALYZE);
			ffound = TRUE;
		}

		if (bitsDamage & DMG_ACID)
		{
			SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN);	// hazardous chemicals detected
			bitsDamage &= ~DMG_ACID;
			ffound = TRUE;
		}

		if (bitsDamage & DMG_NERVEGAS)
		{
			SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN);	// biohazard detected
			bitsDamage &= ~DMG_NERVEGAS;
			ffound = TRUE;
		}

		if (bitsDamage & DMG_RADIATION)
		{
			SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN);	// radiation detected
			bitsDamage &= ~DMG_RADIATION;
			ffound = TRUE;
		}
		if (bitsDamage & DMG_SHOCK)
		{
			bitsDamage &= ~DMG_SHOCK;
			ffound = TRUE;
		}
	}
	*/
	pev->punchangle.x = -2;

	/* disabled by harSens
	if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) 
	{
		// first time we take major damage...
		// turn automedic on if not on
		SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN);	// automedic on

		// give morphine shot if not given recently
		SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN);	// morphine shot
	}
	
	if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75)
	{

		// already took major damage, now it's critical...
		if (pev->health < 6)
			SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN);	// near death
		else if (pev->health < 20)
			SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN);	// health critical
	
		// give critical health warnings
		if (!RANDOM_LONG(0,3) && flHealthPrev < 50)
			SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention
	}
	*/		
	// if we're taking time based damage, warn about its continuing effects
	if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75)
		{
			if (flHealthPrev < 50)
			{
				if (!RANDOM_LONG(0,3))
					SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention
			}
			else
				SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN);	// health dropping
		}

	return fTookDamage;
}

//=========================================================
// PackDeadPlayerItems - call this when a player dies to
// pack up the appropriate weapons and ammo items, and to
// destroy anything that shouldn't be packed.
//
// This is pretty brute force :(
//=========================================================
void CBasePlayer::PackDeadPlayerItems( void )
{	/* changed by harSens: only pack sensubeans
	int iWeaponRules;
	int iAmmoRules;
	int i;
	CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have?
	int iPackAmmo[ MAX_AMMO_SLOTS + 1];
	int iPW = 0;// index into packweapons array
	int iPA = 0;// index into packammo array

	memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) );
	memset(iPackAmmo, -1, sizeof(iPackAmmo) );

	// get the game rules 
	iWeaponRules = g_pGameRules->DeadPlayerWeapons( this );
 	iAmmoRules = g_pGameRules->DeadPlayerAmmo( this );

	if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO )
	{
		// nothing to pack. Remove the weapons and return. Don't call create on the box!
		RemoveAllItems( TRUE );
		return;
	}

// go through all of the weapons and make a list of the ones to pack
	for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
	{
		if ( m_rgpPlayerItems[ i ] )
		{
			// there's a weapon here. Should I pack it?
			CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ];

			while ( pPlayerItem )
			{
				switch( iWeaponRules )
				{
				case GR_PLR_DROP_GUN_ACTIVE:
					if ( m_pActiveItem && pPlayerItem == m_pActiveItem )
					{
						// this is the active item. Pack it.
						rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem;
					}
					break;

				case GR_PLR_DROP_GUN_ALL:
					rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem;
					break;

				default:
					break;
				}

				pPlayerItem = pPlayerItem->m_pNext;
			}
		}
	}

// now go through ammo and make a list of which types to pack.
	if ( iAmmoRules != GR_PLR_DROP_AMMO_NO )
	{
		for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ )
		{
			if ( m_rgAmmo[ i ] > 0 )
			{
				// player has some ammo of this type.
				switch ( iAmmoRules )
				{
				case GR_PLR_DROP_AMMO_ALL:
					iPackAmmo[ iPA++ ] = i;
					break;

				case GR_PLR_DROP_AMMO_ACTIVE:
					if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) 
					{
						// this is the primary ammo type for the active weapon
						iPackAmmo[ iPA++ ] = i;
					}
					else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) 
					{
						// this is the secondary ammo type for the active weapon
						iPackAmmo[ iPA++ ] = i;
					}
					break;

				default:
					break;
				}
			}
		}
	}

// create a box to pack the stuff into.
	CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() );

	pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt.
	pWeaponBox->pev->angles.z = 0;

	pWeaponBox->SetThink( CWeaponBox::Kill );
	pWeaponBox->pev->nextthink = gpGlobals->time + 120;

// back these two lists up to their first elements
	iPA = 0;
	iPW = 0;

// pack the ammo
	while ( iPackAmmo[ iPA ] != -1 )
	{
		pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName ), m_rgAmmo[ iPackAmmo[ iPA ] ] );
		iPA++;
	}

// now pack all of the items in the lists
	while ( rgpPackWeapons[ iPW ] )
	{
		// weapon unhooked from the player. Pack it into der box.
		pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] );

		iPW++;
	}

	pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some.
	*/

/* DragonDude: don't drop senzu beans
	if (m_iSensuBeans>0)
	{	CPlayerBag::CreateBag(m_iSensuBeans,this);
	}
*/
	RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above.
}
void CBasePlayer::RemoveAllWeapons( BOOL removeSuit)
{	if (m_pActiveItem)
	{
		/* disabled by harSens
		ResetAutoaim( );
		*/
		//TEST by harSens
		m_pActiveItem->Holster( );	
		m_pActiveItem = NULL;
	}

	m_pLastItem = NULL;

	int i;
	CBasePlayerItem *pPendingItem;
	for (i = 0; i < MAX_ITEM_TYPES; i++)
	{
		m_pActiveItem = m_rgpPlayerItems[i];
		while (m_pActiveItem)
		{
			//added by harSens
			extern int gmsgWeaponUpdate;
			MESSAGE_BEGIN( MSG_ONE, gmsgWeaponUpdate, NULL, pev );
				WRITE_CHAR( -m_pActiveItem->m_iId );
			MESSAGE_END();

			pPendingItem = m_pActiveItem->m_pNext; 
			m_pActiveItem->Drop( );
			m_pActiveItem = pPendingItem;			
		}
		m_rgpPlayerItems[i] = NULL;
	}
	m_pActiveItem = NULL;

	pev->viewmodel		= 0;
	pev->weaponmodel	= 0;
	
	if ( removeSuit )
		pev->weapons = 0;
	/*removed by harSens
	else
		pev->weapons &= ~WEAPON_ALLWEAPONS;
	*/

	UpdateClientData();
	// send Selected Weapon Message to our client
	MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
		WRITE_BYTE(0);
		WRITE_BYTE(0);
		WRITE_BYTE(0);
	MESSAGE_END();
}

float CBasePlayer::GetPowerRatio( void )
{	if (g_pGameRules->m_iAveragePowerLevel)
	{	float flRatio = (float)GetPowerLevel()/(float)g_pGameRules->m_iAveragePowerLevel;
		return flRatio<MAX_POWER_RATIO?flRatio:MAX_POWER_RATIO;
	}
	else
	{	return 0;
	}
}

void CBasePlayer::RemoveAllItems( BOOL removeSuit )
{	/* moved to RemoveAllWeapons
	if (m_pActiveItem)
	{
		ResetAutoaim( );
		m_pActiveItem->Holster( );
		m_pActiveItem = NULL;
	}

	m_pLastItem = NULL;

	int i;
	CBasePlayerItem *pPendingItem;
	for (i = 0; i < MAX_ITEM_TYPES; i++)
	{
		m_pActiveItem = m_rgpPlayerItems[i];
		while (m_pActiveItem)
		{
			pPendingItem = m_pActiveItem->m_pNext; 
			m_pActiveItem->Drop( );
			m_pActiveItem = pPendingItem;
		}
		m_rgpPlayerItems[i] = NULL;
	}
	m_pActiveItem = NULL;

	pev->viewmodel		= 0;
	pev->weaponmodel	= 0;
	
	if ( removeSuit )
		pev->weapons = 0;
	else
		pev->weapons &= ~WEAPON_ALLWEAPONS;
	*/
	/* disabled by harSens
	for ( i = 0; i < MAX_AMMO_SLOTS;i++)
		m_rgAmmo[i] = 0;
	*/
	/* moved to RemoveAllWeapons
	UpdateClientData();
	// send Selected Weapon Message to our client
	MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
		WRITE_BYTE(0);
		WRITE_BYTE(0);
	*/
	//added by harSens
	RemoveAllWeapons(removeSuit);

	//added by harSens: update sensubean status
	/* DragonDude: don't remove senzu beans upon death
	m_iSensuBeans = 0;
	MESSAGE_BEGIN( MSG_ONE, gmsgSensuBean, NULL, pev );
		WRITE_BYTE(0);
	MESSAGE_END();
	*/
}

/*
 * GLOBALS ASSUMED SET:  g_ulModelIndexPlayer
 *
 * ENTITY_METHOD(PlayerDie)
 */
entvars_t *g_pevLastInflictor;  // Set in combat.cpp.  Used to pass the damage inflictor for death messages.
								// Better solution:  Add as parameter to all Killed() functions.

/**
* Pcjoe: Remove Special Modes
*/
void CBasePlayer::RemoveSpecialModes( void )
{	//added by harSens:unblind player
	if (m_fBlinded)
	{	UTIL_ScreenFade	( this, Vector (255,255,255), 0, 0, 255, FFADE_IN );	
	}

	//added by harSens:disable special modes
	if (m_fAscending)
	{	Descend( true );
		
		// Added by Pcjoe: Disable transform FX
		MESSAGE_BEGIN( MSG_ALL, gmsgStopTransformFX, pev->origin);
			WRITE_BYTE(entindex());		// Index of Player
		MESSAGE_END();
		
		// Added by Pcjoe: Disable model lock
		UTIL_Model_RemoveAll( entindex() );
	}	
	if (m_fPowerUp)
	{	StopPowerUp();
	}
	if (m_fBlock)
	{	StopBlock();
	}
	if (m_fFlying)
	{	StopFly();
	}
	if (m_fTurbo)
	{	StopTurbo();
	}
	//dead players can't wish
	m_fWishing = false;
	// Added by Pcjoe
	if (m_Swoop.m_fSwoop)
	{	StopSwoop();
	}
	if(m_pAura)
	{
		m_pAura->Destroy();
		m_pAura = NULL;
	}
	// Moved down here to be used w/ the death flag
	while(m_pClass->CanDescend())
	{
		Descend( true );
	}
	//end harSens add

	// added by Pcjoe : Disable melee + its animations if enabled...
	if(m_fMelee)
	{	// Stop Throw
		if(m_Melee.m_fThrown)
		{	m_Melee.StopThrow();
		}
		// Disable advanced melee
		if(m_Melee.InAdvMeleeBattle())
		{	if(m_Melee.IsAttacker())
			{	m_Melee.StopMelee(FALSE);
			}
		}
		// Disable walljump
		if(m_fWallJump)
		{	RemoveWallJump();
		}
		m_fMelee = FALSE;
	}

	if(!m_Melee.InAdvMeleeBattle())
	{	m_Melee.Reset();
	}

	//unfreeze controls
	if(FBitSet(pev->flags, FL_FROZEN))
	{	pev->flags &= ~FL_FROZEN;
	}
	// Used for KI Blast blob attack
	for(int i = 0; i < 2; i++)
	{	m_vecBlob[i] = Vector(0, 0, 0);
		m_flBlobTime[i] = -1;
	}
	m_fShield = FALSE;
	m_flLastTeleport = 0;
	// Remove weps after trans
	m_fAddWepAfterTrans = FALSE;
	// Sub model control
	m_flSubModelDelay = 0;
	m_iNextSubModel = 0;
	// Reset Trans animation
	m_iTransformStatus = TRANS_NONE;
	m_flDragonBallPickup = 0;

	// Added by Rick
	m_flDragonballDrop = 0.0f;

	// stop immortality
	m_fInvulnerable = false;
	if (m_fSpawnInvulnerable)
	{	m_fSpawnInvulnerable = false;
		pev->rendermode = kRenderNormal;
		pev->renderfx = kRenderFxNone;
	}
}

void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib )
{
	CSound *pSound;

	//added by harSens: no longer invulnerable
	m_fInvulnerable = false;
	m_fSpawnInvulnerable = false;
	m_iHideHUD = (HIDEHUD_HEALTH | HIDEHUD_WEAPONS);

	//added by harSens: remove weapon related animations
	m_szAnimExtention[0]='\0';

	/*DEBUG by harSens: if i enable this it crashes :(
	// Holster weapon immediately, to allow it to cleanup
	if ( m_pActiveItem )
		m_pActiveItem->Holster( );
	*/
	//added by harSens
	entvars_t *pevWorld = VARS( INDEXENT(0) );
	if(pevAttacker==pevWorld || pevAttacker==pev)
	{	
		m_fSelfKill=true;
	}

	g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor );

	if ( m_pTank != NULL )
	{
		m_pTank->Use( this, this, USE_OFF, 0 );
		m_pTank = NULL;
	}

	// this client isn't going to be thinking for a while, so reset the sound until they respawn
	pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) );
	{
		if ( pSound )
		{
			pSound->Reset();
		}
	}

	// Pcjoe: Remove Special Modes
	RemoveSpecialModes();

	// Removed by Pcjoe
//	SetAnimation( PLAYER_DIE );
	// Pcjoe: Play death anim
	m_Melee.SetAttacker( this );
	UTIL_MakeVectors(pev->v_angle);
	float flDot = DotProduct(gpGlobals->v_forward, pev->velocity.Normalize());
	if(flDot > 0)
	{	m_Melee.AddAnimation(true, gpGlobals->time, 1, "die_fall_down");
	}
	else
	{	m_Melee.AddAnimation(true, gpGlobals->time, 1, "die_fall_up");
	}
	
	m_iRespawnFrames = 0;

	// Removed by Pcjoe
//	pev->modelindex = g_ulModelIndexPlayer;    // don't use eyes

	pev->deadflag		= DEAD_DYING;
	pev->movetype		= MOVETYPE_TOSS;
	// Added by Pcjoe, setting gravity + friction back to normal and disabing player key movement
	pev->gravity		= 1.0;
	pev->friction		= 1.0;
	m_flSlowDown = 0;

	ClearBits( pev->flags, FL_ONGROUND );
	if (pev->velocity.z < 10)
		pev->velocity.z += RANDOM_FLOAT(0,300);

	// clear out the suit message cache so we don't keep chattering
	SetSuitUpdate(NULL, FALSE, 0);

	// send "health" update message to zero
	m_iClientHealth = 0;
	MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev );
		WRITE_BYTE( m_iClientHealth );
	MESSAGE_END();

	// Tell Ammo Hud that the player is dead
	MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
		WRITE_BYTE(0);
		WRITE_BYTE(0XFF);
		WRITE_BYTE(0xFF);
	MESSAGE_END();

	// reset FOV
	pev->fov = m_iFOV = m_iClientFOV = 0;

	MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
		WRITE_BYTE(0);
	MESSAGE_END();


	// UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12
	// UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE );
	
	//added by harSens
	if(g_pevLastInflictor)
	{
		CBaseEntity *pEnt=CBaseEntity::Instance(g_pevLastInflictor);
	
		// disc kill? create body slices!
		if (pEnt->Classify()==CLASS_DISCATTACK)
		{	
			pev->solid = SOLID_NOT;		
			CBodySlice::SpawnBodySlices(pev,false);
			pev->effects |= EF_NODRAW;// This clears pev->model
			return;
		}

		// Added by Rick: let bots taunt or whine
		CBasePlayer *pKiller = NULL;
		
		// Is the damager a player?
		if (pEnt->IsPlayer())
			pKiller = (CBasePlayer *)pEnt;
		// else is the ent owned by an (valid) player?
		else if ((!IsNull(g_pevLastInflictor->owner)) &&
				 (g_pevLastInflictor->owner->v.flags & FL_CLIENT))
			pKiller = (CBasePlayer *)CBaseEntity::Instance(g_pevLastInflictor->owner);

		if ((pKiller) && (pKiller != this))
		{
			// Player is killed by another bot?
			if (UTIL_IsBot(pKiller))
			{
				CBot *pOtherBot = UTIL_GetBotPointer(pKiller);
				if (RANDOM_LONG(1, 100) <= pOtherBot->m_pPersonality->taunt_percent)
					ChatClass.LetBotTaunt(pOtherBot, this);
			}
		}
	}

	// Added by Rick: if this player is a bot, let him know that he's killed
	if (UTIL_IsBot(this))
	{
		CBot *pBot = UTIL_GetBotPointer(this);
		pBot->BotKilled(g_pevLastInflictor);
	}

	if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS )
	{
		pev->solid			= SOLID_NOT;
		GibMonster();	// This clears pev->model
		pev->effects |= EF_NODRAW;
		return;
	}

	DeathSound();
	
	pev->angles.x = 0;
	pev->angles.z = 0;

	//added by harSens: fade player away
	pev->renderamt = 255;
	pev->rendermode = kRenderTransTexture;
	pev->renderfx = kRenderFxNone;
	
	SetThink(&CBasePlayer::PlayerDeathThink);
	pev->nextthink = gpGlobals->time + 0.1;
}


//Pcjoe: Can play forward walk/run animation
BOOL CBasePlayer::CanPlayForwardWalk( void )
{	UTIL_MakeVectors ( pev->v_angle );
	float flDot = DotProduct (pev->velocity, gpGlobals->v_forward);

	// Use Forward anims
	if (flDot > VIEW_FIELD_FULL)
	{	return TRUE;
	}
	// Use backward anims
	return FALSE;
}

void CBasePlayer::RemoveAnimationTriggers()
{
	//remove triggers on running animations if they're finished
	if(m_eAnimationTrigger == PLAYER_ATTACK1)
	{	if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_ATTACK2)
	{	if (m_Activity != ACT_RANGE_ATTACK2 || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_SWATAWAY_LEFT)
	{	if (m_Activity != ACT_SWATAWAY_LEFT || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
			m_fSwat = false;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_SWATAWAY_RIGHT)
	{	if (m_Activity != ACT_SWATAWAY_RIGHT || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
			m_fSwat = false;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_SWATAWAY_FORWARD)
	{	if (m_Activity != ACT_SWATAWAY_FORWARD || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
			m_fSwat = false;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_WRAP)
	{	if (m_Activity != ACT_WRAP || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_JUMP)
	{	if (m_Activity != ACT_HOP || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_BACKFLIP)
	{	if (m_Activity != ACT_BACKFLIP || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
	else if(m_eAnimationTrigger == PLAYER_SUPERJUMP)
	{	if (m_Activity != ACT_LEAP || m_fSequenceFinished)
		{	m_eAnimationTrigger = PLAYER_NULL;
		}
	}
}

int CBasePlayer::PlayFullBodyAnimation()
{	m_IdealActivity = ACT_RESET;
	ANIM_FLAGS eIdealAnimFlags = ANIM_NONE;
	int animDesired = 0;
	char szAnim[64];
	//choose full body animation

	//wrapped in a bodypart
	if(m_eAnimationTrigger == PLAYER_WRAP)
	{	m_IdealActivity = ACT_WRAP;
		animDesired = LookupSequence("wrap");
	}
	else if (m_eAnimationTrigger != PLAYER_NULL)
	{	//all other ani triggers go on the upper body
		return false;
	}
	// Removed by Pcjoe
	//DIE!
/*	if (m_eAnimationTrigger == PLAYER_DIE)
	{	m_IdealActivity = ACT_DIESIMPLE;
		m_IdealActivity = GetDeathActivity( );
		animDesired = LookupActivity( m_IdealActivity );
		m_eAnimationTrigger = PLAYER_NULL;
	}*/
	// Added by Pcjoe
	// Advanced Melee Animations
	else if ( m_Melee.CanPlayAnimation() )
	{	int iAnim;
		// Get animation
		plrmelee_anim_s *pAnim = m_Melee.GetCurrentAnim();
		iAnim = LookupSequence( pAnim->szAnim[pAnim->iCurrentAnim] );
		if(iAnim == -1)
			iAnim = 0;

		// Init animation ( Reset frames )
		if(!pAnim->fInit )
		{	pev->frame = 0.001;	// HACK HACK: Setting to a incredibly low non-zero value so we wont 'skip' animations accidently
			m_fSequenceFinished = FALSE;
			pAnim->fStartOnGround = FBitSet(pev->flags,FL_ONGROUND);
			pAnim->fInit = TRUE;
		}

		// Set animation
		m_IdealActivity = pAnim->IdealActivity[pAnim->iCurrentAnim];
		animDesired = iAnim;	
		eIdealAnimFlags = ANIM_REF;

		if((iAnim == pev->sequence && m_fSequenceFinished) || pev->frame == 255)
		{	// First check if it's combo execution
			if(pAnim->fExecution)
			{	// switch to next combo in list
				m_Melee.NextExeMove( );
			}
			// Go to next anim
			else if((pAnim->iCurrentAnim+1) < pAnim->iNumAnims)
			{	pAnim->iCurrentAnim++;
			}
			else
			{	// Sequence is finished, we arn't looping, delete it
				if(!pAnim->fLooping && !m_Melee.InAdvMeleeBattle())
				{	// Unset fixed angles
					m_Melee.RemoveAnim(pAnim);
				}
			}
		}
	}
	// If Ascending + not controlling a beam, play the FX
	else if ( m_fAscending && !m_fControl )
	{
		eIdealAnimFlags = ANIM_REF;

		float flAscendTime = m_flAscendTime - gpGlobals->time;

		switch(m_iTransformStatus)
		{
		case TRANS_SHORT:
			{
				strcpy( szAnim, "change_finish" );
				m_IdealActivity = ACT_TRANS_FINISH;
				break;
			}
		case TRANS_NORM:
			{
				if(flAscendTime <= 1)
				{
					strcpy( szAnim, "change_finish" );
					m_IdealActivity = ACT_TRANS_FINISH;
				}
				else
				{
					strcpy( szAnim, "change_normal" );
					m_IdealActivity = ACT_TRANS_NORMAL;
				}
				break;
			}
		case TRANS_LONG:
			{
				if(flAscendTime <= 1)
				{
					strcpy( szAnim, "change_finish" );
					m_IdealActivity = ACT_TRANS_FINISH;
				}
				else
				{
					strcpy( szAnim, "change_long" );
					m_IdealActivity = ACT_TRANS_LONG;
				}
				break;
			}
		default:
			{
				strcpy( szAnim, "change_normal" );
				m_IdealActivity = ACT_TRANS_NORMAL;
				break;
			}
		}
		animDesired = LookupSequence( szAnim );
	}
	// Added by Pcjoe
	else if(m_fMelee)
	{	// Swoop Animation
		if(m_Swoop.m_fSwoop)
		{	m_Swoop.SetSwoopAnim( szAnim, m_IdealActivity );
		}
		// Throw animation
		else if( m_Melee.m_fThrown )
		{	m_Melee.SetThrowAnim( szAnim, m_IdealActivity );
		}
		
		// Set animation
		eIdealAnimFlags = ANIM_REF;
		animDesired = LookupSequence( szAnim );
	}
	// end of add by Pcjoe
	//Control attacks
	else if(m_fControl)
	{//	m_IdealActivity = ACT_CONTROL;
		// Edited by Pcjoe, add in support for beam jump anims
		if(pev->movetype == MOVETYPE_RIDEBEAM)
		{	m_IdealActivity = ACT_BEAMJUMP;
			strcpy( szAnim, "ref_beam_push" );
		}
		else
		{	m_IdealActivity = ACT_CONTROL;
			strcpy( szAnim, "ref_control_" );
			strcat( szAnim, m_szAnimExtention );
		}
		eIdealAnimFlags = ANIM_REF;
		animDesired = LookupSequence( szAnim );		
	}
	
	//charge attacks secondary mode (when not able to walk with them
	else if(m_fCharging2 && m_flSlowDown == 0.0)
	{	m_IdealActivity = ACT_CHARGE;
		strcpy( szAnim, "ref_charge2_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;
		animDesired = LookupSequence( szAnim );
	}
	//charge attacks (when not able to walk with them
	else if(m_fCharging && m_flSlowDown == 0.0)
	{	m_IdealActivity = ACT_CHARGE;
		strcpy( szAnim, "ref_charge_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;
		animDesired = LookupSequence( szAnim );
	}
	
	//blocking
	else if(m_fBlock && !m_fSwat)
	{	m_IdealActivity = ACT_BLOCK;
		if (m_fFlying)
		{	strcpy( szAnim, "fly_block" );
			eIdealAnimFlags = ANIM_FLY;
		}
		else
		{	strcpy( szAnim, "ref_block" );
			eIdealAnimFlags = ANIM_REF;
		}
		animDesired = LookupSequence( szAnim );
	}
	//strangled
	else if (m_fStrangled)
	{	/*
		if (m_fPowerUp)
		{	
		}
		else
		*/
		{	animDesired = LookupSequence("struggle");
			m_IdealActivity = ACT_STRUGGLE;
		}
	}
	
	//powering up
	else if (m_fPowerUp)
	{	if ( (m_Activity == ACT_POWERUP && m_fSequenceFinished) || m_Activity == ACT_POWERUPCHARGE)
		{	m_IdealActivity = ACT_POWERUPCHARGE;		
			//select right ani
			if (m_fFlying)
			{	animDesired = LookupSequence ("fly_powerup_charge");
				eIdealAnimFlags = ANIM_FLY;
			}
			else
			{	animDesired = LookupSequence ("ref_powerup_charge");
				eIdealAnimFlags = ANIM_REF;
			}
		}
		else
		{	m_IdealActivity = ACT_POWERUP;
			//select right ani
			if (m_fFlying)
			{	animDesired = LookupSequence ("fly_powerup");
				eIdealAnimFlags = ANIM_FLY;
			}
			else
			{	animDesired = LookupSequence ("ref_powerup");
				eIdealAnimFlags = ANIM_REF;
			}
		}
	}

	// Charged turbo
	else if (m_ChargedTurbo.isChargeTurboActive())
	{	if(m_Swoop.GetActiveDirection() != -1)
		{	m_IdealActivity = ACT_SWOOP_PREP;
			animDesired = LookupSequence ("turbo_boost");
			eIdealAnimFlags = ANIM_REF;
		}
		else if ( (m_Activity == ACT_CHARGE_TURBO && m_fSequenceFinished) || m_Activity == ACT_CHARGE_TURBO_CHARGE || m_Activity == ACT_SWOOP_PREP)
		{	m_IdealActivity = ACT_CHARGE_TURBO_CHARGE;
			animDesired = LookupSequence ("turbo_charge");
			eIdealAnimFlags = ANIM_REF;
		}
		else
		{	m_IdealActivity = ACT_CHARGE_TURBO;
			animDesired = LookupSequence ("turbo_start");
			eIdealAnimFlags = ANIM_REF;
		}
	}

	//play the animation
	if (m_IdealActivity )
	{	// Pcjoe: Reset animation trigger
		if(m_eAnimationTrigger != PLAYER_NULL)
			m_eAnimationTrigger = PLAYER_NULL;
		int iFrame = 0;
		if ( m_Activity == m_IdealActivity )
		{	if (eIdealAnimFlags && eIdealAnimFlags==m_eAnimationFlags)
			{	return true;
			}
			// Pcjoe: Force interpolation on death
			else if(IsAlive())
			{	iFrame = pev->frame;
				pev->effects |= EF_NOINTERP;
			}
		}
		m_Activity = m_IdealActivity;
		m_eAnimationFlags = eIdealAnimFlags;
		
		if (animDesired == -1)
		{	animDesired = 0;			
		}		
		
		// Already using the desired animation?
		if (pev->sequence == animDesired)
		{	return true;
		}

		pev->gaitsequence = 0;
		pev->sequence		= animDesired;
		pev->frame			= iFrame;
		ResetSequenceInfo( );
		return true;
	}
	return false;
}
int CBasePlayer::GetUpperBodyAnimation(int &iFrame)
{	int animDesired = 0;
	ANIM_FLAGS eIdealAnimFlags = ANIM_NONE;
	float flSpeed = pev->velocity.Length2D();
	char szAnim[64];
	
	//select an animation
	//attack 1
	if (m_eAnimationTrigger == PLAYER_ATTACK1)
	{	m_IdealActivity = ACT_RANGE_ATTACK1;
		strcpy( szAnim, "ref_shoot_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;		
		animDesired = LookupSequence( szAnim );
	}
	
	//attack 2
	else if (m_eAnimationTrigger == PLAYER_ATTACK2)
	{	m_IdealActivity = ACT_RANGE_ATTACK2;
		strcpy( szAnim, "ref_shoot2_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;		
		animDesired = LookupSequence( szAnim );
	}
	
	//charging secondary
	else if (m_fCharging2)
	{	m_IdealActivity = ACT_CHARGE;
		strcpy( szAnim, "ref2_charge_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;		
		animDesired = LookupSequence( szAnim );
	}
	//charging
	else if (m_fCharging)
	{	m_IdealActivity = ACT_CHARGE;
		strcpy( szAnim, "ref_charge_" );
		strcat( szAnim, m_szAnimExtention );
		eIdealAnimFlags = ANIM_REF;		
		animDesired = LookupSequence( szAnim );
	}

	//swat an attack away to the left
	else if (m_eAnimationTrigger == PLAYER_SWATAWAY_LEFT)
	{	m_fSwat = true;
		m_IdealActivity = ACT_SWATAWAY_LEFT;
		strcpy( szAnim, "ref_left_swataway" );
		animDesired = LookupSequence( szAnim );
		eIdealAnimFlags = ANIM_REF;		
	}

	//swat an attack away to the right
	else if (m_eAnimationTrigger == PLAYER_SWATAWAY_RIGHT)
	{	m_fSwat = true;
		m_IdealActivity = ACT_SWATAWAY_RIGHT;
		strcpy( szAnim, "ref_right_swataway" );
		animDesired = LookupSequence( szAnim );
		eIdealAnimFlags = ANIM_REF;		
	}

	//push a heavy beam forward
	else if (m_eAnimationTrigger == PLAYER_SWATAWAY_FORWARD)
	{	m_fSwat = true;
		m_IdealActivity = ACT_SWATAWAY_FORWARD;
		strcpy( szAnim, "ref_forward_swataway" );
		animDesired = LookupSequence( szAnim );
		eIdealAnimFlags = ANIM_REF;		
	}

	//aim animation?
	else 
	{	m_IdealActivity = ACT_WALK;
		if(m_fAimAnimation)
		{
			strcpy( szAnim, "ref_aim_" );
			strcat( szAnim, m_szAnimExtention );
			animDesired = LookupSequence( szAnim );
			if (animDesired == -1)
			{	animDesired = 0;
			}
		}
		else
		{
			animDesired = 0;
		}
		eIdealAnimFlags = ANIM_REF;				
		
		
		//no aim animation: generic walk/fly/jump/swim animation
		if (!animDesired)
		{	//Flying
			if (m_fFlying)
			{	// Edited by Pcjoe, Make the animations blend
				if(pev->button & IN_FORWARD)
				{	animDesired = LookupSequence( "fly_forward" );
					m_IdealActivity = ACT_FLY_FRONT;
				}
				else if(pev->button & IN_BACK)
				{	animDesired = LookupSequence( "fly_backward" );
					m_IdealActivity = ACT_FLY_BACK;
				}
				else
				{	animDesired = LookupSequence( "fly_idle" );
					m_IdealActivity = ACT_FLY;
				}
			}

			//Swimming
			else if ( pev->waterlevel > 1 )
			{// Edited by Pcjoe
				//	if ( flSpeed == 0 )
				if (flSpeed > GetMaxSpeed()/1.6)
				{	m_IdealActivity = ACT_SWIM;	

					// Back/front swimming animations
					if(pev->button & IN_BACK)
						animDesired = LookupSequence("swim_backwards");
					else
						animDesired = LookupActivity(ACT_SWIM);
				}
				else
				{	m_IdealActivity = ACT_HOVER;
					animDesired = LookupActivity(ACT_HOVER);
				}
			}

			else if (!FBitSet(pev->flags,FL_ONGROUND))
			{	//falling
				if(pev->velocity.z < 0 )
				{	m_IdealActivity = ACT_FALL;
					animDesired = LookupSequence("fly_fall");
				}

				//jumping
				else if(m_eAnimationTrigger == PLAYER_JUMP)
				{	m_IdealActivity = ACT_HOP;
					animDesired = LookupActivity(ACT_HOP);
				}
				
				//backflip
				else if(m_eAnimationTrigger == PLAYER_BACKFLIP)
				{	m_IdealActivity = ACT_BACKFLIP;
					animDesired = LookupSequence("back_flip");
				}

				//super jumping
				else if(m_eAnimationTrigger == PLAYER_SUPERJUMP)
				{	m_IdealActivity = ACT_LEAP;
					animDesired = LookupActivity(ACT_LEAP);
				}
				// Pcjoe: Must be moving upwards, play jump anim
				else
				{	m_IdealActivity = ACT_HOP;
					animDesired = LookupActivity(ACT_HOP);
				}

			}

			//walk/crouch
			else 
			{	// Edited by Pcjoe - Making it possible to walk :-)
				//	if ( flSpeed > GetMaxSpeed()/3 )
				if ( flSpeed > GetMaxSpeed()/1.3 || (m_fTurbo && flSpeed > 0))
				{	// Added by Pcjoe - Run Backwards
					if(pev->button & IN_BACK)
					{	animDesired = LookupSequence( "run_backward" );
						m_IdealActivity = ACT_RUN_BACK;
					}
					else
					{	// Turbo run anim
						if(m_fTurbo && ((pev->button & IN_FORWARD) || (pev->button & IN_MOVELEFT) || (pev->button & IN_MOVERIGHT)))
						{	animDesired = LookupSequence( "turbo_run" );
						}
						else
						{	// Added by Pcjoe
							if(CanPlayForwardWalk())
							{	animDesired = LookupSequence( "run" );
							}
							else
							{	animDesired = LookupSequence( "run_backward" );
							}
						}
						m_IdealActivity = ACT_RUN_FRONT;
					}
				}
				else if (flSpeed > 0)
				{	// Added by Pcjoe - walk Backwards
					if(pev->button & IN_BACK)
					{	animDesired = LookupSequence( "walk_backward" );
						m_IdealActivity = ACT_WALK;
					}
					else
					{	// Added by Pcjoe
						if(CanPlayForwardWalk())
						{	animDesired  = LookupSequence( "walk2handed" );
						}
						else
						{	animDesired = LookupSequence( "walk_backward" );
						}
						m_IdealActivity = ACT_WALK;
					}
				}
				else
				{	// Edited by Pcjoe, implention of deep idle
					if(pev->sequence != LookupSequence( "idle" ) && pev->sequence != LookupSequence( "deep_idle" ))
					{	m_flIdleTime = gpGlobals->time;
					}
					if(m_flIdleTime < gpGlobals->time - DEEP_IDLE_TIME)
					{	animDesired  = LookupSequence( "deep_idle" );
					}
					else
					{	animDesired  = LookupSequence( "idle" );
					}
				}
			}
		}
	}	

	//play the animation
	iFrame = 0;
	if ( m_Activity == m_IdealActivity )
	{	if (eIdealAnimFlags && eIdealAnimFlags!=m_eAnimationFlags)
		{	iFrame = pev->frame;				
		}		
	}
	m_Activity = m_IdealActivity;
	m_eAnimationFlags = eIdealAnimFlags;	

	if (animDesired == -1)
	{	animDesired = 0;
	}
	return animDesired;
}

int CBasePlayer::GetLowerBodyAnimation()
{	int animDesired = 0;
	float flSpeed = pev->velocity.Length2D();
	
	//Flying
	if (m_fFlying)
	{	if (pev->button & IN_BACK)
		{	animDesired = LookupSequence("fly_backward");			
		}
		else if (pev->button & IN_FORWARD)
		{	animDesired = LookupSequence("fly_forward");			
		}
		else
		{	animDesired = LookupSequence("fly_idle");			
		}
	}
	
	//Swimming
	else if ( pev->waterlevel > 1 )
	{// Edited by Pcjoe
		//	if ( flSpeed == 0 )
		if (flSpeed > GetMaxSpeed()/1.6)
		{
			// Back/front swimming animations
			if(pev->button & IN_BACK)
				animDesired = LookupSequence("swim_backwards");
			else
				animDesired = LookupActivity(ACT_SWIM);
		}
		else
		{	animDesired = LookupActivity(ACT_HOVER);
		}
	}

	else if(!FBitSet(pev->flags,FL_ONGROUND))
	{	//Falling
		if(pev->velocity.z < 0)
		{	animDesired = LookupSequence("fly_fall");
		}
	
		//Long Jumping
		else if(m_eAnimationTrigger == PLAYER_SUPERJUMP)
		{	animDesired = LookupActivity(ACT_LEAP);		
		}

		//Back Flip
		else if (m_eAnimationTrigger == PLAYER_BACKFLIP)
		{	animDesired = LookupSequence("back_flip");
		}
		
		//Jump
		else if(m_eAnimationTrigger == PLAYER_JUMP )
		{	animDesired = LookupActivity(ACT_HOP);		
		}

		// Pcjoe: Must be moving upwards, play jump anim
		else
		{	m_IdealActivity = ACT_HOP;
			animDesired = LookupActivity(ACT_HOP);
		}
	}	
	else 
	{	//Crouching
		// Edited by Pcjoe - Making it possible to walk :-)
		//	if ( flSpeed > GetMaxSpeed()/3 )
		if ( flSpeed > GetMaxSpeed()/1.3  || (m_fTurbo && flSpeed > 0))
		{	// Added by Pcjoe - Run Backwards
			if(pev->button & IN_BACK)
			{	animDesired = LookupSequence( "run_backward" );
			}
			else
			{	// Turbo run anim
				if(m_fTurbo && ((pev->button & IN_FORWARD) || (pev->button & IN_MOVELEFT) || (pev->button & IN_MOVERIGHT)))
				{	animDesired = LookupSequence( "turbo_run" );
				}
				else
				{	// Added by Pcjoe
					if(CanPlayForwardWalk())
					{	animDesired = LookupSequence( "run" );
					}
					else
					{	animDesired = LookupSequence( "run_backward" );
					}
				}
			}
		}
		else if ( flSpeed > 0 )
		{	// Added by Pcjoe - walk Backwards
			if(pev->button & IN_BACK)
			{	animDesired = LookupSequence( "walk_backward" );
			}
			else
			{	// Added by Pcjoe
				if(CanPlayForwardWalk())
				{	animDesired  = LookupSequence( "walk2handed" );
				}
				else
				{	animDesired = LookupSequence( "walk_backward" );
				}
			}		
		}
		else
		{	// Edited by Pcjoe, implention of deep idle
			if(pev->sequence != LookupSequence( "idle" ) && pev->sequence != LookupSequence( "deep_idle" ))
			{	m_flIdleTime = gpGlobals->time;
			}
			if(m_flIdleTime < gpGlobals->time - DEEP_IDLE_TIME)
			{	animDesired = LookupSequence( "deep_idle" );		
			}
			else
			{	animDesired  = LookupSequence( "idle" );
			}
		}		
	}

	//animation error, don't play ani
	if (animDesired == -1)
	{	animDesired = 0;
	}
	return animDesired;
}

void CBasePlayer::PlayAnimation( )
{	//set aura direction, 1 is up, 0 is down
	if (m_pAura)
	{	// Added by Pcjoe, better way to determine aura direction
		m_pAura->pev->body = GetAuraDirection();
	}

	// Added by Pcjoe, manage animations
	m_Melee.ManageList();
	//select an animation
	if (!PlayFullBodyAnimation())
	{	int iFrame;
		int animDesired = GetUpperBodyAnimation(iFrame);
		int animDesiredGait = GetLowerBodyAnimation();
		if (animDesiredGait)
		{	pev->gaitsequence = animDesiredGait;
		}
		
		// Already using the desired animation?
		if (pev->sequence != animDesired)
		{
			pev->frame = iFrame;
			pev->sequence = animDesired;
			ResetSequenceInfo( );
		}
	}
	RemoveAnimationTriggers();	
}
void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
{	// Added by Pcjoe, reset sequence first
	ResetSequenceInfo( );
	if (m_eAnimationTrigger != PLAYER_SWATAWAY_FORWARD && m_eAnimationTrigger != PLAYER_SWATAWAY_LEFT && m_eAnimationTrigger != PLAYER_SWATAWAY_RIGHT)
	{	m_fSwat = false;
	}
	m_eAnimationTrigger = playerAnim;
	PlayAnimation();
}

void CBasePlayer::StopAniTrigger( PLAYER_ANIM playerAnim )
{	if (m_eAnimationTrigger == playerAnim)
	{	ResetSequenceInfo();
		m_eAnimationTrigger = PLAYER_NULL;
		m_fSwat = false;
		PlayAnimation();
	}
}
/*

// Set the activity based on an event or current state
void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
{
	int animDesired;
	float speed;
	char szAnim[64];

	speed = pev->velocity.Length2D();

	if (pev->flags & FL_FROZEN)
	{
		speed = 0;
		playerAnim = PLAYER_IDLE;
	}

	switch (playerAnim) 
	{
	case PLAYER_JUMP:
		m_IdealActivity = ACT_HOP;
		break;
	
	case PLAYER_SUPERJUMP:
		m_IdealActivity = ACT_LEAP;
		break;
	
	case PLAYER_DIE:
		m_IdealActivity = ACT_DIESIMPLE;
		m_IdealActivity = GetDeathActivity( );
		break;

	case PLAYER_ATTACK1:	
		switch( m_Activity )
		{
		case ACT_HOVER:
		case ACT_SWIM:
		case ACT_HOP:
		case ACT_LEAP:
		case ACT_DIESIMPLE:
			m_IdealActivity = m_Activity;
			break;
		default:
			m_IdealActivity = ACT_RANGE_ATTACK1;
			break;
		}
		break;
	case PLAYER_IDLE:
	case PLAYER_WALK:
		if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) )	// Still jumping
		{
			m_IdealActivity = m_Activity;
		}
		else if ( pev->waterlevel > 1 )
		{
			if ( speed == 0 )
				m_IdealActivity = ACT_HOVER;
			else
				m_IdealActivity = ACT_SWIM;
		}
		else
		{
			m_IdealActivity = ACT_WALK;
		}
		break;
	}

	switch (m_IdealActivity)
	{
	case ACT_HOVER:
	case ACT_LEAP:
	case ACT_SWIM:
	case ACT_HOP:
	case ACT_DIESIMPLE:
	default:
		if ( m_Activity == m_IdealActivity)
			return;
		m_Activity = m_IdealActivity;

		animDesired = LookupActivity( m_Activity );
		// Already using the desired animation?
		if (pev->sequence == animDesired)
			return;

		pev->gaitsequence = 0;
		pev->sequence		= animDesired;
		pev->frame			= 0;
		ResetSequenceInfo( );
		return;

	case ACT_RANGE_ATTACK1:
		if ( FBitSet( pev->flags, FL_DUCKING ) )	// crouching
			strcpy( szAnim, "crouch_shoot_" );
		else
			strcpy( szAnim, "ref_shoot_" );
		strcat( szAnim, m_szAnimExtention );
		animDesired = LookupSequence( szAnim );
		if (animDesired == -1)
			animDesired = 0;

		if ( pev->sequence != animDesired || !m_fSequenceLoops )
		{
			pev->frame = 0;
		}

		if (!m_fSequenceLoops)
		{
			pev->effects |= EF_NOINTERP;
		}

		m_Activity = m_IdealActivity;

		pev->sequence		= animDesired;
		ResetSequenceInfo( );
		break;

	case ACT_WALK:
		if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished)
		{
			if ( FBitSet( pev->flags, FL_DUCKING ) )	// crouching
				strcpy( szAnim, "crouch_aim_" );
			else
				strcpy( szAnim, "ref_aim_" );
			strcat( szAnim, m_szAnimExtention );
			animDesired = LookupSequence( szAnim );
			if (animDesired == -1)
				animDesired = 0;
			m_Activity = ACT_WALK;
		}
		else
		{
			animDesired = pev->sequence;
		}
	}

	if ( FBitSet( pev->flags, FL_DUCKING ) )
	{
		if ( speed == 0)
		{
			pev->gaitsequence	= LookupActivity( ACT_CROUCHIDLE );
			// pev->gaitsequence	= LookupActivity( ACT_CROUCH );
		}
		else
		{
			pev->gaitsequence	= LookupActivity( ACT_CROUCH );
		}
	}
	else if ( speed > 220 )
	{
		pev->gaitsequence	= LookupActivity( ACT_RUN );
	}
	else if (speed > 0)
	{
		pev->gaitsequence	= LookupActivity( ACT_WALK );
	}
	else
	{
		// pev->gaitsequence	= LookupActivity( ACT_WALK );
		pev->gaitsequence	= LookupSequence( "deep_idle" );
	}


	// Already using the desired animation?
	if (pev->sequence == animDesired)
		return;

	//ALERT( at_console, "Set animation to %d\n", animDesired );
	// Reset to first frame of desired animation
	pev->sequence		= animDesired;
	pev->frame			= 0;
	ResetSequenceInfo( );
}

/*
===========
TabulateAmmo
This function is used to find and store 
all the ammo we have into the ammo vars.
============
*/
/* disabled by harSens
void CBasePlayer::TabulateAmmo()
{
	ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) );
	ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) );
	ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) );
	ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) );
	ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) );
	ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) );
	ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) );
	ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) );
}
*/
/*
added by harSens
*/

BOOL CBasePlayer::HasStamina(int amount)
{	
	if(m_fExhausted)return false;
	if(amount==0)return true;
	amount *= m_pClass->GetStaminaEfficiency();
	if(amount<1)
	{	amount=1;
	}

	if(m_iStamina<amount)
	{	//return false;
		return true;
	}
	else
	{	return true;
	}
}


BOOL CBasePlayer::UseStamina(int amount)
{	
	if(m_fExhausted)return false;
	if(amount==0)return true;
	amount *= m_pClass->GetStaminaEfficiency();
	if(amount<1)
	{	amount=1;
	}

	if(m_iStamina<amount)
	{	//return false;
		m_iStamina = 0;
		return true;		
	}
	else
	{	m_iStamina-=amount;
		return true;
	}
}

BOOL CBasePlayer::HasKi(int amount)
{
	if(amount==0)return true;
	amount *= m_pClass->GetKiEfficiency();
	if(amount<1)
	{	amount=1;
	}

	if(pev->fuser4<amount)
	{	return false;
	}
	else
	{	return true;
	}
}

BOOL CBasePlayer::UseKi(int amount)
{	if(amount==0)return true;	
	amount *= m_pClass->GetKiEfficiency();
	if(amount<1)
	{	amount=1;
	}

	if(pev->fuser4<amount)
	{	return false;
	}
	else
	{	pev->fuser4-=amount;
		return true;
	}
}


/*
===========
WaterMove
============
*/
/*modified by harSens: ZWarriors can stay longer underwater :-)
#define AIRTIME	12		// lung full of air lasts this many seconds
*/
#define AIRTIME	90		// lung full of air lasts this many seconds

void CBasePlayer::WaterMove()
{
	int air;

	if (pev->movetype == MOVETYPE_NOCLIP)
		return;

	if (pev->health < 0)
		return;

	// waterlevel 0 - not in water
	// waterlevel 1 - feet in water
	// waterlevel 2 - waist in water
	// waterlevel 3 - head in water

	if (pev->waterlevel != 3) 
	{
		// not underwater
		
		// play 'up for air' sound
		if (pev->air_finished < gpGlobals->time)
			EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM);
		else if (pev->air_finished < gpGlobals->time + 9)
			EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM);

		pev->air_finished = gpGlobals->time + AIRTIME;
		pev->dmg = 2;

		// if we took drowning damage, give it back slowly
		if (m_idrowndmg > m_idrownrestored)
		{
			// set drowning damage bit.  hack - dmg_drownrecover actually
			// makes the time based damage code 'give back' health over time.
			// make sure counter is cleared so we start count correctly.
			
			// NOTE: this actually causes the count to continue restarting
			// until all drowning damage is healed.

			m_bitsDamageType |= DMG_DROWNRECOVER;
			m_bitsDamageType &= ~DMG_DROWN;
			m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
		}

	}
	else
	{	// fully under water
		// stop restoring damage while underwater
		m_bitsDamageType &= ~DMG_DROWNRECOVER;
		m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;

		if (pev->air_finished < gpGlobals->time)		// drown!
		{
			if (pev->pain_finished < gpGlobals->time)
			{
				// take drowning damage
				pev->dmg += 1;
				if (pev->dmg > 5)
					pev->dmg = 5;
				TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN);
				pev->pain_finished = gpGlobals->time + 1;
				
				// track drowning damage, give it back when
				// player finally takes a breath

				m_idrowndmg += pev->dmg;
			} 
		}
		else
		{
			m_bitsDamageType &= ~DMG_DROWN;
		}
	}

	if (!pev->waterlevel)
	{
		if (FBitSet(pev->flags, FL_INWATER))
		{       
			ClearBits(pev->flags, FL_INWATER);
		}
		return;
	}
	
	// make bubbles

	air = (int)(pev->air_finished - gpGlobals->time);
	if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air)
	{
		switch (RANDOM_LONG(0,3))
			{
			case 0:	EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break;
			case 1:	EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break;
			case 2:	EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break;
			case 3:	EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break;
		}
	}

	if (pev->watertype == CONTENT_LAVA)		// do damage
	{
		if (pev->dmgtime < gpGlobals->time)
		{	// added by Pcjoe
			// If player is in the lava and someone else blew him into their, give the blower credit
			if(m_Melee.m_pThrower && m_Melee.m_fThrown)
			{	TakeDamage(VARS(eoNullEntity), m_Melee.m_pThrower->pev, 10 * pev->waterlevel, DMG_BURN);
			}
			// Added by Rick; Same as above, just for buddies this time...
			if (m_Melee.m_pBuddyThrower && m_Melee.m_fThrown)
			{	TakeDamage(VARS(eoNullEntity), m_Melee.m_pBuddyThrower->pev, 10 * pev->waterlevel, DMG_BURN);
			}
			// Regular Lava DMG
			else
			{	TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN);
			}
		}
	}
	/* disabled by harSens

	else if (pev->watertype == CONTENT_SLIME)		// do damage
	{
		pev->dmgtime = gpGlobals->time + 1;
		TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID);
	}
	*/
	
	if (!FBitSet(pev->flags, FL_INWATER))
	{
		SetBits(pev->flags, FL_INWATER);
		pev->dmgtime = 0;
	}
}

/*
harSens:Gives you a few beans
*/
BOOL CBasePlayer::GiveBean(int nr_of_beans)
{	if (m_iSensuBeans<MAX_SENSUBEAN)
	{	m_iSensuBeans+=nr_of_beans;
		if (m_iSensuBeans>MAX_SENSUBEAN)
		{	m_iSensuBeans = MAX_SENSUBEAN;
		}
		
		//update hud
		MESSAGE_BEGIN( MSG_ONE, gmsgSensuBean, NULL, pev ); 
			WRITE_BYTE(m_iSensuBeans);	
		MESSAGE_END();		
		
		return TRUE;
	}
	return FALSE;
}

/*
harSens: take a bean, restoring health, ki and powerlevel
*/
BOOL CBasePlayer::TakeBean()
{	if (m_iSensuBeans>0)
	{	m_iSensuBeans--;

		//update hud
		MESSAGE_BEGIN( MSG_ONE, gmsgSensuBean, NULL, pev ); 
			WRITE_BYTE(m_iSensuBeans);	
		MESSAGE_END();		

		//restore health,ki,powerlevel
		pev->fuser4 = 1000;						//set max ki
		SetPowerLevel(m_iMaxPowerLevel);	//restore power level
		pev->health = m_iMaxHealth;			//restore health

		return TRUE;
	}
	return FALSE;
}

/*
harSens: send max health to the client
*/
void CBasePlayer::SetMaxHealth(int health)
{	MESSAGE_BEGIN( MSG_ONE, gmsgMaxHealth, NULL, pev ); 
		WRITE_BYTE(health);	
	MESSAGE_END();		
}

/*
 * harSens speed thingie
*/
int CBasePlayer::GetMaxSpeed( void )
{	//no slowing down/speeding up, when riding a beam
	if (pev->movetype == MOVETYPE_RIDEBEAM)
	{	if(m_fBlock)
		{
			//some old code... bs moving at normal flight speed max
			return m_iMaxSpeed;
		}
		else
		{
			return m_iMaxSpeed * m_flSlowDown;
		}
	}
	else
	{	if(!m_Swoop.IsSwooping() && !m_Swoop.IsDashing())
			return ( m_fTurbo ? m_iMaxSpeed * TURBO_SPEED_MULTIPLIER: m_iMaxSpeed) * (m_fExhausted ? 0.5 : 1) *m_flSlowDown;
		else
		{	if(m_Swoop.GetSwoopSpeedStart() > m_Swoop.GetSwoopSpeedEnd())
				return m_Swoop.GetSwoopSpeedStart();
			return m_Swoop.GetSwoopSpeedEnd();
		}
	}
}

/*
* harSens: Get powerlevel
*/
int CBasePlayer::GetPowerLevel( void )
{	// Edited by Pcjoe, charged turbo requires custom multiplier
	//	return (m_fTurbo ? TURBO_PL_MULTIPLIER : 1) * m_iPowerLevel;
	return m_iPowerLevel * m_ChargedTurbo.getTurboMultiplier();
}

/*
* Pcjoe: Get Aura Direction
*/
int CBasePlayer::GetAuraDirection( void )
{/*	float flSpeed = pev->velocity.Length2D();
	if (flSpeed>GetMaxSpeed()*0.1)
	{	m_pAura->pev->body = 1;
	}
	else
	{	m_pAura->pev->body = 0;
	}*/

	// Speed of the player
	float flSpeed = pev->velocity.Length2D();

	// The Buttons, saved here to make code shorter + easier to read...
	int iLeft = pev->button & IN_LEFT || pev->button & IN_MOVELEFT, iRight = pev->button & IN_RIGHT || pev->button & IN_MOVERIGHT,
		iFront = pev->button & IN_FORWARD, iBack = pev->button & IN_BACK;

	// If flying...
	if(pev->flDuckTime)
	{	return UP;
	}
	else if(m_fFlying)
	{	// If your moving side to side in flight, dont tip the aura
		if( (iLeft || iRight) && !(iFront || iBack) )
		{	return UP;
		}
		else if((iFront || iBack) && m_flSlowDown)
		{	return DOWN;
		}
		else
		{	return UP;
		}
	}
	// Swooping
	else if(m_Swoop.m_fSwoop)
	{	return DOWN;
	}
	// On ground
	else if ( pev->flags & FL_ONGROUND )
	{	// If your ducking, automatically point it down
		if(pev->button & IN_DUCK)
		{	return UP;
		}
		// If your moving side to side, dont tip the aura
		else if( (iLeft || iRight) && !(iFront || iBack) )
		{	return UP;
		}
		// Moving? Point it down, if not, point it up
	/*	else if(flSpeed > GetMaxSpeed()*0.45)
		{	return DOWN;
		}*/
		// Moving front/back
		else if((iFront || iBack) && m_flSlowDown)
		{	return DOWN;
		}
		else
		{	return UP;
		}
	}
	// If the player is in water
	else if(pev->waterlevel > 1)
	{
		if (flSpeed > GetMaxSpeed()/1.6)
		{	return DOWN;
		}
		else
		{	return UP;
		}

	}
	// In the air, falling up/down
	else
	{	if(pev->velocity.z >= 0)
		{	return DOWN;
		}
		else
		{	return UP;
		}
	}

	return UP;
}

/*
* Pcjoe: Set sub model
*/
void CBasePlayer::SetBodyPart( float flTime, int iSubModel )
{
	m_flSubModelDelay = flTime;
	m_iNextSubModel = iSubModel;
}

/*
* Pcjoe: Check on sub model status
*/
void CBasePlayer::CheckSubModelStatus( void )
{
	// See if its time to change sub models
	if(m_flSubModelDelay && m_flSubModelDelay <= gpGlobals->time)
	{	
		m_iBody = m_iNextSubModel;
		m_flSubModelDelay = 0;
		m_iNextSubModel = 0;
	}

	// Hide sword body part if we are doing some special action if we are doing some type of special action
	if(m_fSword && (m_fPowerUp || m_fBlock || m_fStrangled || m_fBecomeCandy || m_fAscending))
	{
		pev->body = 0;
	}
	else if(pev->body != m_iBody)
	{
		pev->body = m_iBody;
	}
}

/*
* Pcjoe: Add client afterfx
*/
void CBasePlayer::AddClientAfterFX( void )
{	MESSAGE_BEGIN( MSG_PVS, gmsgAfterFX, pev->origin);
		WRITE_BYTE(entindex());
		WRITE_COORD(pev->origin.x);
		WRITE_COORD(pev->origin.y);
		WRITE_COORD(pev->origin.z);
	MESSAGE_END();
}

void CBasePlayer::GetWallJumpAnim( char *pPrefix, Vector vecNormal, char *pReturn )
{	strcpy(pReturn,pPrefix);
	
	UTIL_MakeVectors(pev->angles);
	Vector vecFront = gpGlobals->v_forward;
	Vector vecBack = vecFront * -1;
	Vector vecRight = gpGlobals->v_right;
	Vector vecLeft = vecRight * -1;

	// Make all Z's 0, more accurate this way
	vecFront.z = vecBack.z = vecRight.z = vecLeft.z = vecNormal.z = 0;
	vecFront = vecFront.Normalize();
	vecBack = vecBack.Normalize();
	vecRight = vecRight.Normalize();
	vecLeft = vecLeft.Normalize();
	vecNormal = vecNormal.Normalize();

	// Are we being blown frontwards?
	if((vecFront - vecNormal).Length() <= 0.80)
	{	strcat(pReturn,"back");
	}
	else if((vecRight - vecNormal).Length() <= 0.80)
	{	strcat(pReturn,"left");
	}
	else if((vecLeft - vecNormal).Length() <= 0.80)
	{	strcat(pReturn,"right");
	}
	else
	{	strcat(pReturn,"forward");
	}
}

void CBasePlayer::GetWallJumpAnim( char *pAnim, char *pReturn )
{	if(!strcmp(pAnim, "grabwall_forward"))
	{	strcpy(pReturn,"walljump_forward");
	}
	else if(!strcmp(pAnim, "grabwall_left"))
	{	strcpy(pReturn,"walljump_left");
	}
	else if(!strcmp(pAnim, "grabwall_right"))
	{	strcpy(pReturn,"walljump_right");
	}
	else
	{	strcpy(pReturn,"walljump_back");
	}
}

/*
* Pcjoe: Check Wall Jump
*/
void CBasePlayer::CheckWallJump( void )
{	if(((pev->movetype == MOVETYPE_WALK) || 
		(pev->movetype == MOVETYPE_PLAYERFLY)) && pev->iuser3)
	{	// Dont walljump if we're being thrown
		if(pev->iuser3 && m_Melee.m_fThrown)
		{	pev->iuser3 = 0;
			return;
		}

		if(!m_fInJump)
		{	m_fInJump = TRUE;
			EnableWallJump(pev->vuser4);
		}

		if(m_fInJump && pev->iuser3 == 0)
		{	m_fInJump = FALSE;
			
			if(m_fWallJump)
			{	DisableWallJump();
			}
		}
	}
	else
	{	if(m_fInJump)
		{	m_fInJump = FALSE;
		}
		if(m_fWallJump)
		{	DisableWallJump();
		}
	}
}

/*
* Enable Wall Jump
*/
void CBasePlayer::EnableWallJump( vec3_t vecNormal )
{	// Dont allow walljump during special events
	if(m_fStrangled || m_fBecomeCandy || m_fBecomeCandy || m_fCharging || m_fPowerUp || 
		m_fBlock || m_fHoldDisc || m_fAscending || m_fMelee || m_fShield || 
		!IsAlive() || m_fControl || m_fPowerStruggling)
	{	float flSlowdown = m_flSlowDown;
		ResetWallJumpVars();
		m_flSlowDown = flSlowdown;
		return;
	}

	// Disable flight if we do a flying walljump
	if(m_fFlying)
	{	StopFly();
	}
	// Set movetypes/varibles
	UTIL_MakeVectors(pev->angles);
	m_fWallJump = TRUE;
	m_fMelee = TRUE;
	m_flSlowDown = 0;
	m_Melee.m_vecWallStickNormal = gpGlobals->v_forward;
	m_Melee.m_flStartWallStick = gpGlobals->time;

	// Reset Swoop Direction(s)
	m_Swoop.ResetAllDT();
	// Reset Animations
	m_Melee.RemoveAllAnims();
	
	char szAnim[32];
	GetWallJumpAnim("grabwall_",vecNormal, szAnim);
	vec3_t vecAngles = UTIL_VecToAngles(vecNormal);

	// Set player angle
	if(!strcmp(szAnim, "grabwall_forward"))
	{	vecAngles.y += 180;
		if(vecAngles.y > 180)
			vecAngles.y -= 360;
		vecAngles.x = -vecAngles.x;
	}
	else if(!strcmp(szAnim, "grabwall_left"))
	{	vecAngles.y += 90;
		if(vecAngles.y > 180)
			vecAngles.y -= 360;
	}
	else if(!strcmp(szAnim, "grabwall_right"))
	{	vecAngles.y -= 90;
		if(vecAngles.y < -180)
			vecAngles.y += 360;
	}

	// Add anim
	vecAngles.x = -vecAngles.x;
	UTIL_MakeVectors(vecAngles);
	m_Melee.AddAnimationAFix(gpGlobals->v_forward, true, gpGlobals->time, szAnim);
}

/*
* Disable Wall Jump
*/
void CBasePlayer::DisableWallJump( void )
{	// Set animation
	if(m_Melee.CanPlayAnimation())
	{	char szAnim[64];
		GetWallJumpAnim(m_Melee.GetCurrentAnim()->szAnim[0], szAnim);
		m_Melee.SetAnimPriority( ANIM_PRIORITY_LOW, m_Melee.AddAnimationAFix(m_Melee.m_vecWallStickNormal, false, gpGlobals->time, szAnim));
	}
	// Emit Sound
	EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/walljumps.wav", 1, ATTN_NORM);

	// HACK HACK: Set a small delay for weapon fire
	if(m_pActiveItem)
	{	CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)m_pActiveItem->GetWeaponPtr();
		if(pWeapon)
		{	pWeapon->m_flNextPrimaryAttack = pWeapon->m_flNextSecondaryAttack = gpGlobals->time + 0.2;
		}
	}

	// Reset values
	ResetWallJumpVars();
}


/*
* Remove Wall Jump ( Disable without intentions of jumping off the wall )
*/
void CBasePlayer::RemoveWallJump( void )
{	// Unfix model + Delete anims
	UTIL_Model_RemoveAll(entindex());
	m_Melee.RemoveAnim(m_Melee.GetCurrentAnim());
	// Reset values
	ResetWallJumpVars();
}

/*
* Reset Walljump varibles
*/
void CBasePlayer::ResetWallJumpVars( void )
{	m_Melee.m_vecWallStickNormal = Vector(0,0,0);
	m_Melee.m_flStartWallStick = 0;
	m_fWallJump = FALSE;
	m_fMelee = FALSE;
	m_flSlowDown = 1.0;
	pev->iuser3 = 0;
	pev->vuser4 = Vector(0,0,0);
	// Reset swoop data
	m_Swoop.ResetAllDT();
	m_Swoop.AddAllToNullKeyset();
}

/*
* Pcjoe: Stop Swoop
*/

void CBasePlayer::StopSwoop( void )
{	m_Swoop.StopSwoop();
}

/*
* Pcjoe: Can Melee
*/
BOOL CBasePlayer::CanMelee( CBasePlayer *pOther )
{	if(pOther->m_Melee.m_eThrowStatus == THROW_LAY || pOther->m_Melee.m_eThrowStatus == THROW_RECOVER ||
	   pOther->m_Melee.m_eThrowStatus == THROW_WALLSTICK || pOther->m_Melee.m_eThrowStatus == THROW_LANDRECOVER)
	{	return false;
	}

	// Can we attack?
	if(pOther->m_fStrangled || pOther->m_fPowerStruggling || pOther->m_fBlockStruggling || pOther->m_fBlockStruggleAttacker || pOther->m_fBecomeCandy ||
		pOther->m_fAscending ||	pOther->m_fShield || pOther->m_fSpawnInvulnerable || !pOther->IsAlive() || pOther->m_Melee.InAdvMeleeBattle() ||
		pOther->m_Melee.m_flLastRecoverTime > gpGlobals->time - nomeleehittime.value)
	{	return false;
	}

	// Can the player take dmg?
	if(!g_pGameRules->FPlayerCanTakeDamage( this, pOther ))
	{	return false;
	}

	return true;
}

// Added by Rick
BOOL CBasePlayer::CanMelee( CBuddy *pOther )
{
	if(pOther->m_Toss.m_eThrowStatus == THROW_LAY || pOther->m_Toss.m_eThrowStatus == THROW_RECOVER ||
	   pOther->m_Toss.m_eThrowStatus == THROW_WALLSTICK || pOther->m_Toss.m_eThrowStatus == THROW_LANDRECOVER)
	{	return false;
	}

	// Can we attack?
	if(/*pOther->m_fPowerStruggling || pOther->m_fBlockStruggling || pOther->m_fBlockStruggleAttacker ||*/ pOther->m_bBecomeCandy ||/*
		pOther->m_fAscending ||	pOther->m_fShield || pOther->m_fSpawnInvulnerable || !pOther->IsAlive() || pOther->m_Melee.InAdvMeleeBattle() ||*/
		pOther->m_Melee.m_fLastRecoverTime > gpGlobals->time - nomeleehittime.value)
	{	return false;
	}

	// Can the player take dmg?
	if(!g_pGameRules->FPlayerCanTakeDamage( this, pOther ))
	{	return false;
	}

	return true;
}

/*
* Pcjoe: Start Swoop
*/
void CBasePlayer::Swoop( void )
{	if(m_pActiveItem && (m_pActiveItem->m_iId == WEAPON_MELEE || m_pActiveItem->m_iId == WEAPON_SWORD))
	{	// Simple Melee
		if(m_Melee.m_fSimpleMelee)
		{
			CBasePlayer *pOther = m_Melee.GetEnemyPrepunch(NULL);
			if(pOther && ((pev->button & IN_ATTACK2) ? CanMelee(pOther) : CanMelee(pOther) && !pOther->m_Melee.m_fThrown ))
			{	// Save Varibles
				float flSwoopTime, flOtherSwoopTime;
				int iDirection;
				Vector vecSwoop;
				BOOL fHeadon = FALSE;

				flSwoopTime = m_Swoop.GetSwoopTime();
				vecSwoop = m_Swoop.GetCurrentDirection();
				iDirection = m_Swoop.m_iSwoopDirection;

				// Disable Swoop
				StopSwoop();

				if((pOther->m_Melee.GetEnemyPrepunch(this) == this) && pOther->m_Swoop.m_fSwoop)
				{	// You havnt swooped long enough to melee struggle
					if((flSwoopTime <= melee_swoop_minstrugtime.value) && !m_Swoop.m_fChainSwoop)
					{	if((pOther->m_Swoop.GetSwoopTime() > flSwoopTime) && !pOther->m_Swoop.m_fChainSwoop)
						{	pOther->Swoop();
							return;
						}
					}
					// Other player swooped long enough to melee struggle
					else if((pOther->m_Swoop.GetSwoopTime() > melee_swoop_minstrugtime.value) && !pOther->m_Swoop.m_fChainSwoop)
					{	fHeadon = TRUE;
					}
				}
				// Melee Struggle
				if(fHeadon)
				{	flOtherSwoopTime = pOther->m_Swoop.GetSwoopTime();
					// Disable Swoop
					pOther->StopSwoop();

					// Knockback - Knockback
					m_Melee.BlowbackStruggle( vecSwoop, flSwoopTime, flOtherSwoopTime, pOther );

					// Struggle text
					m_Melee.MeleeText( MELEETXT_HEADON, 0 );
					m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
					pOther->m_Melee.MeleeText( MELEETXT_HEADON, 0 );
					pOther->m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );

				}
				// Regular hit
				else if(pev->button & IN_ATTACK2)
				{	if(UseKi(BLOW_KICK_KI_COST) && (pOther->m_Melee.m_iConsecutiveHits < CONSECUTIVE_MELEEHITS))
					{	m_Melee.SimpleMeleePowerhit( pOther, vecSwoop, iDirection );
					}
				}
			}
			// Added by Rick: let us be able to hit buddies aswell
			else
			{
				CBuddy *pBuddy = m_Melee.GetBuddyEnemyPrepunch(NULL);
				if(pBuddy && ((pev->button & IN_ATTACK2) ? CanMelee(pBuddy) : CanMelee(pBuddy) && !pBuddy->m_bThrown))
				{
					// Save Varibles
					float flSwoopTime, flOtherSwoopTime;
					int iDirection;
					Vector vecSwoop;
					BOOL fHeadon = FALSE;

					flSwoopTime = m_Swoop.GetSwoopTime();
					vecSwoop = m_Swoop.GetCurrentDirection();
					iDirection = m_Swoop.m_iSwoopDirection;

					// Disable Swoop
					StopSwoop();

					if((pBuddy->m_Melee.GetNearestPlayerToMelee(this) == this) && pBuddy->m_Swoop.bActive)
					{	// You havnt swooped long enough to melee struggle
						if((flSwoopTime <= melee_swoop_minstrugtime.value) && !m_Swoop.m_fChainSwoop)
						{
							if((pBuddy->m_Swoop.GetSwoopTime() > flSwoopTime) && !pBuddy->m_Swoop.bChainSwoop)
							{
								pBuddy->m_Melee.SimpleMeleePowerhit( this, vecSwoop, iDirection );
								return;
							}
						}
						// Other player swooped long enough to melee struggle
						else if((pBuddy->m_Swoop.GetSwoopTime() > melee_swoop_minstrugtime.value) && !pOther->m_Swoop.m_fChainSwoop)
						{	fHeadon = TRUE;
						}
					}
					// Melee Struggle
					if(fHeadon)
					{	flOtherSwoopTime = pBuddy->m_Swoop.GetSwoopTime();
						// Disable Swoop
						pBuddy->StopSwoop();

						// Knockback - Knockback
						pBuddy->m_Melee.HandleHeadOn(this);//BlowbackStruggle( vecSwoop, flSwoopTime, flOtherSwoopTime, pBuddy );

						// Struggle text
						m_Melee.MeleeText( MELEETXT_HEADON, 0 );
						m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
					}
					// Regular hit
					else if(pev->button & IN_ATTACK2)
					{
						if(UseKi(BLOW_KICK_KI_COST) && (pBuddy->m_Melee.m_iConsecutiveHits < CONSECUTIVE_MELEEHITS))
						{
							m_Melee.SimpleMeleePowerhit( pBuddy, vecSwoop, iDirection );
						}
					}
				}
			}
		}
		// Advanced Melee
		else
		{
			CBasePlayer *pOther = m_Melee.GetEnemyPrepunch(NULL);
			if(pOther && ((pev->button & IN_ATTACK2) ? CanMelee(pOther) : CanMelee(pOther) && !pOther->m_Melee.m_fThrown ))
			{	// Save Varibles
				float flSwoopTime, flOtherSwoopTime;
				int iDirection;
				Vector vecSwoop;
				BOOL fHeadon = FALSE;

				flSwoopTime = m_Swoop.GetSwoopTime();
				vecSwoop = m_Swoop.GetCurrentDirection();
				iDirection = m_Swoop.m_iSwoopDirection;

				// Disable Swoop
				StopSwoop();

				// Check for struggle
				if((pOther->m_Melee.GetEnemyPrepunch(this) == this) && pOther->m_Swoop.m_fSwoop && pOther->m_Swoop.m_iSwoopDirection != BACK)
				{	// You havnt swooped long enough to melee struggle
					if((flSwoopTime <= melee_swoop_minstrugtime.value) && !m_Swoop.m_fChainSwoop)
					{	if((pOther->m_Swoop.GetSwoopTime() > flSwoopTime) || pOther->m_Swoop.m_fChainSwoop)
						{	pOther->Swoop();
							return;
						}
					}
					// Other player swooped long enough to melee struggle
					else if((pOther->m_Swoop.GetSwoopTime() > melee_swoop_minstrugtime.value) || pOther->m_Swoop.m_fChainSwoop)
					{	fHeadon = TRUE;
					}
				}
				// Melee Struggle
				if(fHeadon)
				{	flOtherSwoopTime = pOther->m_Swoop.GetSwoopTime();
					// Disable Swoop
					pOther->StopSwoop();

					// Prepunch - Prepunch
					if(!(pOther->pev->button & IN_ATTACK2) && !(pev->button & IN_ATTACK2))
					{	// Init Melee
						m_Melee.InitMelee( pOther );

						// Start Struggle
						m_Melee.SetMode( STRUGGLE_ATTACK );
					}
					// Prepunch - Knockback
					else if(!(pOther->pev->button & IN_ATTACK2) && (pev->button & IN_ATTACK2))
					{	// Init Melee
						pOther->m_Melee.InitMelee( this );

						// Start Struggle
						pOther->m_Melee.SetMode( KNOCKPRE_STRUGGLE_ATTACK );
					}
					// Knockback - Prepunch
					else if((pOther->pev->button & IN_ATTACK2) && !(pev->button & IN_ATTACK2))
					{	// Init Melee
						m_Melee.InitMelee( pOther );

						// Start Struggle
						m_Melee.SetMode( KNOCKPRE_STRUGGLE_ATTACK );
					}
					// Knockback - Knockback
					else
					{	m_Melee.BlowbackStruggle( vecSwoop, flSwoopTime, flOtherSwoopTime, pOther );

						// Struggle text
						m_Melee.MeleeText( MELEETXT_HEADON, 0 );
						m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
						pOther->m_Melee.MeleeText( MELEETXT_HEADON, 0 );
						pOther->m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
					}
				}
				// Regular hit
				else if(iDirection != BACK)
				{	if(!(pev->button & IN_ATTACK2) && (pOther->pev->movetype != MOVETYPE_RIDEBEAM))
					{	// Initialize melee
						m_Melee.InitMelee( pOther );

						// Set prepunch dir
						m_Melee.m_vecPrepunchDir = vecSwoop;

						// Start prepunches
						m_Melee.SetMode( PREPUNCH_ATTACK );
					}
					// Super punch
					else if((pOther->m_Melee.m_iConsecutiveHits < CONSECUTIVE_MELEEHITS) &&
							(pev->button & IN_ATTACK2) && UseKi(BLOW_KICK_KI_COST))
					{	m_Melee.Powerhit( pOther, vecSwoop, iDirection );
					}
				}
			}
			// Added by Rick: check for buddies aswell
			else
			{	
				CBuddy *pBuddy = m_Melee.GetBuddyEnemyPrepunch(NULL);
				if(pBuddy && ((pev->button & IN_ATTACK2) ? CanMelee(pBuddy) : CanMelee(pBuddy) && !pBuddy->m_bThrown ))
				{	
					// Save Varibles
					float flSwoopTime, flOtherSwoopTime;
					int iDirection;
					Vector vecSwoop;
					BOOL fHeadon = FALSE;

					flSwoopTime = m_Swoop.GetSwoopTime();
					vecSwoop = m_Swoop.GetCurrentDirection();
					iDirection = m_Swoop.m_iSwoopDirection;

					// Disable Swoop
					StopSwoop();

					// Check for struggle
					if((pBuddy->m_Melee.GetNearestPlayerToMelee(this) == this) && pBuddy->m_Swoop.bActive && pBuddy->m_Swoop.iSwoopDir != BACK)
					{	// You havnt swooped long enough to melee struggle
						if((flSwoopTime <= melee_swoop_minstrugtime.value) && !m_Swoop.m_fChainSwoop)
						{	if((pBuddy->m_Swoop.GetSwoopTime() > flSwoopTime) || pBuddy->m_Swoop.bChainSwoop)
							{	pBuddy->m_Melee.SimpleMeleePowerhit( pBuddy, vecSwoop, iDirection );
								return;
							}
						}
						// Other player swooped long enough to melee struggle
						else if((pBuddy->m_Swoop.GetSwoopTime() > melee_swoop_minstrugtime.value) || pBuddy->m_Swoop.bChainSwoop)
						{	fHeadon = (pev->button & IN_ATTACK2);
						}
					}
					// Melee Struggle
					if(fHeadon)
					{	flOtherSwoopTime = pBuddy->m_Swoop.GetSwoopTime();
						// Disable Swoop
						pBuddy->StopSwoop();

						// Knockback - Knockback
						pBuddy->m_Melee.HandleHeadOn(this);//m_Melee.BlowbackStruggle( vecSwoop, flSwoopTime, flOtherSwoopTime, pOther );

						// Struggle text
						m_Melee.MeleeText( MELEETXT_HEADON, 0 );
						m_Melee.MeleeText( MELEETXT_KNOCKBACK, 0 );
					}
					// Regular hit
					else if(iDirection != BACK)
					{	/*if(!(pev->button & IN_ATTACK2) && (pOther->pev->movetype != MOVETYPE_RIDEBEAM))
						{	// Initialize melee
							m_Melee.InitMelee( pOther );

							// Set prepunch dir
							m_Melee.m_vecPrepunchDir = vecSwoop;

							// Start prepunches
							m_Melee.SetMode( PREPUNCH_ATTACK );
						}
						// Super punch
						else */
						if((pBuddy->m_Melee.m_iConsecutiveHits < CONSECUTIVE_MELEEHITS) &&
								(pev->button & IN_ATTACK2) && UseKi(BLOW_KICK_KI_COST))
						{	m_Melee.Powerhit( pBuddy, vecSwoop, iDirection );
						}
					}
				}
			}	
		}
	}
}

// Pcjoe: End of add

// Added by Rick

// Draw the charge bar
void CBasePlayer::DrawChargeBar(int iChargePercent)
{
	m_iChargePercent = iChargePercent; // Store the charge percent for this player

	MESSAGE_BEGIN( MSG_ONE, gmsgCharge, NULL, pev ); 
		WRITE_BYTE( iChargePercent );	//amount charged in %
	MESSAGE_END();
}

void CBasePlayer::UpdateOldPositions()
{
	m_flOldPosUpdateDelay = gpGlobals->time + 0.2;
		
	Vector v_src = pev->origin;
	Vector v_old = m_OldPositions[0].Pos;
	float Dist = (v_src - v_old).Length();

	// Dist between current and last stored position is high enough?
	if (Dist > MIN_NEW_POSITION_DIST)
	{
		for (short j=(MAX_OLD_POSITIONS-1);j>0;j--)
			m_OldPositions[j] = m_OldPositions[j-1];
			  
		m_OldPositions[0].Pos = v_src;
		m_OldPositions[0].flCreateTime = gpGlobals->time;
	}
}

// End add by Rick

// Added by DragonDude
void CBasePlayer::UpdateSenzuStats(CBasePlayer* pKiller)
{
	if(!pKiller)
		return;

	//if we killed ourselves, award nothing
	if(pKiller == this)
        return;

	//send HUD messages to the killer and victim if necessary: fill levels based on 10%?
}
// End DragonDude add

// TRUE if the player is attached to a ladder
BOOL CBasePlayer::IsOnLadder( void )
{ 
	return ( pev->movetype == MOVETYPE_FLY );
}

void CBasePlayer::PlayerDeathThink(void)
{
	float flForward;

	if (FBitSet(pev->flags, FL_ONGROUND))
	{
		flForward = pev->velocity.Length() - 20;
		if (flForward <= 0)
			pev->velocity = g_vecZero;
		else    
			pev->velocity = flForward * pev->velocity.Normalize();
	}

	/* modified by harSens
	if ( HasWeapons() )
	*/
	if ( HasWeapons() || m_iSensuBeans>0)
	{
		// we drop the guns here because weapons that have an area effect and can kill their user
		// will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the
		// player class sometimes is freed. It's safer to manipulate the weapons once we know
		// we aren't calling into any of their code anymore through the player pointer.
		PackDeadPlayerItems();
	}

	// Added by Pcjoe, setting gravity + friction back to normal and disabing player key movement
	if(m_flSlowDown)
	{	pev->gravity		= 1.0;
		pev->friction		= 1.0;
		m_flSlowDown		= 0;
	}


	// Edited by Pcjoe, animate death until respawn
	if (pev->modelindex/* && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)*/)
	{
		// Pcjoe: Set Animation if we hit the ground
		if(m_Melee.CanPlayAnimation())
		{	// Player must be viewable and hit the ground
			if(FBitSet(pev->flags, FL_ONGROUND) && !(pev->effects & EF_NODRAW))
			{	plrmelee_anim_s *pAnim = m_Melee.GetCurrentAnim();
				if(pAnim)
				{	// HACK HACK: Reset owner if deleted
					if(!m_Melee.GetAttacker())
					{	m_Melee.SetAttacker(this);
					}
					if(!strcmp(pAnim->szAnim[pAnim->iCurrentAnim], "die_fall_up"))
					{	m_Melee.AddAnimation(true, gpGlobals->time, 1, "die_fall_up_hit");
						// Emit Sound
						EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/deathfall.wav", 1, ATTN_NORM);
					}
					else if(!strcmp(pAnim->szAnim[pAnim->iCurrentAnim], "die_fall_down"))
					{	m_Melee.AddAnimation(true, gpGlobals->time, 1, "die_fall_down_hit");
						// Emit Sound
						EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/deathfall.wav", 1, ATTN_NORM);
					}
				}
			}
		}

		PlayAnimation();
		StudioFrameAdvance( );

		m_iRespawnFrames++;				// Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands
		if ( m_iRespawnFrames < 120 )   // Animations should be no longer than this
			return;
	}

	// once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore
	// this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn
	if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) )
		pev->movetype = MOVETYPE_NONE;

	if (pev->deadflag == DEAD_DYING)
		pev->deadflag = DEAD_DEAD;
	
	/*Removed by Pcjoe, animate death until respawn
	StopAnimation();

	pev->effects |= EF_NOINTERP;
	pev->framerate = 0.0;*/

	//added by harSens: fade player away
	if (pev->renderamt > 0)
	{	pev->renderamt--;
	}
	BOOL fAnyButtonDown = (pev->button & ~IN_SCORE );
	
	// wait for all buttons released
	if (pev->deadflag == DEAD_DEAD)
	{
		if (fAnyButtonDown)
			return;

		if ( g_pGameRules->FPlayerCanRespawn( this ) )
		{
			m_fDeadTime = gpGlobals->time;
			pev->deadflag = DEAD_RESPAWNABLE;
		}
		
		return;
	}

// if the player has been dead for one second longer than allowed by forcerespawn, 
// forcerespawn isn't on. Send the player off to an intermission camera until they 
// choose to respawn.
	/*modified by harSens: longer fade out :)
	if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) )
	*/
	if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 12) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) )
	{
		// go to dead camera. 
		StartDeathCam();
	}
	
// wait for any button down,  or mp_forcerespawn is set and the respawn time is up
	if (!fAnyButtonDown 
		&& !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + 5))) )
		return;

	pev->button = 0;
	m_iRespawnFrames = 0;

	//ALERT(at_console, "Respawn\n");
	/*modified by harSens: never copy bodies

	respawn(pev, !(m_afPhysicsFlags & PFLAG_OBSERVER) );// don't copy a corpse if we're in deathcam.
	*/
	pev->rendermode = kRenderNormal;
	respawn(pev, false );
	pev->nextthink = -1;
}

//=========================================================
// StartDeathCam - find an intermission spot and send the
// player off into observer mode
//=========================================================
void CBasePlayer::StartDeathCam( void )
{
	edict_t *pSpot, *pNewSpot;
	int iRand;

	if ( pev->view_ofs == g_vecZero )
	{
		// don't accept subsequent attempts to StartDeathCam()
		return;
	}

	pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission");	

	if ( !FNullEnt( pSpot ) )
	{
		// at least one intermission spot in the world.
		iRand = RANDOM_LONG( 0, 3 );

		while ( iRand > 0 )
		{
			pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission");
			
			if ( pNewSpot )
			{
				pSpot = pNewSpot;
			}

			iRand--;
		}

		/*removed by harSens
		CopyToBodyQue( pev );
		*/
		StartObserver( pSpot->v.origin, pSpot->v.v_angle );
	}
	else
	{
		// no intermission spot. Push them up in the air, looking down at their corpse
		TraceResult tr;
		/*removed by harSens
		CopyToBodyQue( pev );
		*/
		UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr );
		StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin  ) );
		return;
	}
}

void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle )
{
	/* removed by harSens, set in startobserving
	m_fObserverFlag = true;
	*/
	
	m_afPhysicsFlags |= PFLAG_OBSERVER;

	pev->view_ofs = g_vecZero;
	pev->angles = pev->v_angle = vecViewAngle;
	pev->fixangle = TRUE;
	pev->solid = SOLID_NOT;
	pev->takedamage = DAMAGE_NO;
	pev->movetype = MOVETYPE_NONE;
	pev->effects = EF_NODRAW;
	UTIL_SetOrigin( pev, vecPosition );
}

/**
 * Added by harSens
 */
void CBasePlayer::StartSpectator( Vector vecPosition, Vector vecViewAngle )
{
	//Can't go spectator twice. Dunno why
	if(IsSpectator())
	{
		return;
	}
	
	//HACK HACK: observer should be subset of spectator
	if (m_fObserverFlag)
	{	StopObserving();
	}
	
	// clear any clientside entities attached to this player
	MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
		WRITE_BYTE( TE_KILLPLAYERATTACHMENTS );
		WRITE_BYTE( (BYTE)entindex() );
	MESSAGE_END();
	
	// Holster weapon immediately, to allow it to cleanup
	if (m_pActiveItem)
		m_pActiveItem->Holster( );
	
	if ( m_pTank != NULL )
	{
		m_pTank->Use( this, this, USE_OFF, 0 );
		m_pTank = NULL;
	}

	// Added by Pcjoe, reset special modes if player is alive
	if(IsAlive())
	{	RemoveSpecialModes();
	}
	
	// clear out the suit message cache so we don't keep chattering
	SetSuitUpdate(NULL, FALSE, 0);
	
	// Tell Ammo Hud that the player is dead
	MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
		WRITE_BYTE(0);
		WRITE_BYTE(0XFF);
		WRITE_BYTE(0xFF);
	MESSAGE_END();
	
	// reset FOV
	m_iFOV = m_iClientFOV = 0;
	pev->fov = m_iFOV;
	MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
		WRITE_BYTE(0);
	MESSAGE_END();
	
	// Setup flags
	m_iHideHUD = (HIDEHUD_HEALTH | HIDEHUD_WEAPONS);
	m_afPhysicsFlags |= PFLAG_OBSERVER;
	pev->effects = EF_NODRAW;
	pev->view_ofs = g_vecZero;
	pev->angles = pev->v_angle = vecViewAngle;
	pev->fixangle = TRUE;
	pev->solid = SOLID_NOT;
	pev->takedamage = DAMAGE_NO;
	pev->movetype = MOVETYPE_NONE;
	pev->deadflag = DEAD_RESPAWNABLE;
	pev->health = 1;
	pev->team = 0;
	pev->playerclass = 0;
	
	//clear team name
	strcpy(m_szTeamName,"");

	// Clear out the status bar
	m_fInitHUD = TRUE;
	
	// Update Team Status
	MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
		WRITE_BYTE( ENTINDEX(edict()) );
		WRITE_STRING( "" );
	MESSAGE_END();

	//update scores
	MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
		WRITE_BYTE( entindex() );
		WRITE_SHORT( pev->frags );
		WRITE_SHORT( m_iDeaths );
		//added by harSens
		WRITE_SHORT( m_iWishes );
		/*modified by harSens
		WRITE_SHORT( 0 );
		*/		
		WRITE_SHORT( 0 );
		WRITE_SHORT( 0 );
		WRITE_SHORT(0);
	MESSAGE_END();
	
	// Remove all the player's stuff
	RemoveAllItems( FALSE );
	
	// Move them to the new position
	UTIL_SetOrigin( pev, vecPosition );

	
	
	// Find a player to watch
	m_flNextSpectatorInput = 0;
	Spectator_SetMode(OBS_CHASE_LOCKED);
	
	// Tell all clients this player is now a spectator
	MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );  
		WRITE_BYTE( ENTINDEX( edict() ) );
		WRITE_BYTE( 1 );
	MESSAGE_END();
}

// 
// PlayerUse - handles USE keypress
//
#define	PLAYER_SEARCH_RADIUS	(float)64

void CBasePlayer::PlayerUse ( void )
{
	// added by harSens
	if(m_fSpawnInvulnerable)
	{
		return;
	}

	// Was use pressed or released?
	if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
		return;

	// Hit Use on a train?
	if ( m_afButtonPressed & IN_USE )
	{
		if ( m_pTank != NULL )
		{
			// Stop controlling the tank
			// TODO: Send HUD Update
			m_pTank->Use( this, this, USE_OFF, 0 );
			m_pTank = NULL;
			return;
		}
		else
		{
			if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
			{
				m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
				m_iTrain = TRAIN_NEW|TRAIN_OFF;
				return;
			}
			else
			{	// Start controlling the train!
				CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity );

				if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) )
				{
					m_afPhysicsFlags |= PFLAG_ONTRAIN;
					m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse);
					m_iTrain |= TRAIN_NEW;
					EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM);
					return;
				}
			}
		}
	}

	CBaseEntity *pObject = NULL;
	CBaseEntity *pClosest = NULL;
	Vector		vecLOS;
	float flMaxDot = VIEW_FIELD_NARROW;
	float flDot;

	UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing
	
	while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL)
	{

		if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE))
		{
			// !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that
			// this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS
			// when player hits the use key. How many objects can be in that area, anyway? (sjb)
			vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs));
			
			// This essentially moves the origin of the target to the corner nearest the player to test to see 
			// if it's "hull" is in the view cone
			vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 );
			
			flDot = DotProduct (vecLOS , gpGlobals->v_forward);
			if (flDot > flMaxDot )
			{// only if the item is in front of the user
				pClosest = pObject;
				flMaxDot = flDot;
//				ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
			}
//			ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
		}
	}
	pObject = pClosest;

	// Found an object
	if (pObject )
	{
		//!!!UNDONE: traceline here to prevent USEing buttons through walls			
		int caps = pObject->ObjectCaps();

		if ( m_afButtonPressed & IN_USE )
			EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM);

		if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) ||
			 ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
		{
			if ( caps & FCAP_CONTINUOUS_USE )
				m_afPhysicsFlags |= PFLAG_USING;

			pObject->Use( this, this, USE_SET, 1 );
		}
		// UNDONE: Send different USE codes for ON/OFF.  Cache last ONOFF_USE object to send 'off' if you turn away
		else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) )	// BUGBUG This is an "off" use
		{
			pObject->Use( this, this, USE_SET, 0 );
		}
	}
	else
	{
		if ( m_afButtonPressed & IN_USE )
		{	//added by harSens
			if (!g_pGameRules->PlayerUses(this))
			{	
				//end harSens add
				/*removed by harSens
				EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM);
				*/
			}
	}
}
}



void CBasePlayer::Jump()
{
	Vector		vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping
	Vector		vecAdjustedVelocity;
	Vector		vecSpot;
	TraceResult	tr;
	//added by harSens
	if (m_fStrangled || m_fBecomeCandy || m_fFlying || m_fControl || m_fBlock || m_fPowerUp || m_fAscending || pev->stop_jump || m_fMelee) //don't jump while flying
		return;	
	
	if (FBitSet(pev->flags, FL_WATERJUMP))
		return;
	
	if (pev->waterlevel >= 2)
	{
		return;
	}

	// jump velocity is sqrt( height * gravity * 2)

	// If this isn't the first frame pressing the jump button, break out.
	if ( !FBitSet( m_afButtonPressed, IN_JUMP ) )
		return;         // don't pogo stick

	if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity )
	{
		return;
	}

// many features in this function use v_forward, so makevectors now.
	UTIL_MakeVectors (pev->angles);

	// ClearBits(pev->flags, FL_ONGROUND);		// don't stairwalk
	
	/*moved down by harSens
	SetAnimation( PLAYER_JUMP );
	*/

	/* modified by harSens
	if ( m_fLongJump &&
		(pev->button & IN_DUCK) &&
		( pev->flDuckTime > 0 ) &&
		pev->velocity.Length() > 50 )
	{
		SetAnimation( PLAYER_SUPERJUMP );
	}
	*/
	EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/jump.wav", 1, ATTN_NORM);
	if (pev->button & IN_DUCK)
	{	SetAnimation( PLAYER_SUPERJUMP );
		pev->fuser4 -= SUPER_JUMP_KI_COST;
	}
	else if (pev->button & IN_BACK)
	{	SetAnimation( PLAYER_BACKFLIP );
		pev->fuser4 -= JUMP_KI_COST;
	}
	else
	{	SetAnimation( PLAYER_JUMP );
		pev->fuser4 -= JUMP_KI_COST;
	}
	
	if (pev->fuser4<0)
	{	pev->fuser4 = 0;
	}

	// If you're standing on a conveyor, add it's velocity to yours (for momentum)
	entvars_t *pevGround = VARS(pev->groundentity);
	if ( pevGround && (pevGround->flags & FL_CONVEYOR) )
	{
		pev->velocity = pev->velocity + pev->basevelocity;
	}
}



// This is a glorious hack to find free space when you've crouched into some solid space
// Our crouching collisions do not work correctly for some reason and this is easier
// than fixing the problem :(
void FixPlayerCrouchStuck( edict_t *pPlayer )
{
	TraceResult trace;

	// Move up as many as 18 pixels if the player is stuck.
	for ( int i = 0; i < 18; i++ )
	{
		UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace );
		if ( trace.fStartSolid )
			pPlayer->v.origin.z ++;
		else
			break;
	}
}

/* disabled by harSens
void CBasePlayer::Duck( )
{
	if (pev->button & IN_DUCK) 
	{
		if ( m_IdealActivity != ACT_LEAP )
		{
			SetAnimation( PLAYER_WALK );
		}
	}
}
*/

//
// ID's player as such.
//
int  CBasePlayer::Classify ( void )
{
	return CLASS_PLAYER;
}


void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore )
{
	// Positive score always adds
	if ( score < 0 )
	{
		if ( !bAllowNegativeScore )
		{
			if ( pev->frags < 0 )		// Can't go more negative
				return;
			
			if ( -score > pev->frags )	// Will this go negative?
			{
				score = -pev->frags;		// Sum will be 0
			}
		}
	}

	pev->frags += score;

	MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
		WRITE_BYTE( ENTINDEX(edict()) );
		WRITE_SHORT( pev->frags );
		WRITE_SHORT( m_iDeaths );
		//added by harSens
		WRITE_SHORT( m_iWishes);
		/*modified by harSens
		WRITE_SHORT( 0 );
		*/
		WRITE_SHORT( pev->playerclass );
		WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 );
		WRITE_SHORT(m_pClass->ScoreboardName());
	MESSAGE_END();
}


void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore )
{
	int index = entindex();

	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );

		if ( pPlayer && i != index )
		{
			if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE )
			{
				pPlayer->AddPoints( score, bAllowNegativeScore );
			}
		}
	}
}

//Player ID
/* removed by harSens
void CBasePlayer::InitStatusBar()
{
	m_flStatusBarDisappearDelay = 0;
	m_SbarString1[0] = m_SbarString0[0] = 0; 
}

void CBasePlayer::UpdateStatusBar()
{
	int newSBarState[ SBAR_END ];
	char sbuf0[ SBAR_STRING_SIZE ];
	char sbuf1[ SBAR_STRING_SIZE ];

	memset( newSBarState, 0, sizeof(newSBarState) );
	strcpy( sbuf0, m_SbarString0 );
	strcpy( sbuf1, m_SbarString1 );

	// Find an ID Target
	TraceResult tr;
	UTIL_MakeVectors( pev->v_angle + pev->punchangle );
	Vector vecSrc = EyePosition();
	Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE);
	UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr);

	if (tr.flFraction != 1.0)
	{
		if ( !FNullEnt( tr.pHit ) )
		{
			CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );

			if (pEntity->Classify() == CLASS_PLAYER )
			{
				newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() );
				strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" );

				// allies and medics get to see the targets health
				if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE )
				{
					newSBarState[ SBAR_ID_TARGETHEALTH ] = 100 * (pEntity->pev->health / pEntity->pev->max_health);
					newSBarState[ SBAR_ID_TARGETARMOR ] = pEntity->pev->armorvalue; //No need to get it % based since 100 it's the max.
				}

				m_flStatusBarDisappearDelay = gpGlobals->time + 1.0;
			}
		}
		else if ( m_flStatusBarDisappearDelay > gpGlobals->time )
		{
			// hold the values for a short amount of time after viewing the object
			newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ];
			newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ];
			newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ];
		}
	}

	BOOL bForceResend = FALSE;

	if ( strcmp( sbuf0, m_SbarString0 ) )
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev );
			WRITE_BYTE( 0 );
			WRITE_STRING( sbuf0 );
		MESSAGE_END();

		strcpy( m_SbarString0, sbuf0 );

		// make sure everything's resent
		bForceResend = TRUE;
	}

	if ( strcmp( sbuf1, m_SbarString1 ) )
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev );
			WRITE_BYTE( 1 );
			WRITE_STRING( sbuf1 );
		MESSAGE_END();

		strcpy( m_SbarString1, sbuf1 );

		// make sure everything's resent
		bForceResend = TRUE;
	}

	// Check values and send if they don't match
	for (int i = 1; i < SBAR_END; i++)
	{
		if ( newSBarState[i] != m_izSBarState[i] || bForceResend )
		{
			MESSAGE_BEGIN( MSG_ONE, gmsgStatusValue, NULL, pev );
				WRITE_BYTE( i );
				WRITE_SHORT( newSBarState[i] );
			MESSAGE_END();

			m_izSBarState[i] = newSBarState[i];
		}
	}
}
*/








#define CLIMB_SHAKE_FREQUENCY	22	// how many frames in between screen shakes when climbing
#define	MAX_CLIMB_SPEED			200	// fastest vertical climbing speed possible
#define	CLIMB_SPEED_DEC			15	// climbing deceleration rate
#define	CLIMB_PUNCH_X			-7  // how far to 'punch' client X axis when climbing
#define CLIMB_PUNCH_Z			7	// how far to 'punch' client Z axis when climbing

void CBasePlayer::PreThink(void)
{
	int buttonsChanged = (m_afButtonLast ^ pev->button);	// These buttons have changed this frame
	
	// Debounced button codes for pressed/released
	// UNDONE: Do we need auto-repeat?
	m_afButtonPressed =  buttonsChanged & pev->button;		// The changed ones still down are "pressed"
	m_afButtonReleased = buttonsChanged & (~pev->button);	// The ones not down are "released"

	g_pGameRules->PlayerThink( this );

	if ( g_fGameOver )
		return;         // intermission or finale

	UTIL_MakeVectors(pev->v_angle);             // is this still used?
	
	ItemPreFrame( );
	WaterMove();
	
	// JOHN: checks if new client data (for HUD and view control) needs to be sent to the client
	UpdateClientData();
	
	CheckTimeBasedDamage();

	if(IsSpectator())
	{
		Spectator_HandleButtons();
		pev->impulse = 0;	//no impulse commands in spectator
		return;
	}
	
	// Pcjoe: Set melee status
	if((simplemelee.value == 1 && !m_Melee.m_fSimpleMelee) || (simplemelee.value == 0 && m_Melee.m_fSimpleMelee))
	{
		if(!m_fMelee)
		{	m_Melee.m_fSimpleMelee = !m_Melee.m_fSimpleMelee;
			m_Melee.Reset();
			m_Melee.SetAttacker(this);
		}
	}

	// Pcjoe: Melee!
	if(m_fMelee)
	{	// Melee Swoop Collision
	/*	if(m_Swoop.m_fSwoop)
		{	Swoop();
		}*/

		// Manage Toss
		m_Melee.ManageToss();

		/*
		* Advanced Melee
		*/
		m_Melee.ManageMelee();
	}

	// Pcjoe: WallJump
	CheckWallJump();

	// Pcjoe: Swoop
	if (!FBitSet(pev->flags, FL_SPECTATOR))
		m_Swoop.ManageSwoop();

	// Pcjoe: Check on SubModels
	CheckSubModelStatus();

	//check if we're still invulnerable
	if (m_fInvulnerable)
	{	if (gpGlobals->time > m_flInvulnerableTime)
		{	if(m_fSpawnInvulnerable)
			{
				m_fSpawnInvulnerable = false;
				pev->renderfx = kRenderFxNone;
				if (!m_fTurbo && !m_Swoop.m_fSwoop)
				{	pev->rendermode = kRenderNormal;
				}
				m_pClass->AddAllAttacks();
			}
			m_fInvulnerable = false;
		}
	}

	//check if we're candying someone
	if (m_pCandyVictim)
	{// Edited by Pcjoe
	//	if(gpGlobals->time - m_flCandyCounter > 45)
		if(gpGlobals->time - m_flCandyCounter > 10)
		{	m_pCandyVictim->ReleaseCandy();
			m_pCandyVictim = NULL;
		}
	}

	// Added by Rick: check if we're candyfying a buddy
	if (m_pBuddyCandyVictim)
	{
		if(gpGlobals->time - m_flCandyCounter > 10)
		{	m_pBuddyCandyVictim->ReleaseCandy();
			m_pBuddyCandyVictim = NULL;
		}
	}
	//end add by Rick

	// update aura trail thingie
	// Removed by Pcjoe
/*	if (m_pAura)
	{	if (m_pAura->m_fHasTrail && !pev->velocity.Length())
		{	m_pAura->m_fHasTrail = false;
		}
	}*/

	// Added by Pcjoe
	// See if its time to add weapons after transformation
	if (m_fAddWepAfterTrans)
	{
		if(!m_fControl)
		{
			// Remove + Add transformed weapons
			RemoveAllWeapons(false);
			m_pClass->AddAllAttacks();
			m_fAddWepAfterTrans = false;
		}
	}
	
	if(m_iStamina<EXHAUST_STAMINA)
	{
		if(!m_fExhausted)
		{
			m_fExhausted = true;
			m_flExhaustedTime = gpGlobals->time;
		}
	}
	else if(m_iStamina>HEALTHY_STAMINA)
	{
		m_fExhausted = false;
	}
		
	//deal with ki updates
	if (gpGlobals->time - m_flKiUpdate > KI_UPDATE_TIME)
	{	// decrease ki for transformations
		if (pev->fuser4>m_pClass->KiCost())
		{	pev->fuser4-=m_pClass->KiCost();
		}
		else
		{	// Edited by Pcjoe, dont de-transform while controlling a beam
			if(!m_fControl)
			{	
				Descend( true );
			}
		}
	
		
		int fCanChargeStamina = true;
		if(m_fExhausted && ((gpGlobals->time-m_flExhaustedTime)<EXHAUST_TIME))
		{
			fCanChargeStamina = false;
		}

		//slowly increase ki & stamina
		if( !m_fFlying && !m_fTurbo && !m_fStrangled && !m_Melee.InAdvMeleeBattle() && !m_fPowerUp)
		{	if (pev->fuser4<1000)
			{	pev->fuser4 += KI_INCREASE_RATE;
				if (pev->fuser4>1000)
				{	pev->fuser4 = 1000;
				}
			}
		}
		if( !m_fTurbo && !m_fStrangled && !m_Melee.InAdvMeleeBattle() && fCanChargeStamina)
		{	if(!(m_fPowerUp&&pev->fuser4 == 1000))
			{
				if(m_iStamina<1000)
				{
					m_iStamina += STAMINA_INCREASE_RATE;
					if(m_iStamina>1000)
					{
						m_iStamina=1000;
					}
				}
			}
		}

		//increase ki when powering up
		if( m_fPowerUp)
		{	if (pev->fuser4<1000)
			{	pev->fuser4 += POWERUP_KI_INCREASE_RATE;
				if (pev->fuser4>1000)
				{	pev->fuser4 = 1000;
				}
			}
			else
			{
				if(fCanChargeStamina)
				{
					m_iStamina += POWERUP_STAMINA_INCREASE_RATE;
					if(m_iStamina>1000)
					{
						m_iStamina=1000;
					}
				}
			}
		}
		
		
		if (m_fTurbo)
		{	// Pcjoe: Get turbo KI cost
			if(!UseKi(m_ChargedTurbo.getKIBurn()))
			{	StopTurbo();
			}
		}

		if (m_fFlying)
		{	//decrease ki
			if (!UseKi(FLY_KI_COST))
			{	StopFly();
			}
		}

		// added by Pcjoe, Melee
		if(m_fMelee)
		{	// Pcjoe: Take away from KI if swooping
			if(m_Swoop.IsSwooping())
			{//	if(!UseKi(MELEE_SWOOP_COST))
				if(!UseKi(ki_cost_swoop.value))
				{	StopSwoop();
				}
			}
			else if(m_Swoop.IsDashing())
			{//	if(!UseKi(MELEE_DASH_COST))
				if(!UseKi(ki_cost_dash.value))
				{	StopSwoop();
				}
			}
		}

		m_flKiUpdate = gpGlobals->time;	
	}

	// Pcjoe: Charged Turbo
	m_ChargedTurbo.manageChargedTurbo();

	// Added by Rick: Store previous locations
	if (m_flOldPosUpdateDelay < gpGlobals->time)
		UpdateOldPositions();

	//check if we can jump
	if (pev->fuser4 > JUMP_KI_COST)
	{	if (m_flSlowDown != 0.0)
		{	pev->stop_jump = false;
		}
	}
	else 
	{	pev->stop_jump = true;
	}

	//check if we are still blinded
	if (m_fBlinded)
	{	if (gpGlobals->time > m_flBlindedTime)
		{	m_fBlinded = false;
			pev->flags&=~FL_GODMODE;
		}
	}

	//decreases powerlevel if we are low on health
	if (pev->health<PLDROP_HEALTH)
	{	int iPowerLevel = m_iPowerLevel - m_iMaxPowerLevel*0.0001;
		if (iPowerLevel>0)
		{	SetPowerLevel(iPowerLevel);
		}
		else
		{	//no pl left, die
			if (IsAlive())
			{	int damageFlags = DMG_GENERIC;
				damageFlags |= DMG_NEVERGIB;
				entvars_t *pevWorld = VARS( INDEXENT(0) );
				TakeDamage( pevWorld, pev, 900, damageFlags );
			}
		}
	}

	//see if it's time to transform
	if (m_fAscending)
	{	if (gpGlobals->time - m_flAscendTime > 0)
		{	Ascend();
		}
	}


	//add block points when block struggling
	if(m_fBlockStruggling)
	{	
		Vector vecAngles = m_pBlockStruggler->pev->angles;
		UTIL_MakeVectors(vecAngles);
		Vector vecForward = gpGlobals->v_forward;
		if(FBitSet( pev->flags, FL_ONGROUND ))
		{
			vecForward.z = 0;
			//m_pBlockStruggler->pev->angles = UTIL_VecToAngles(vecForward);
			m_pBlockStruggler->pev->angles.x = 0;
		}		
		TraceResult tr;
		UTIL_TraceHull(pev->origin,pev->origin + vecForward * 32, dont_ignore_monsters,human_hull,ENT(m_pBlockStruggler->pev),&tr);
		if(tr.flFraction<1.0)
		{	m_pBlockStruggler->pev->velocity = Vector(0,0,0);
			pev->vuser4 = Vector(0,0,0);
			m_pBlockStruggler->m_fBlockStruggleDamage = true;
		}
		if(gpGlobals->time > m_flNextBlockStruggle)
		{	//decrease ki
			if (!UseKi(BLOCKSTRUGGLE_KI_COST))
			{	
				StopBlock();
			}	
			else
			{	if (g_pGameRules->m_iAveragePowerLevel)
				{	m_iBlockPoints += (float)GetPowerLevel()/(float)g_pGameRules->m_iAveragePowerLevel * BLOCKSTRUGGLE_POWER;
				}
				m_flNextBlockStruggle = gpGlobals->time + BLOCKSTRUGGLE_TIME;
			}
		}
	}

	//HACK HACK: find exploding attacks to block, fix for HL's crappy collision detection
	if (!m_fShield)
	{	CBaseEntity *pEntity = UTIL_FindEntityInSphere( NULL, pev->origin, 30 );
		while (pEntity!=NULL)
		{
			if (pEntity->Classify()==CLASS_EXPLODINGATTACK)
			{
				CExplodingAttack *pExp = ((CExplodingAttack*)pEntity);
				if (pExp->pev->solid!=SOLID_NOT)
				{
					pExp->Touch(this);
				}
			}
			pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, 30 );
		}	
	}
	//end harSens add

	/* removed by harSens
	if ( g_pGameRules && g_pGameRules->FAllowFlashlight() )
		m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
	else
		m_iHideHUD |= HIDEHUD_FLASHLIGHT;
	*/

	CheckSuitUpdate();

	if (pev->deadflag >= DEAD_DYING)
	{
		PlayerDeathThink();
		return;
	}

	// So the correct flags get sent to client asap.
	//
	if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
		pev->flags |= FL_ONTRAIN;
	else 
		pev->flags &= ~FL_ONTRAIN;

	/* disabled by harSens
	// Train speed control
	if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
	{
		CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity );
		float vel;
		
		if ( !pTrain )
		{
			TraceResult trainTrace;
			// Maybe this is on the other side of a level transition
			UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace );

			// HACKHACK - Just look for the func_tracktrain classname
			if ( trainTrace.flFraction != 1.0 && trainTrace.pHit )
			pTrain = CBaseEntity::Instance( trainTrace.pHit );


			if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) )
			{
				//ALERT( at_error, "In train mode with no train!\n" );
				m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
				m_iTrain = TRAIN_NEW|TRAIN_OFF;
				return;
			}
		}
		else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) )
		{
			// Turn off the train if you jump, strafe, or the train controls go dead
			m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
			m_iTrain = TRAIN_NEW|TRAIN_OFF;
			return;
		}

		pev->velocity = g_vecZero;
		vel = 0;
		if ( m_afButtonPressed & IN_FORWARD )
		{
			vel = 1;
			pTrain->Use( this, this, USE_SET, (float)vel );
		}
		else if ( m_afButtonPressed & IN_BACK )
		{
			vel = -1;
			pTrain->Use( this, this, USE_SET, (float)vel );
		}

		if (vel)
		{
			m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse);
			m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW;
		}

	} else if (m_iTrain & TRAIN_ACTIVE)
		m_iTrain = TRAIN_NEW; // turn off train
	*/

	if (pev->button & IN_JUMP)
	{
		// If on a ladder, jump off the ladder
		// else Jump
		Jump();
	}


	// If trying to duck, already ducked, or in the process of ducking
	/* disabled by harSens
	if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) )
		Duck();
	*/

	if ( !FBitSet ( pev->flags, FL_ONGROUND ) )
	{
		m_flFallVelocity = -pev->velocity.z;
	}

	// StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?

	// Clear out ladder pointer
	m_hEnemy = NULL;

	if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
	{
		pev->velocity = g_vecZero;
	}
}
/* Time based Damage works as follows: 
	1) There are several types of timebased damage:

		#define DMG_PARALYZE		(1 << 14)	// slows affected creature down
		#define DMG_NERVEGAS		(1 << 15)	// nerve toxins, very bad
		#define DMG_POISON			(1 << 16)	// blood poisioning
		#define DMG_RADIATION		(1 << 17)	// radiation exposure
		#define DMG_DROWNRECOVER	(1 << 18)	// drown recovery
		#define DMG_ACID			(1 << 19)	// toxic chemicals or acid burns
		#define DMG_SLOWBURN		(1 << 20)	// in an oven
		#define DMG_SLOWFREEZE		(1 << 21)	// in a subzero freezer

	2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter,
		per damage type. The counter is decremented every second, so the maximum time 
		an effect will last is 255/60 = 4.25 minutes.  Of course, staying within the radius
		of a damaging effect like fire, nervegas, radiation will continually reset the counter to max.

	3) Every second that a tbd counter is running, the player takes damage.  The damage
		is determined by the type of tdb.  
			Paralyze		- 1/2 movement rate, 30 second duration.
			Nervegas		- 5 points per second, 16 second duration = 80 points max dose.
			Poison			- 2 points per second, 25 second duration = 50 points max dose.
			Radiation		- 1 point per second, 50 second duration = 50 points max dose.
			Drown			- 5 points per second, 2 second duration.
			Acid/Chemical	- 5 points per second, 10 second duration = 50 points max.
			Burn			- 10 points per second, 2 second duration.
			Freeze			- 3 points per second, 10 second duration = 30 points max.

	4) Certain actions or countermeasures counteract the damaging effects of tbds:

		Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body
							- recharged by suit recharger
		Air In Lungs		- drowning damage is done to air in lungs first, then to body
							- recharged by poking head out of water
							- 10 seconds if swiming fast
		Air In SCUBA		- drowning damage is done to air in tanks first, then to body
							- 2 minutes in tanks. Need new tank once empty.
		Radiation Syringe	- Each syringe full provides protection vs one radiation dosage
		Antitoxin Syringe	- Each syringe full provides protection vs one poisoning (nervegas or poison).
		Health kit			- Immediate stop to acid/chemical, fire or freeze damage.
		Radiation Shower	- Immediate stop to radiation damage, acid/chemical or fire damage.
		
	
*/

// If player is taking time based damage, continue doing damage to player -
// this simulates the effect of being poisoned, gassed, dosed with radiation etc -
// anything that continues to do damage even after the initial contact stops.
// Update all time based damage counters, and shut off any that are done.

// The m_bitsDamageType bit MUST be set if any damage is to be taken.
// This routine will detect the initial on value of the m_bitsDamageType
// and init the appropriate counter.  Only processes damage every second.

//#define PARALYZE_DURATION	30		// number of 2 second intervals to take damage
//#define PARALYZE_DAMAGE		0.0		// damage to take each 2 second interval

//#define NERVEGAS_DURATION	16
//#define NERVEGAS_DAMAGE		5.0

//#define POISON_DURATION		25
//#define POISON_DAMAGE		2.0

//#define RADIATION_DURATION	50
//#define RADIATION_DAMAGE	1.0

//#define ACID_DURATION		10
//#define ACID_DAMAGE			5.0

//#define SLOWBURN_DURATION	2
//#define SLOWBURN_DAMAGE		1.0

//#define SLOWFREEZE_DURATION	1.0
//#define SLOWFREEZE_DAMAGE	3.0

/* */


void CBasePlayer::CheckTimeBasedDamage() 
{
	int i;
	BYTE bDuration = 0;

	static float gtbdPrev = 0.0;

	if (!(m_bitsDamageType & DMG_TIMEBASED))
		return;

	// only check for time based damage approx. every 2 seconds
	if (abs(gpGlobals->time - m_tbdPrev) < 2.0)
		return;
	
	m_tbdPrev = gpGlobals->time;

	for (i = 0; i < CDMG_TIMEBASED; i++)
	{
		// make sure bit is set for damage type
		if (m_bitsDamageType & (DMG_PARALYZE << i))
		{
			switch (i)
			{
			case itbd_Paralyze:
				// UNDONE - flag movement as half-speed
				bDuration = PARALYZE_DURATION;
				break;
			case itbd_NerveGas:
//				TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC);	
				bDuration = NERVEGAS_DURATION;
				break;
			case itbd_Poison:
				TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC);
				bDuration = POISON_DURATION;
				break;
			case itbd_Radiation:
//				TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC);
				bDuration = RADIATION_DURATION;
				break;
			case itbd_DrownRecover:
				// NOTE: this hack is actually used to RESTORE health
				// after the player has been drowning and finally takes a breath
				if (m_idrowndmg > m_idrownrestored)
				{
					int idif = min(m_idrowndmg - m_idrownrestored, 10);

					TakeHealth(idif, DMG_GENERIC);
					m_idrownrestored += idif;
				}
				bDuration = 4;	// get up to 5*10 = 50 points back
				break;
			case itbd_Acid:
//				TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC);
				bDuration = ACID_DURATION;
				break;
			case itbd_SlowBurn:
//				TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC);
				bDuration = SLOWBURN_DURATION;
				break;
			case itbd_SlowFreeze:
//				TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC);
				bDuration = SLOWFREEZE_DURATION;
				break;
			default:
				bDuration = 0;
			}

			if (m_rgbTimeBasedDamage[i])
			{
				// use up an antitoxin on poison or nervegas after a few seconds of damage					
				if (((i == itbd_NerveGas) && (m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION)) ||
					((i == itbd_Poison)   && (m_rgbTimeBasedDamage[i] < POISON_DURATION)))
				{	/* removed by harSens
					if (m_rgItems[ITEM_ANTIDOTE])
					{
						m_rgbTimeBasedDamage[i] = 0;
						m_rgItems[ITEM_ANTIDOTE]--;
						SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK);
					}
					*/
				}


				// decrement damage duration, detect when done.
				if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0)
				{
					m_rgbTimeBasedDamage[i] = 0;
					// if we're done, clear damage bits
					m_bitsDamageType &= ~(DMG_PARALYZE << i);	
				}
			}
			else
				// first time taking this damage type - init damage duration
				m_rgbTimeBasedDamage[i] = bDuration;
		}
	}
}

/*
THE POWER SUIT

The Suit provides 3 main functions: Protection, Notification and Augmentation. 
Some functions are automatic, some require power. 
The player gets the suit shortly after getting off the train in C1A0 and it stays
with him for the entire game.

Protection

	Heat/Cold
		When the player enters a hot/cold area, the heating/cooling indicator on the suit 
		will come on and the battery will drain while the player stays in the area. 
		After the battery is dead, the player starts to take damage. 
		This feature is built into the suit and is automatically engaged.
	Radiation Syringe
		This will cause the player to be immune from the effects of radiation for N seconds. Single use item.
	Anti-Toxin Syringe
		This will cure the player from being poisoned. Single use item.
	Health
		Small (1st aid kits, food, etc.)
		Large (boxes on walls)
	Armor
		The armor works using energy to create a protective field that deflects a
		percentage of damage projectile and explosive attacks. After the armor has been deployed,
		it will attempt to recharge itself to full capacity with the energy reserves from the battery.
		It takes the armor N seconds to fully charge. 

Notification (via the HUD)

x	Health
x	Ammo  
x	Automatic Health Care
		Notifies the player when automatic healing has been engaged. 
x	Geiger counter
		Classic Geiger counter sound and status bar at top of HUD 
		alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal.
x	Poison
	Armor
		Displays the current level of armor. 

Augmentation 

	Reanimation (w/adrenaline)
		Causes the player to come back to life after he has been dead for 3 seconds. 
		Will not work if player was gibbed. Single use.
	Long Jump
		Used by hitting the ??? key(s). Caused the player to further than normal.
	SCUBA	
		Used automatically after picked up and after player enters the water. 
		Works for N seconds. Single use.	
	
Things powered by the battery

	Armor		
		Uses N watts for every M units of damage.
	Heat/Cool	
		Uses N watts for every second in hot/cold area.
	Long Jump	
		Uses N watts for every jump.
	Alien Cloak	
		Uses N watts for each use. Each use lasts M seconds.
	Alien Shield	
		Augments armor. Reduces Armor drain by one half
 
*/

// if in range of radiation source, ping geiger counter

/* disabled by harSens
#define GEIGERDELAY 0.25

void CBasePlayer :: UpdateGeigerCounter( void )
{
	BYTE range;

	// delay per update ie: don't flood net with these msgs
	if (gpGlobals->time < m_flgeigerDelay)
		return;

	m_flgeigerDelay = gpGlobals->time + GEIGERDELAY;
		
	// send range to radition source to client

	range = (BYTE) (m_flgeigerRange / 4);

	if (range != m_igeigerRangePrev)
	{
		m_igeigerRangePrev = range;

		MESSAGE_BEGIN( MSG_ONE, gmsgGeigerRange, NULL, pev );
			WRITE_BYTE( range );
		MESSAGE_END();
	}

	// reset counter and semaphore
	if (!RANDOM_LONG(0,3))
		m_flgeigerRange = 1000;

}
*/
/*
================
CheckSuitUpdate

Play suit update if it's time
================
*/

#define SUITUPDATETIME	3.5
#define SUITFIRSTUPDATETIME 0.1

void CBasePlayer::CheckSuitUpdate()
{
	int i;
	int isentence = 0;
	int isearch = m_iSuitPlayNext;
	
	// Ignore suit updates if no suit
	if ( !(pev->weapons & (1<<WEAPON_SUIT)) )
		return;

	// if in range of radiation source, ping geiger counter
	/* disabled by harSensmme
	UpdateGeigerCounter();
	*/

	if ( g_pGameRules->IsMultiplayer() )
	{
		// don't bother updating HEV voice in multiplayer.
		return;
	}

	if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0)
	{
		// play a sentence off of the end of the queue
		for (i = 0; i < CSUITPLAYLIST; i++)
			{
			if (isentence = m_rgSuitPlayList[isearch])
				break;
			
			if (++isearch == CSUITPLAYLIST)
				isearch = 0;
			}

		if (isentence)
		{
			m_rgSuitPlayList[isearch] = 0;
			if (isentence > 0)
			{
				// play sentence number

				char sentence[CBSENTENCENAME_MAX+1];
				strcpy(sentence, "!");
				strcat(sentence, gszallsentencenames[isentence]);
				EMIT_SOUND_SUIT(ENT(pev), sentence);
			}
			else
			{
				// play sentence group
				EMIT_GROUPID_SUIT(ENT(pev), -isentence);
			}
		m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME;
		}
		else
			// queue is empty, don't check 
			m_flSuitUpdate = 0;
	}
}
 
// add sentence to suit playlist queue. if fgroup is true, then
// name is a sentence group (HEV_AA), otherwise name is a specific
// sentence name ie: !HEV_AA0.  If iNoRepeat is specified in
// seconds, then we won't repeat playback of this word or sentence
// for at least that number of seconds.

void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime)
{
	int i;
	int isentence;
	int iempty = -1;
	
	
	// Ignore suit updates if no suit
	if ( !(pev->weapons & (1<<WEAPON_SUIT)) )
		return;

	if ( g_pGameRules->IsMultiplayer() )
	{
		// due to static channel design, etc. We don't play HEV sounds in multiplayer right now.
		return;
	}

	// if name == NULL, then clear out the queue

	if (!name)
	{
		for (i = 0; i < CSUITPLAYLIST; i++)
			m_rgSuitPlayList[i] = 0;
		return;
	}
	// get sentence or group number
	if (!fgroup)
	{
		isentence = SENTENCEG_Lookup(name, NULL);
		if (isentence < 0)
			return;
	}
	else
		// mark group number as negative
		isentence = -SENTENCEG_GetIndex(name);

	// check norepeat list - this list lets us cancel
	// the playback of words or sentences that have already
	// been played within a certain time.

	for (i = 0; i < CSUITNOREPEAT; i++)
	{
		if (isentence == m_rgiSuitNoRepeat[i])
			{
			// this sentence or group is already in 
			// the norepeat list

			if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time)
				{
				// norepeat time has expired, clear it out
				m_rgiSuitNoRepeat[i] = 0;
				m_rgflSuitNoRepeatTime[i] = 0.0;
				iempty = i;
				break;
				}
			else
				{
				// don't play, still marked as norepeat
				return;
				}
			}
		// keep track of empty slot
		if (!m_rgiSuitNoRepeat[i])
			iempty = i;
	}

	// sentence is not in norepeat list, save if norepeat time was given

	if (iNoRepeatTime)
	{
		if (iempty < 0)
			iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over
		m_rgiSuitNoRepeat[iempty] = isentence;
		m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time;
	}

	// find empty spot in queue, or overwrite last spot
	
	m_rgSuitPlayList[m_iSuitPlayNext++] = isentence;
	if (m_iSuitPlayNext == CSUITPLAYLIST)
		m_iSuitPlayNext = 0;

	if (m_flSuitUpdate <= gpGlobals->time)
	{
		if (m_flSuitUpdate == 0)
			// play queue is empty, don't delay too long before playback
			m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME;
		else 
			m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; 
	}

}

/*
================
CheckPowerups

Check for turning off powerups

GLOBALS ASSUMED SET:  g_ulModelIndexPlayer
================
*/
	static void
CheckPowerups(entvars_t *pev)
{
	if (pev->health <= 0)
		return;

	// Removed by Pcjoe
//	pev->modelindex = g_ulModelIndexPlayer;    // don't use eyes
}


//=========================================================
// UpdatePlayerSound - updates the position of the player's
// reserved sound slot in the sound list.
//=========================================================
void CBasePlayer :: UpdatePlayerSound ( void )
{
	int iBodyVolume;
	int iVolume;
	CSound *pSound;

	pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) );

	if ( !pSound )
	{
		ALERT ( at_console, "Client lost reserved sound!\n" );
		return;
	}

	pSound->m_iType = bits_SOUND_NONE;

	// now calculate the best target volume for the sound. If the player's weapon
	// is louder than his body/movement, use the weapon volume, else, use the body volume.
	
	if ( FBitSet ( pev->flags, FL_ONGROUND ) )
	{	
		iBodyVolume = pev->velocity.Length(); 

		// clamp the noise that can be made by the body, in case a push trigger,
		// weapon recoil, or anything shoves the player abnormally fast. 
		if ( iBodyVolume > 512 )
		{
			iBodyVolume = 512;
		}
	}
	else
	{
		iBodyVolume = 0;
	}

	if ( pev->button & IN_JUMP )
	{
		iBodyVolume += 100;
	}

// convert player move speed and actions into sound audible by monsters.
	if ( m_iWeaponVolume > iBodyVolume )
	{
		m_iTargetVolume = m_iWeaponVolume;

		// OR in the bits for COMBAT sound if the weapon is being louder than the player. 
		pSound->m_iType |= bits_SOUND_COMBAT;
	}
	else
	{
		m_iTargetVolume = iBodyVolume;
	}

	// decay weapon volume over time so bits_SOUND_COMBAT stays set for a while
	m_iWeaponVolume -= 250 * gpGlobals->frametime;
	if ( m_iWeaponVolume < 0 )
	{
		iVolume = 0;
	}


	// if target volume is greater than the player sound's current volume, we paste the new volume in 
	// immediately. If target is less than the current volume, current volume is not set immediately to the
	// lower volume, rather works itself towards target volume over time. This gives monsters a much better chance
	// to hear a sound, especially if they don't listen every frame.
	iVolume = pSound->m_iVolume;

	if ( m_iTargetVolume > iVolume )
	{
		iVolume = m_iTargetVolume;
	}
	else if ( iVolume > m_iTargetVolume )
	{
		iVolume -= 250 * gpGlobals->frametime;

		if ( iVolume < m_iTargetVolume )
		{
			iVolume = 0;
		}
	}

	if ( m_fNoPlayerSound )
	{
		// debugging flag, lets players move around and shoot without monsters hearing.
		iVolume = 0;
	}

	if ( gpGlobals->time > m_flStopExtraSoundTime )
	{
		// since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two 
		// after actual emission to make sure it gets heard.
		m_iExtraSoundTypes = 0;
	}

	if ( pSound )
	{
		pSound->m_vecOrigin = pev->origin;
		pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes );
		pSound->m_iVolume = iVolume;
	}

	// keep track of virtual muzzle flash
	m_iWeaponFlash -= 256 * gpGlobals->frametime;
	if (m_iWeaponFlash < 0)
		m_iWeaponFlash = 0;

	//UTIL_MakeVectors ( pev->angles );
	//gpGlobals->v_forward.z = 0;

	// Below are a couple of useful little bits that make it easier to determine just how much noise the 
	// player is making. 
	// UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 );
	//ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume );
}

/*
* Pcjoe: Force Correct Models
*/
void CBasePlayer::ForceCorrectModels( void )
{	char szModel[128];
	strcpy(szModel,STRING( pev->model ));
	// Dont change player.mdl
	if(!stricmp(szModel, "models/player.mdl") || !stricmp(szModel, ""))
	{	return;
	}

	char szModelName[64];
	bool blCanChange = false;
	// Save model name
	sscanf(szModel,"models/player/%*s/%s.mdl",szModelName);
	// Search through all models and reset model name if needed
	for(int i = 0; i < NUM_PLR_MODELS; i++)
	{	if(!stricmp(g_szModelList[i],""))
		{	break;
		}
		if(!stricmp(g_szModelList[i],szModel))
		{	blCanChange = true;
		}
	}

	// Change models
	if(blCanChange && m_pClass)
	{	char szClassModel[64];
		strcpy(szClassModel, m_pClass->GetModelName());
		UTIL_SetPlayerModel(this, szClassModel);
	}
}

void CBasePlayer::PostThink()
{
	if ( g_fGameOver )
		goto pt_end;         // intermission or finale

	if (!IsAlive())
		goto pt_end;

	//DragonDude: get a bean if the bean-o-meter is full
	/* (disabled for now)
	if(!UTIL_IsBot(this))
		ALERT(at_console, "Senzu Percent: %f\n", this->m_flSenzuPercent);

	//check to see if we should give the player a senzu bean 
	while(m_flSenzuPercent >= 100.0f)
	{
		GiveBean(1);
		m_flSenzuPercent -= 100.0f;
	}*/
	//end DragonDude add

	// Handle Tank controlling
	if ( m_pTank != NULL )
	{ // if they've moved too far from the gun,  or selected a weapon, unuse the gun
		if ( m_pTank->OnControls( pev ) && !pev->weaponmodel )
		{  
			m_pTank->Use( this, this, USE_SET, 2 );	// try fire the gun
		}
		else
		{  // they've moved off the platform
			m_pTank->Use( this, this, USE_OFF, 0 );
			m_pTank = NULL;
		}
	}

	// Added by Pcjoe, force correct models
	ForceCorrectModels();

// do weapon stuff
	ItemPostFrame( );

// check to see if player landed hard enough to make a sound
// falling farther than half of the maximum safe distance, but not as far a max safe distance will
// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half
// of maximum safe distance will make no sound. Falling farther than max safe distance will play a 
// fallpain sound, and damage will be inflicted based on how far the player fell

	if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD )
	{
		// ALERT ( at_console, "%f\n", m_flFallVelocity );

		if (pev->watertype == CONTENT_WATER)
		{
			// Did he hit the world or a non-moving entity?
			// BUG - this happens all the time in water, especially when 
			// BUG - water has current force
			// if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 )
				// EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM);
		}
		else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED )
		{// after this point, we start doing damage
			
			float flFallDamage = g_pGameRules->FlPlayerFallDamage( this );


			// Removed by Pcjoe, no splat sounds in ESF
		/*	if ( flFallDamage > pev->health )
			{//splat
				// note: play on item channel because we play footstep landing on body channel
				EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM);
			}*/

			if ( flFallDamage > 0 )
			{
				TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); 
				pev->punchangle.x = 0;

				// Pcjoe: Emit sound
				EMIT_SOUND(ENT(pev), CHAN_ITEM, "weapons/groundhit2.wav", 1, ATTN_NORM);
			}
		}

		if ( IsAlive() )
		{	/* modified by harSens
			SetAnimation( PLAYER_WALK );
			*/
			PlayAnimation();
		}
    }

	if (FBitSet(pev->flags, FL_ONGROUND))
	{		
		if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer())
		{
			CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, m_flFallVelocity, 0.2 );
			// ALERT( at_console, "fall %f\n", m_flFallVelocity );
		}
		m_flFallVelocity = 0;
	}

	// select the proper animation for the player character	
	if ( IsAlive() )
	{	//added by harSens
		PlayAnimation();
		/*disabled by harSens
		if (!pev->velocity.x && !pev->velocity.y)
			SetAnimation( PLAYER_IDLE );
		else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND)))
			SetAnimation( PLAYER_WALK );
		else if (pev->waterlevel > 1)
			SetAnimation( PLAYER_WALK );
		*/
	}

	// Added by Pcjoe, Melee Swoop Collision
	if(m_Swoop.m_fSwoop)
	{	Swoop();
	}

	// Edited by Pcjoe: Read framerate off of player.mdl in adv melee battles, one steady framerate for melee
	if(m_Melee.InAdvMeleeBattle() && (m_Melee.m_eAdvMeleeStatus == EXE_ATTACK || m_Melee.m_eAdvMeleeStatus == EXE_DEFEND))
	{	m_Melee.MeleeFrameAdvance();
	}
	else
	{	StudioFrameAdvance( );
	}

	CheckPowerups(pev);

	UpdatePlayerSound();

	// Track button info so we can detect 'pressed' and 'released' buttons next frame
	m_afButtonLast = pev->button;

pt_end:
	//omega; fix the corpses. 
    if (pev->deadflag == DEAD_NO)
	{
        m_vecLastAngles = pev->angles;
	}
    else
	{
        pev->angles = m_vecLastAngles;
	}

#if defined( CLIENT_WEAPONS )
		// Decay timers on weapons
	// go through all of the weapons and make a list of the ones to pack
	for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ )
	{
		if ( m_rgpPlayerItems[ i ] )
		{
			CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ];

			while ( pPlayerItem )
			{
				CBasePlayerWeapon *gun;

				gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr();
				
				if ( gun && gun->UseDecrement() )
				{
					gun->m_flNextPrimaryAttack		= max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 );
					gun->m_flNextSecondaryAttack	= max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 );

					if ( gun->m_flTimeWeaponIdle != 1000 )
					{
						gun->m_flTimeWeaponIdle		= max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 );
					}

					if ( gun->pev->fuser1 != 1000 )
					{
						gun->pev->fuser1	= max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 );
					}

					// Only decrement if not flagged as NO_DECREMENT
//					if ( gun->m_flPumpTime != 1000 )
				//	{
				//		gun->m_flPumpTime	= max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 );
				//	}
					
				}

				pPlayerItem = pPlayerItem->m_pNext;
			}
		}
	}

	m_flNextAttack -= gpGlobals->frametime;
	if ( m_flNextAttack < -0.001 )
		m_flNextAttack = -0.001;
	
	if ( m_flNextAmmoBurn != 1000 )
	{
		m_flNextAmmoBurn -= gpGlobals->frametime;
		
		if ( m_flNextAmmoBurn < -0.001 )
			m_flNextAmmoBurn = -0.001;
	}

	if ( m_flAmmoStartCharge != 1000 )
	{
		m_flAmmoStartCharge -= gpGlobals->frametime;
		
		if ( m_flAmmoStartCharge < -0.001 )
			m_flAmmoStartCharge = -0.001;
	}
	

#else
	return;
#endif
}


// checks if the spot is clear of players
BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot )
{
	CBaseEntity *ent = NULL;

	if ( !pSpot->IsTriggered( pPlayer ) )
	{
		return FALSE;
	}

	while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL )
	{
		// if ent is a client, don't spawn on 'em
		if ( ent->IsPlayer() && ent != pPlayer )
			return FALSE;
	}

	return TRUE;
}


DLL_GLOBAL CBaseEntity	*g_pLastSpawn;
inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); }

/*
============
EntSelectSpawnPoint

Returns the entity to spawn at

USES AND SETS GLOBAL g_pLastSpawn
============
*/
edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer )
{
	CBaseEntity *pSpot;
	edict_t		*player;

	player = pPlayer->edict();

// choose a info_player_deathmatch point
	if (g_pGameRules->IsCoOp())
	{
		pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop");
		if ( !FNullEnt(pSpot) )
			goto ReturnSpot;
		pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start");
		if ( !FNullEnt(pSpot) ) 
			goto ReturnSpot;
	}
	//added by harSens
	if (g_pGameRules->IsTeamplay())
	{	pSpot = g_pLastSpawn;
		
		char spawn_point[255];
		CBasePlayer *cbPlayer = (CBasePlayer *)pPlayer; // Get a CBasePlayer

		// Randomize the start spot
		if (FStrEq(cbPlayer->m_szTeamName, "Good")) 
		{	strcpy(spawn_point,"info_good_start");
		}
		else if (FStrEq(cbPlayer->m_szTeamName, "Evil"))
		{	strcpy(spawn_point,"info_evil_start");
		}
		else
		{	//no team... shouldn't happen... 
			strcpy(spawn_point,"info_player_deathmatch");
		}

		for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
			pSpot = UTIL_FindEntityByClassname( pSpot, spawn_point );
		if ( FNullEnt( pSpot ) )  // skip over the null point
			pSpot = UTIL_FindEntityByClassname( pSpot, spawn_point );

		CBaseEntity *pFirstSpot = pSpot;

		do 
		{
			if ( pSpot )
			{
				// check if pSpot is valid
				if ( IsSpawnPointValid( pPlayer, pSpot ) )
				{
					if ( pSpot->pev->origin == Vector( 0, 0, 0 ) )
					{
						pSpot = UTIL_FindEntityByClassname( pSpot, spawn_point );
						continue;
					}

					// if so, go to pSpot
					goto ReturnSpot;
				}
			}
			// increment pSpot
			pSpot = UTIL_FindEntityByClassname( pSpot, spawn_point );
		} while ( pSpot != pFirstSpot ); // loop if we're not back to the start

		// we haven't found a place to spawn yet,  so kill any guy at the first spawn point and spawn there
		if ( !FNullEnt( pSpot ) )
		{
			CBaseEntity *ent = NULL;
			while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL )
			{
				// if ent is a client, kill em (unless they are ourselves)
				if ( ent->IsPlayer() && !(ent->edict() == player) )
					ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC );
			}
			goto ReturnSpot;
		}
	}
	/*modified by harSens
	else if ( g_pGameRules->IsDeathmatch() )
	*/
	if ( g_pGameRules->IsDeathmatch() )
	{
		pSpot = g_pLastSpawn;
		// Randomize the start spot
		for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
			pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
		if ( FNullEnt( pSpot ) )  // skip over the null point
			pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );

		CBaseEntity *pFirstSpot = pSpot;

		do 
		{
			if ( pSpot )
			{
				// check if pSpot is valid
				if ( IsSpawnPointValid( pPlayer, pSpot ) )
				{
					if ( pSpot->pev->origin == Vector( 0, 0, 0 ) )
					{
						pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
						continue;
					}

					// if so, go to pSpot
					goto ReturnSpot;
				}
			}
			// increment pSpot
			pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
		} while ( pSpot != pFirstSpot ); // loop if we're not back to the start

		// we haven't found a place to spawn yet,  so kill any guy at the first spawn point and spawn there
		if ( !FNullEnt( pSpot ) )
		{
			CBaseEntity *ent = NULL;
			while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL )
			{
				// if ent is a client, kill em (unless they are ourselves)
				if ( ent->IsPlayer() && !(ent->edict() == player) )
					ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC );
			}
			goto ReturnSpot;
		}
	}

	// If startspot is set, (re)spawn there.
	if ( FStringNull( gpGlobals->startspot ) || !strlen(STRING(gpGlobals->startspot)))
	{
		pSpot = UTIL_FindEntityByClassname(NULL, "info_player_start");
		if ( !FNullEnt(pSpot) )
			goto ReturnSpot;
	}
	else
	{
		pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) );
		if ( !FNullEnt(pSpot) )
			goto ReturnSpot;
	}

ReturnSpot:
	if ( FNullEnt( pSpot ) )
	{
		ALERT(at_error, "PutClientInServer: no info_player_start on level");
		return INDEXENT(0);
	}

	g_pLastSpawn = pSpot;
	return pSpot->edict();
}

void CBasePlayer::Spawn( void )
{
	pev->classname		= MAKE_STRING("player");
	pev->health			= 100;
	pev->armorvalue		= 0;
	pev->takedamage		= DAMAGE_AIM;
	pev->solid			= SOLID_SLIDEBOX;
	pev->movetype		= MOVETYPE_WALK;
	pev->max_health		= pev->health;
	pev->flags		   &= FL_PROXY;	// keep proxy flag sey by engine
	pev->flags		   |= FL_CLIENT;
	pev->air_finished	= gpGlobals->time + 12;
	pev->dmg			= 2;				// initial water damage
	pev->effects		= 0;
	pev->deadflag		= DEAD_NO;
	pev->dmg_take		= 0;
	pev->dmg_save		= 0;
	pev->friction		= 1.0;
	pev->gravity		= 1.0;
	m_bitsHUDDamage		= -1;
	m_bitsDamageType	= 0;
	m_afPhysicsFlags	= 0;
	m_fLongJump			= FALSE;// no longjump module. 

	// change this to read from a config var?
	m_eBuddyMood = buddyMimic;

	g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" );
	g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" );

	pev->fov = m_iFOV				= 0;// init field of view.
	m_iClientFOV		= -1; // make sure fov reset is sent

	m_flNextDecalTime	= 0;// let this player decal as soon as he spawns.

	/* disabled by harSens
	m_flgeigerDelay = gpGlobals->time + 2.0;	// wait a few seconds until user-defined message registrations
												// are recieved by all clients
	*/
	m_flTimeStepSound	= 0;
	m_iStepLeft = 0;
	m_flFieldOfView		= 0.5;// some monsters use this to determine whether or not the player is looking at them.

	m_bloodColor	= BLOOD_COLOR_RED;
	m_flNextAttack	= UTIL_WeaponTimeBase();
	StartSneaking();

	/* removed by harSens
	m_iFlashBattery = 99;
	*/

// dont let uninitialized value here hurt the player
	m_flFallVelocity = 0;

	//added by harSens
	m_iHideHUD &= ~(HIDEHUD_HEALTH|HIDEHUD_WEAPONS);
	if (!m_pClass)
	{	m_pClass = new CBaseClass (this);
		m_flPowerLevelMultiplier=m_pClass->GetTransFromPLMultiplier();
		//m_fRandomClass = false;
		SetPowerLevel(0);
		SetMaxPowerLevel(0);
		m_iMaxHealth = 0;
		m_iMaxSpeed = 0;
		m_fSelfKill=false;
		// Added by Pcjoe
		m_pClass->SetModel();
	}
	pev->playerclass = m_pClass->Classify();
	
	if(m_pClass->Classify()!=PC_BASE)
	{	
		m_flInvulnerableTime = gpGlobals->time + spawn_invulnerable_time.value;
		m_fInvulnerable = true;
		m_fSpawnInvulnerable = true;
		pev->renderfx = kRenderFxStrobeFaster;
		pev->renderamt = 255;
		pev->rendermode = kRenderTransTexture;		
	}
	else
	{
		m_fInvulnerable = false;
		m_fSpawnInvulnerable = false;
		pev->rendermode = kRenderNormal;
		pev->renderfx = kRenderFxNone;
	}
	m_fFlying = false;
	m_fTurbo = false;
	m_fBurning = false;
	m_fAimAnimation = false;
	m_flSlowDown = 1.0;
	m_fBlock = false;
	m_fPowerUp = false;
	m_fExhausted = false;
	m_fCharging = false;
	m_fCharging2 = false;
	m_fControl = false;
	m_fWishing = false;
	m_fPowerStruggling = false;
	m_fBlockStruggling = false;
	m_fBlockStruggleAttacker = false;
	m_fSwat = false;
	m_pCandyVictim = NULL;
	// Added by Rick
	m_pBuddyCandyVictim = NULL;
	// End add by Rick
	m_pAura = NULL;
	m_iSensuBeans = 0;
	m_iWishes = 0;
	m_fStrangled = false;
	m_pPowerStruggle = NULL;
	m_fBecomeCandy = false;
	m_fChargeNamekSB = false;

	// added by Pcjoe
	m_fAddWepAfterTrans = false;
	m_fMelee = false;
	m_flDragonBallPickup = 0;

	// Added by Rick
	m_flDragonballDrop = 0.0f;

	for(int i = 0; i < 2; i++)
	{	m_vecBlob[i] = Vector(0, 0, 0);
		m_flBlobTime[i] = -1;
	}
	m_fShield = FALSE;
	m_iTransformStatus = TRANS_NONE;
	m_flSubModelDelay = 0;
	m_flLastTeleport = 0;
	m_iNextSubModel = 0;
	m_iBody = 0;
	m_fSword = FALSE;
	m_fWallJump = FALSE;
	// Reset Melee
	m_Melee.Reset();
	m_Melee.SetAttacker(this);
	// Reset Swoop
	m_Swoop.Reset();
	m_Swoop.SetOwner(this);
	// Reset Charged Turbo
	m_ChargedTurbo.Reset();
	m_ChargedTurbo.setOwner(this);

	// End of add by Pcjoe
	
	// Added by Rick
	m_iChargePercent = 0;
	m_flOldPosUpdateDelay = 0.0f;
	for(byte b=0;b<MAX_OLD_POSITIONS;b++)
	{
		m_OldPositions->Pos = Vector(0, 0, 0);
		m_OldPositions->flCreateTime = 0.0f;
	}
	// End of add by Rick
	
	pev->effects &= ~EF_NODRAW;
	m_eAnimationTrigger = PLAYER_NULL;
	m_eAnimationFlags = ANIM_NONE;
	m_hSpectatorTarget = NULL;
	//end of harSens add
	/*disabled by harSens
	g_pGameRules->SetDefaultPlayerTeam( this );
	*/
	g_pGameRules->GetPlayerSpawnSpot( this );

	// Removed by Pcjoe
/*  SET_MODEL(ENT(pev), "models/player.mdl");
    g_ulModelIndexPlayer = pev->modelindex;*/

	pev->sequence		= LookupActivity( ACT_IDLE );

	/* disabled by harSens
	if ( FBitSet(pev->flags, FL_DUCKING) ) 
		UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
	else
	*/
		UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX);

    pev->view_ofs = VEC_VIEW;
	Precache();
	m_HackedGunPos		= Vector( 0, 32, 0 );

	if ( m_iPlayerSound == SOUNDLIST_EMPTY )
	{
		ALERT ( at_console, "Couldn't alloc player sound slot!\n" );
	}

	m_fNoPlayerSound = FALSE;// normal sound behavior.

	m_pLastItem = NULL;
	m_fInitHUD = TRUE;
	m_iClientHideHUD = -1;  // force this to be recalculated
	m_fWeapon = FALSE;
	m_pClientActiveItem = NULL;
	m_iClientBattery = -1;

	// reset all ammo values to 0
	/* disabled by harSens
	for ( int i = 0; i < MAX_AMMO_SLOTS; i++ )
	{
		m_rgAmmo[i] = 0;
		m_rgAmmoLast[i] = 0;  // client ammo values also have to be reset  (the death hud clear messages does on the client side)
	}
	*/
	//added by harSens 
	m_iClientSpeed = 0; // force speed update to client 
 	g_engfuncs.pfnSetClientMaxspeed( ENT( pev ), GetMaxSpeed() ); 
	//end harSens add
	
	m_lastx = m_lasty = 0;
	
	m_bHadBuddy = false;

	m_flNextChatTime = gpGlobals->time;
	g_pGameRules->PlayerSpawn( this );
}


void CBasePlayer :: Precache( void )
{
	// in the event that the player JUST spawned, and the level node graph
	// was loaded, fix all of the node graph pointers before the game starts.
	
	// !!!BUGBUG - now that we have multiplayer, this needs to be moved!
	if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet )
	{
		if ( !WorldGraph.FSetGraphPointers() )
		{
			ALERT ( at_console, "**Graph pointers were not set!\n");
		}
		else
		{
			ALERT ( at_console, "**Graph Pointers Set!\n" );
		} 
	}

	// SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific)
	// because they need to precache before any clients have connected

	// init geiger counter vars during spawn and each time
	// we cross a level transition

	/*disabled by harSens
	m_flgeigerRange = 1000;
	m_igeigerRangePrev = 1000;
	*/

	m_bitsDamageType = 0;
	m_bitsHUDDamage = -1;

	m_iClientBattery = -1;

	m_iTrain = TRAIN_NEW;

	// Make sure any necessary user messages have been registered
	LinkUserMessages();

	m_iUpdateTime = 5;  // won't update for 1/2 a second

	if ( gInitHUD )
		m_fInitHUD = TRUE;
}


int CBasePlayer::Save( CSave &save )
{
	if ( !CBaseMonster::Save(save) )
		return 0;

	return save.WriteFields( "PLAYER", this, m_playerSaveData, HL_ARRAYSIZE(m_playerSaveData) );
}


//
// Marks everything as new so the player will resend this to the hud.
//
void CBasePlayer::RenewItems(void)
{

}


int CBasePlayer::Restore( CRestore &restore )
{
	if ( !CBaseMonster::Restore(restore) )
		return 0;

	int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, HL_ARRAYSIZE(m_playerSaveData) );

	SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData;
	// landmark isn't present.
	if ( !pSaveData->fUseLandmark )
	{
		ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName );

		// default to normal spawn
		edict_t* pentSpawnSpot = EntSelectSpawnPoint( this );
		pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1);
		pev->angles = VARS(pentSpawnSpot)->angles;
	}
	pev->v_angle.z = 0;	// Clear out roll
	pev->angles = pev->v_angle;

	pev->fixangle = TRUE;           // turn this way immediately

// Copied from spawn() for now
	m_bloodColor	= BLOOD_COLOR_RED;

	// Removed by Pcjoe
//   g_ulModelIndexPlayer = pev->modelindex;

	/* disabled by harSens
	if ( FBitSet(pev->flags, FL_DUCKING) ) 
	{
		// Use the crouch HACK
		//FixPlayerCrouchStuck( edict() );
		// Don't need to do this with new player prediction code.
		UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
	}
	else
	{
	*/
		UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX);
	//}

	g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" );

	if ( m_fLongJump )
	{
		g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" );
	}
	else
	{
		g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" );
	}

	RenewItems();

#if defined( CLIENT_WEAPONS )
	// HACK:	This variable is saved/restored in CBaseMonster as a time variable, but we're using it
	//			as just a counter.  Ideally, this needs its own variable that's saved as a plain float.
	//			Barring that, we clear it out here instead of using the incorrect restored time value.
	m_flNextAttack = UTIL_WeaponTimeBase();
#endif

	return status;
}



void CBasePlayer::SelectNextItem( int iItem )
{
	// added by harSens: can we holster?
	if (m_pActiveItem)
	{	if (!m_pActiveItem->CanHolster())
		{	return;
		}
	}
	CBasePlayerItem *pItem;

	pItem = m_rgpPlayerItems[ iItem ];
	
	if (!pItem)
		return;

	if (pItem == m_pActiveItem)
	{
		// select the next one in the chain
		pItem = m_pActiveItem->m_pNext; 
		if (! pItem)
		{
			return;
		}

		CBasePlayerItem *pLast;
		pLast = pItem;
		while (pLast->m_pNext)
			pLast = pLast->m_pNext;

		// relink chain
		pLast->m_pNext = m_pActiveItem;
		m_pActiveItem->m_pNext = NULL;
		m_rgpPlayerItems[ iItem ] = pItem;
	}

	/* removed by harSens
	ResetAutoaim( );
	*/

	// FIX, this needs to queue them up and delay
	if (m_pActiveItem)
	{
		m_pActiveItem->Holster( );
		// Added by Pcjoe, reset animation trigger
		m_eAnimationTrigger = PLAYER_NULL;
		m_fSwat = false;
	}
	
	m_pActiveItem = pItem;

	if (m_pActiveItem)
	{
		m_pActiveItem->Deploy( );
		m_pActiveItem->UpdateItemInfo( );
	}
}

void CBasePlayer::SelectItem(const char *pstr)
{
	if (!pstr)
		return;
	// added by harSens: can we holster?
	if (m_pActiveItem)
	{	if (!m_pActiveItem->CanHolster())
		{	return;
		}
	}

	CBasePlayerItem *pItem = NULL;

	for (int i = 0; i < MAX_ITEM_TYPES; i++)
	{
		if (m_rgpPlayerItems[i])
		{
			pItem = m_rgpPlayerItems[i];
	
			while (pItem)
			{
				if (FClassnameIs(pItem->pev, pstr))
					break;
				pItem = pItem->m_pNext;
			}
		}

		if (pItem)
			break;
	}

	if (!pItem)
		return;

	
	if (pItem == m_pActiveItem)
		return;

	//added by harSens
	if (!pItem->CanDeploy())
		return;
	/* removed by harSens
	ResetAutoaim( );
	*/

	// FIX, this needs to queue them up and delay
	if (m_pActiveItem)
		m_pActiveItem->Holster( );

	// Added by Pcjoe, reset animation trigger
	m_eAnimationTrigger = PLAYER_NULL;
	m_fSwat = false;
	
	m_pLastItem = m_pActiveItem;
	m_pActiveItem = pItem;

	if (m_pActiveItem)
	{
		m_pActiveItem->Deploy( );
		m_pActiveItem->UpdateItemInfo( );
	}
}


void CBasePlayer::SelectLastItem(void)
{
	if (!m_pLastItem)
	{
		return;
	}

	if ( m_pActiveItem && !m_pActiveItem->CanHolster() )
	{
		return;
	}

	/* disabled by harSens
	ResetAutoaim( );
	*/

	// FIX, this needs to queue them up and delay
	if (m_pActiveItem)
		m_pActiveItem->Holster( );
	
	CBasePlayerItem *pTemp = m_pActiveItem;
	m_pActiveItem = m_pLastItem;
	m_pLastItem = pTemp;
	m_pActiveItem->Deploy( );
	m_pActiveItem->UpdateItemInfo( );
}

//==============================================
// HasWeapons - do I have any weapons at all?
//==============================================
BOOL CBasePlayer::HasWeapons( void )
{
	int i;

	for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
	{
		if ( m_rgpPlayerItems[ i ] )
		{
			return TRUE;
		}
	}

	return FALSE;
}

void CBasePlayer::SelectPrevItem( int iItem )
{
}


const char *CBasePlayer::TeamID( void )
{
	if ( pev == NULL )		// Not fully connected yet
		return "";

	// return their team name
	return m_szTeamName;
}


//==============================================
// !!!UNDONE:ultra temporary SprayCan entity to apply
// decal frame at a time. For PreAlpha CD
//==============================================
class CSprayCan : public CBaseEntity
{
public:
	void	Spawn ( entvars_t *pevOwner );
	void	Think( void );

	virtual int	ObjectCaps( void ) { return FCAP_DONT_SAVE; }
};

void CSprayCan::Spawn ( entvars_t *pevOwner )
{
	pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 );
	pev->angles = pevOwner->v_angle;
	pev->owner = ENT(pevOwner);
	pev->frame = 0;

	pev->nextthink = gpGlobals->time + 0.1;
	EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM);
}

void CSprayCan::Think( void )
{
	TraceResult	tr;	
	int playernum;
	int nFrames;
	CBasePlayer *pPlayer;
	
	pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner);

	if (pPlayer)
		nFrames = pPlayer->GetCustomDecalFrames();
	else
		nFrames = -1;

	playernum = ENTINDEX(pev->owner);
	
	// ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames);

	UTIL_MakeVectors(pev->angles);
	UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr);

	// No customization present.
	if (nFrames == -1)
	{
		UTIL_DecalTrace( &tr, DECAL_LAMBDA6 );
		UTIL_Remove( this );
	}
	else
	{
		UTIL_PlayerDecalTrace( &tr, playernum, pev->frame, TRUE );
		// Just painted last custom frame.
		if ( pev->frame++ >= (nFrames - 1))
			UTIL_Remove( this );
	}

	pev->nextthink = gpGlobals->time + 0.1;
}

class	CBloodSplat : public CBaseEntity
{
public:
	void	Spawn ( entvars_t *pevOwner );
	void	Spray ( void );
};

void CBloodSplat::Spawn ( entvars_t *pevOwner )
{
	pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 );
	pev->angles = pevOwner->v_angle;
	pev->owner = ENT(pevOwner);

	SetThink ( &CBloodSplat::Spray );
	pev->nextthink = gpGlobals->time + 0.1;
}

void CBloodSplat::Spray ( void )
{
	TraceResult	tr;	
	
	if ( g_Language != LANGUAGE_GERMAN )
	{
		UTIL_MakeVectors(pev->angles);
		UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr);

		UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
	}
	SetThink ( &CBloodSplat::SUB_Remove );
	pev->nextthink = gpGlobals->time + 0.1;
}

//==============================================



void CBasePlayer::GiveNamedItem( const char *pszName )
{
	edict_t	*pent;

	int istr = MAKE_STRING(pszName);

	pent = CREATE_NAMED_ENTITY(istr);
	if ( FNullEnt( pent ) )
	{
		ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" );
		return;
	}
	VARS( pent )->origin = pev->origin;
	pent->v.spawnflags |= SF_NORESPAWN;

	DispatchSpawn( pent );
	DispatchTouch( pent, ENT( pev ) );
}



CBaseEntity *FindEntityForward( CBaseEntity *pMe )
{
	TraceResult tr;

	UTIL_MakeVectors(pMe->pev->v_angle);
	UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192,dont_ignore_monsters, pMe->edict(), &tr );
	if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) )
	{
		CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
		return pHit;
	}
	return NULL;
}


/* removed by harSens
BOOL CBasePlayer :: FlashlightIsOn( void )
{
	return FBitSet(pev->effects, EF_DIMLIGHT);
}
*/

/* removed by harSens
void CBasePlayer :: FlashlightTurnOn( void )
{
	if ( !g_pGameRules->FAllowFlashlight() )
	{
		return;
	}

	if ( (pev->weapons & (1<<WEAPON_SUIT)) )
	{
		EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_ON, 1.0, ATTN_NORM, 0, PITCH_NORM );
		SetBits(pev->effects, EF_DIMLIGHT);
		MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev );
		WRITE_BYTE(1);
		WRITE_BYTE(m_iFlashBattery);
		MESSAGE_END();

		m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;

	}
}
*/

/* removed by harSens
void CBasePlayer :: FlashlightTurnOff( void )
{
	EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, 1.0, ATTN_NORM, 0, PITCH_NORM );
    ClearBits(pev->effects, EF_DIMLIGHT);
	MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev );
	WRITE_BYTE(0);
	WRITE_BYTE(m_iFlashBattery);
	MESSAGE_END();

	m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time;

}
*/

/*
===============
ForceClientDllUpdate

When recording a demo, we need to have the server tell us the entire client state
so that the client side .dll can behave correctly.
Reset stuff so that the state is transmitted.
===============
*/
void CBasePlayer :: ForceClientDllUpdate( void )
{
	
	m_iClientHealth  = -1;
	m_iClientBattery = -1;
	m_iTrain |= TRAIN_NEW;  // Force new train message.
	
    
	m_fWeapon = FALSE;          // Force weapon send
	m_fKnownItem = FALSE;		// Force weaponinit messages.	
	m_fInitHUD = TRUE;		// Force HUD gmsgResetHUD message
	m_fInitHUDMap = TRUE;	// Pcjoe: Force HUD gmsgMapResetHUD message


	//added by harSens:
	m_pClientActiveItem = NULL;
	m_iClientSpeed = -1;
	m_iClientPowerLevel= -1;
	m_iClientStamina = -1;

	// Now force all the necessary messages
	//  to be sent.
	UpdateClientData();
}

/*
============
ImpulseCommands
============
*/
extern float g_flWeaponCheat;

void CBasePlayer::ImpulseCommands( )
{
	TraceResult	tr;// UNDONE: kill me! This is temporary for PreAlpha CDs

	// Handle use events
	PlayerUse();
		
	int iImpulse = (int)pev->impulse;
	switch (iImpulse)
	{
	case 99:
		{

		int iOn;

		if (!gmsgLogo)
		{
			iOn = 1;
			gmsgLogo = REG_USER_MSG("Logo", 1);
		} 
		else 
		{
			iOn = 0;
		}
		
		ASSERT( gmsgLogo > 0 );
		// send "health" update message
		MESSAGE_BEGIN( MSG_ONE, gmsgLogo, NULL, pev );
			WRITE_BYTE(iOn);
		MESSAGE_END();

		if(!iOn)
			gmsgLogo = 0;
		break;
		}
	case 100:
		/* removed by harSens
        // temporary flashlight for level designers
        if ( FlashlightIsOn() )
		{
			FlashlightTurnOff();
		}
        else 
		{
			FlashlightTurnOn();
		}
		break;
		*/
	case	201:// paint decal
		
		if ( gpGlobals->time < m_flNextDecalTime )
		{
			// too early!
			break;
		}

		UTIL_MakeVectors(pev->v_angle);
		UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr);

		if ( tr.flFraction != 1.0 )
		{// line hit something, so paint a decal
			m_flNextDecalTime = gpGlobals->time + decalfrequency.value;
			CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL);
			pCan->Spawn( pev );
		}

		break;

	default:
		// check all of the cheat impulse commands now
		CheatImpulseCommands( iImpulse );
		break;
	}
	
	pev->impulse = 0;
}

//=========================================================
//=========================================================
void CBasePlayer::CheatImpulseCommands( int iImpulse )
{
#if !defined( HLDEMO_BUILD )
	if ( g_flWeaponCheat == 0.0 )
	{
		return;
	}

	CBaseEntity *pEntity;
	TraceResult tr;

	switch ( iImpulse )
	{
	case 76:
		{
			if (!giPrecacheGrunt)
			{
				giPrecacheGrunt = 1;
				ALERT(at_console, "You must now restart to use Grunt-o-matic.\n");
			}
			else
			{
				UTIL_MakeVectors( Vector( 0, pev->v_angle.y, 0 ) );
				Create("monster_human_grunt", pev->origin + gpGlobals->v_forward * 128, pev->angles);
			}
			break;
		}


	case 101:
		/*disabled by harSens. those no longer exists :-)
		gEvilImpulse101 = TRUE;
		GiveNamedItem( "item_suit" );
		GiveNamedItem( "item_battery" );
		GiveNamedItem( "weapon_crowbar" );
		GiveNamedItem( "weapon_9mmhandgun" );
		GiveNamedItem( "ammo_9mmclip" );
		GiveNamedItem( "weapon_shotgun" );
		GiveNamedItem( "ammo_buckshot" );
		GiveNamedItem( "weapon_9mmAR" );
		GiveNamedItem( "ammo_9mmAR" );
		GiveNamedItem( "ammo_ARgrenades" );
		GiveNamedItem( "weapon_handgrenade" );
		GiveNamedItem( "weapon_tripmine" );
#ifndef OEM_BUILD
		GiveNamedItem( "weapon_357" );
		GiveNamedItem( "ammo_357" );
		GiveNamedItem( "weapon_crossbow" );
		GiveNamedItem( "ammo_crossbow" );
		GiveNamedItem( "weapon_egon" );
		GiveNamedItem( "weapon_gauss" );
		GiveNamedItem( "ammo_gaussclip" );
		GiveNamedItem( "weapon_rpg" );
		GiveNamedItem( "ammo_rpgclip" );
		GiveNamedItem( "weapon_satchel" );
		GiveNamedItem( "weapon_snark" );
		GiveNamedItem( "weapon_hornetgun" );
#endif
		*/
		gEvilImpulse101 = FALSE;
		break;

	case 102:
		// Gibbage!!!
		CGib::SpawnRandomGibs( pev, 1, 1 );
		break;

	case 103:
		// What the hell are you doing?
		pEntity = FindEntityForward( this );
		if ( pEntity )
		{
			CBaseMonster *pMonster = pEntity->MyMonsterPointer();
			if ( pMonster )
				pMonster->ReportAIState();
		}
		break;

	case 104:
		// Dump all of the global state varaibles (and global entity names)
		gGlobalState.DumpGlobals();
		break;

	case	105:// player makes no sound for monsters to hear.
		{
			if ( m_fNoPlayerSound )
			{
				ALERT ( at_console, "Player is audible\n" );
				m_fNoPlayerSound = FALSE;
			}
			else
			{
				ALERT ( at_console, "Player is silent\n" );
				m_fNoPlayerSound = TRUE;
			}
			break;
		}

	case 106:
		// Give me the classname and targetname of this entity.
		pEntity = FindEntityForward( this );
		if ( pEntity )
		{
			ALERT ( at_console, "Classname: %s", STRING( pEntity->pev->classname ) );
			
			if ( !FStringNull ( pEntity->pev->targetname ) )
			{
				ALERT ( at_console, " - Targetname: %s\n", STRING( pEntity->pev->targetname ) );
			}
			else
			{
				ALERT ( at_console, " - TargetName: No Targetname\n" );
			}

			ALERT ( at_console, "Model: %s\n", STRING( pEntity->pev->model ) );
			if ( pEntity->pev->globalname )
				ALERT ( at_console, "Globalname: %s\n", STRING( pEntity->pev->globalname ) );
		}
		break;

	case 107:
		{
			TraceResult tr;

			edict_t		*pWorld = g_engfuncs.pfnPEntityOfEntIndex( 0 );

			Vector start = pev->origin + pev->view_ofs;
			Vector end = start + gpGlobals->v_forward * 1024;
			UTIL_TraceLine( start, end, ignore_monsters, edict(), &tr );
			if ( tr.pHit )
				pWorld = tr.pHit;
			const char *pTextureName = TRACE_TEXTURE( pWorld, start, end );
			if ( pTextureName )
				ALERT( at_console, "Texture: %s\n", pTextureName );
		}
		break;
	case	195:// show shortest paths for entire level to nearest node
		{
			Create("node_viewer_fly", pev->origin, pev->angles);
		}
		break;
	case	196:// show shortest paths for entire level to nearest node
		{
			Create("node_viewer_large", pev->origin, pev->angles);
		}
		break;
	case	197:// show shortest paths for entire level to nearest node
		{
			Create("node_viewer_human", pev->origin, pev->angles);
		}
		break;
	case	199:// show nearest node and all connections
		{
			ALERT ( at_console, "%d\n", WorldGraph.FindNearestNode ( pev->origin, bits_NODE_GROUP_REALM ) );
			WorldGraph.ShowNodeConnections ( WorldGraph.FindNearestNode ( pev->origin, bits_NODE_GROUP_REALM ) );
		}
		break;
	case	202:// Random blood splatter
		UTIL_MakeVectors(pev->v_angle);
		UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr);

		if ( tr.flFraction != 1.0 )
		{// line hit something, so paint a decal
			CBloodSplat *pBlood = GetClassPtr((CBloodSplat *)NULL);
			pBlood->Spawn( pev );
		}
		break;
	case	203:// remove creature.
		pEntity = FindEntityForward( this );
		if ( pEntity )
		{
			if ( pEntity->pev->takedamage )
				pEntity->SetThink(&CBaseEntity::SUB_Remove);
		}
		break;
	}
#endif	// HLDEMO_BUILD
}

//
// Add a weapon to the player (Item == Weapon == Selectable Object)
//
int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem )
{
	CBasePlayerItem *pInsert;
	
	pInsert = m_rgpPlayerItems[pItem->iItemSlot()];

	while (pInsert)
	{
		if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) ))
		{
			if (pItem->AddDuplicate( pInsert ))
			{
				g_pGameRules->PlayerGotWeapon ( this, pItem );
				pItem->CheckRespawn();

				// ugly hack to update clip w/o an update clip message
				pInsert->UpdateItemInfo( );
				if (m_pActiveItem)
					m_pActiveItem->UpdateItemInfo( );

				pItem->Kill( );
			}
			else if (gEvilImpulse101)
			{
				// FIXME: remove anyway for deathmatch testing
				pItem->Kill( );
			}
			return FALSE;
		}
		pInsert = pInsert->m_pNext;
	}


	if (pItem->AddToPlayer( this ))
	{
		g_pGameRules->PlayerGotWeapon ( this, pItem );
		pItem->CheckRespawn();

		pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()];
		m_rgpPlayerItems[pItem->iItemSlot()] = pItem;

		// should we switch to this item?
		if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) )
		{
			SwitchWeapon( pItem );
		}

		return TRUE;
	}
	else if (gEvilImpulse101)
	{
		// FIXME: remove anyway for deathmatch testing
		pItem->Kill( );
	}
	return FALSE;
}



int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem )
{
	if (m_pActiveItem == pItem)
	{	/* removed by harSens
		ResetAutoaim( );
		*/
		pItem->Holster( );
		pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc.
		pItem->SetThink( NULL );
		m_pActiveItem = NULL;
		pev->viewmodel = 0;
		pev->weaponmodel = 0;
	}
	else if ( m_pLastItem == pItem )
		m_pLastItem = NULL;

	CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()];

	if (pPrev == pItem)
	{
		m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext;
		return TRUE;
	}
	else
	{
		while (pPrev && pPrev->m_pNext != pItem)
		{
			pPrev = pPrev->m_pNext;
		}
		if (pPrev)
		{
			pPrev->m_pNext = pItem->m_pNext;
			return TRUE;
		}
	}
	return FALSE;
}


//
// Returns the unique ID for the ammo, or -1 if error
//
/* disabled by harSens
int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax )
{
	if ( !szName )
	{
		// no ammo.
		return -1;
	}

	if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) )
	{
		// game rules say I can't have any more of this ammo type.
		return -1;
	}

	int i = 0;

	i = GetAmmoIndex( szName );

	if ( i < 0 || i >= MAX_AMMO_SLOTS )
		return -1;

	int iAdd = min( iCount, iMax - m_rgAmmo[i] );
	if ( iAdd < 1 )
		return i;

	m_rgAmmo[ i ] += iAdd;


	if ( gmsgAmmoPickup )  // make sure the ammo messages have been linked first
	{
		// Send the message that ammo has been picked up
		MESSAGE_BEGIN( MSG_ONE, gmsgAmmoPickup, NULL, pev );
			WRITE_BYTE( GetAmmoIndex(szName) );		// ammo ID
			WRITE_BYTE( iAdd );		// amount
		MESSAGE_END();
	}

	TabulateAmmo();

	return i;
}
*/


/*
============
ItemPreFrame

Called every frame by the player PreThink
============
*/
void CBasePlayer::ItemPreFrame()
{
#if defined( CLIENT_WEAPONS )
    if ( m_flNextAttack > 0 )
#else
    if ( gpGlobals->time < m_flNextAttack )
#endif
	{
		return;
	}

	if (!m_pActiveItem)
		return;

	m_pActiveItem->ItemPreFrame( );
}


/*
============
ItemPostFrame

Called every frame by the player PostThink
============
*/
void CBasePlayer::ItemPostFrame()
{
	static int fInSelect = FALSE;

	// check if the player is using a tank
	if ( m_pTank != NULL )
		return;

#if defined( CLIENT_WEAPONS )
    if ( m_flNextAttack > 0 )
#else
    if ( gpGlobals->time < m_flNextAttack )
#endif
	{
		return;
	}

	ImpulseCommands();

	if (!m_pActiveItem)
		return;

	m_pActiveItem->ItemPostFrame( );
}

/* disabled by harSens
int CBasePlayer::AmmoInventory( int iAmmoIndex )
{
	if (iAmmoIndex == -1)
	{
		return -1;
	}

	return m_rgAmmo[ iAmmoIndex ];
}
*/

int CBasePlayer::GetAmmoIndex(const char *psz)
{
	int i;

	if (!psz)
		return -1;

	for (i = 1; i < MAX_AMMO_SLOTS; i++)
	{
		if ( !CBasePlayerItem::AmmoInfoArray[i].pszName )
			continue;

		if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0)
			return i;
	}

	return -1;
}

// Called from UpdateClientData
// makes sure the client has all the necessary ammo info,  if values have changed
/* disabled by harSens
void CBasePlayer::SendAmmoUpdate(void)
{
	for (int i=0; i < MAX_AMMO_SLOTS;i++)
	{
		if (m_rgAmmo[i] != m_rgAmmoLast[i])
		{
			m_rgAmmoLast[i] = m_rgAmmo[i];

			ASSERT( m_rgAmmo[i] >= 0 );
			ASSERT( m_rgAmmo[i] < 255 );

			// send "Ammo" update message
			MESSAGE_BEGIN( MSG_ONE, gmsgAmmoX, NULL, pev );
				WRITE_BYTE( i );
				WRITE_BYTE( max( min( m_rgAmmo[i], 254 ), 0 ) );  // clamp the value to one byte
			MESSAGE_END();
		}
	}
}
*/

/*
=========================================================
	UpdateClientData

resends any changed player HUD info to the client.
Called every frame by PlayerPreThink
Also called at start of demo recording and playback by
ForceClientDllUpdate to ensure the demo gets messages
reflecting all of the HUD state info.
=========================================================
*/
void CBasePlayer :: UpdateClientData( void )
{
	if (m_fInitHUD)
	{
		m_fInitHUD = FALSE;
		gInitHUD = FALSE;

		MESSAGE_BEGIN( MSG_ONE, gmsgResetHUD, NULL, pev );
			WRITE_BYTE( 0 );
		MESSAGE_END();

		if ( !m_fGameHUDInitialized )
		{
			MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, pev );
			MESSAGE_END();

			g_pGameRules->InitHUD( this );
			m_fGameHUDInitialized = TRUE;
			if ( g_pGameRules->IsMultiplayer() )
			{
				FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 );
			}

			// KI Shield
			CBaseEntity *pEntity = NULL;
			pEntity = UTIL_FindEntityByClassname( pEntity, "kishield" );

			while (pEntity)
			{	
				CShield *pShield = (CShield*)pEntity;
				MESSAGE_BEGIN( MSG_ONE, gmsgBlobStart, NULL, pev );
					WRITE_BYTE (0);			// Is it a blob or a shield? ( 1 = Blob, 0 = Shield )
					WRITE_COORD(pShield->pev->origin.x);	// Origin
					WRITE_COORD(pShield->pev->origin.y);
					WRITE_COORD(pShield->pev->origin.z);
					WRITE_SHORT (pShield->entindex());	// Entity Index
					WRITE_SHORT (pShield->m_iSize);	// Size of Explosion					
				MESSAGE_END();

				pEntity = UTIL_FindEntityByClassname( pEntity, "kishield" );
			}

			//KI Blob
			pEntity = NULL;
			pEntity = UTIL_FindEntityByClassname( pEntity, "kiblob" );

			while (pEntity)
			{	
				CBlob *pBlob = (CBlob*)pEntity;
				MESSAGE_BEGIN( MSG_ONE, gmsgBlobStart, NULL, pev );
					WRITE_BYTE (1);			// Is it a blob or a shield? ( 1 = Blob, 0 = Shield )
					WRITE_COORD(pBlob->pev->origin.x);	// Origin
					WRITE_COORD(pBlob->pev->origin.y);
					WRITE_COORD(pBlob->pev->origin.z);
					WRITE_SHORT (pBlob->entindex());	// Entity Index
					WRITE_SHORT (pBlob->m_iSize);	// Size of Explosion					
				MESSAGE_END();

				pEntity = UTIL_FindEntityByClassname( pEntity, "kiblob" );
			}
		}

		FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 );

		/* disabled by harSens
		InitStatusBar();
		*/
	}

	// Tell hud we changed levels, reset data
	if(m_fInitHUDMap)
	{	m_fInitHUDMap = FALSE;
		MESSAGE_BEGIN( MSG_ONE, gmsgInitHUDMap, NULL, pev );
		MESSAGE_END();
	}

	if ( m_iHideHUD != m_iClientHideHUD )
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgHideWeapon, NULL, pev );
			WRITE_BYTE( m_iHideHUD );
		MESSAGE_END();
		m_iClientHideHUD = m_iHideHUD;
	}

	if ( m_iFOV != m_iClientFOV )
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
			WRITE_BYTE( m_iFOV );
		MESSAGE_END();

		// cache FOV change at end of function, so weapon updates can see that FOV has changed
	}

	// HACKHACK -- send the message to display the game title
	/* disabled by harSens
	if (gDisplayTitle)
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgShowGameTitle, NULL, pev );
		WRITE_BYTE( 0 );
		MESSAGE_END();
		gDisplayTitle = 0;
	}
	*/
	if (pev->health != m_iClientHealth)
	{
		int iHealth = max( pev->health, 0 );  // make sure that no negative health values are sent

		// send "health" update message
		MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev );
			WRITE_BYTE( iHealth );
		MESSAGE_END();

		m_iClientHealth = pev->health;
	}

	//added by harSens. speed code.
	int iSpeed = GetMaxSpeed();
	if (iSpeed != m_iClientSpeed) 
	{	//stop jumping/duckfly, if maxspeed 0
		if (iSpeed)
		{	pev->stop_jump=false;
		}
		else
		{	pev->stop_jump=true;
		}
				
		// send "Speed" update message 
		g_engfuncs.pfnSetClientMaxspeed( ENT( pev ), GetMaxSpeed() ); 						
		// Edited by Pcjoe
		/*
		MESSAGE_BEGIN( MSG_ONE, gmsgSpeed, NULL, pev ); 
		WRITE_SHORT( iSpeed ); 
		MESSAGE_END(); 
		*/
		pev->fuser1 = iSpeed;
		m_iClientSpeed = iSpeed; 
	} 
	//end harSens add
	//added by harSens. powerlevel code.
	int iPowerLevel = GetPowerLevel();
	if (iPowerLevel != m_iClientPowerLevel) 
	{	//send "PowerLevel" update message
		MESSAGE_BEGIN( MSG_ALL, gmsgPowerLevel);
			WRITE_BYTE( entindex());
			WRITE_LONG( iPowerLevel );
		MESSAGE_END(); 
		m_iClientPowerLevel = iPowerLevel;
	} 

	if(m_iStamina!=m_iClientStamina)
	{
		MESSAGE_BEGIN( MSG_ONE, gmsgStamina, NULL, pev);
			WRITE_LONG( m_iStamina );
		MESSAGE_END(); 
		m_iClientStamina = m_iStamina;
	}
	//end harSens add

	/* disabled by harSens
	if (pev->armorvalue != m_iClientBattery)
	{
		m_iClientBattery = pev->armorvalue;

		ASSERT( gmsgBattery > 0 );
		// send "health" update message
		MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev );
			WRITE_SHORT( (int)pev->armorvalue);
		MESSAGE_END();
	}
	*/

	if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType)
	{
		// Comes from inside me if not set
		Vector damageOrigin = pev->origin;
		// send "damage" message
		// causes screen to flash, and pain compass to show direction of damage
		edict_t *other = pev->dmg_inflictor;
		if ( other )
		{
			CBaseEntity *pEntity = CBaseEntity::Instance(other);
			if ( pEntity )
				damageOrigin = pEntity->Center();
		}

		// only send down damage type that have hud art
		/*removed by harSens
		int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD;

		MESSAGE_BEGIN( MSG_ONE, gmsgDamage, NULL, pev );
			WRITE_BYTE( pev->dmg_save );
			WRITE_BYTE( pev->dmg_take );
			WRITE_LONG( visibleDamageBits );
			WRITE_COORD( damageOrigin.x );
			WRITE_COORD( damageOrigin.y );
			WRITE_COORD( damageOrigin.z );
		MESSAGE_END();
		*/
		pev->dmg_take = 0;
		pev->dmg_save = 0;
		m_bitsHUDDamage = m_bitsDamageType;
		
		// Clear off non-time-based damage indicators
		m_bitsDamageType &= DMG_TIMEBASED;
	}

	/* disabled by harSens
	// Update Flashlight
	if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->time))
	{
		if (FlashlightIsOn())
		{
			if (m_iFlashBattery)
			{
				m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time;
				m_iFlashBattery--;
				
				if (!m_iFlashBattery)
					FlashlightTurnOff();
			}
		}
		else
		{
			if (m_iFlashBattery < 100)
			{
				m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time;
				m_iFlashBattery++;
			}
			else
				m_flFlashLightTime = 0;
		}

		MESSAGE_BEGIN( MSG_ONE, gmsgFlashBattery, NULL, pev );
		WRITE_BYTE(m_iFlashBattery);
		MESSAGE_END();
	}
	*/

	/* removed by harSens
	if (m_iTrain & TRAIN_NEW)
	{
		ASSERT( gmsgTrain > 0 );
		// send "health" update message
		MESSAGE_BEGIN( MSG_ONE, gmsgTrain, NULL, pev );
			WRITE_BYTE(m_iTrain & 0xF);
		MESSAGE_END();

		m_iTrain &= ~TRAIN_NEW;
	}
	*/

	//
	// New Weapon?
	//
	if (!m_fKnownItem)
	{
		m_fKnownItem = TRUE;

	// WeaponInit Message
	// byte  = # of weapons
	//
	// for each weapon:
	// byte		name str length (not including null)
	// bytes... name
	// byte		Ammo Type
	// byte		Ammo2 Type
	// byte		bucket
	// byte		bucket pos
	// byte		flags	
	// ????		Icons
		
		// Send ALL the weapon info now
		int i;

		for (i = 0; i < MAX_WEAPONS; i++)
		{
			ItemInfo& II = CBasePlayerItem::ItemInfoArray[i];

			if ( !II.iId )
				continue;

			const char *pszName;
			if (!II.pszName)
				pszName = "Empty";
			else
				pszName = II.pszName;

			MESSAGE_BEGIN( MSG_ONE, gmsgWeaponList, NULL, pev );  
				WRITE_STRING(pszName);			// string	weapon name
				/* disabled by harSens
				WRITE_BYTE(GetAmmoIndex(II.pszAmmo1));	// byte		Ammo Type
				WRITE_BYTE(II.iMaxAmmo1);				// byte     Max Ammo 1
				WRITE_BYTE(GetAmmoIndex(II.pszAmmo2));	// byte		Ammo2 Type
				WRITE_BYTE(II.iMaxAmmo2);				// byte     Max Ammo 2
				*/
				WRITE_BYTE(II.iSlot);					// byte		bucket
				WRITE_BYTE(II.iPosition);				// byte		bucket pos
				WRITE_BYTE(II.iId);						// byte		id (bit index into pev->weapons)
				WRITE_BYTE(II.iFlags);					// byte		Flags
			MESSAGE_END();		
		}

		//added by harSens, update available player weapons on client
		for ( int i = 0; i < MAX_ITEM_TYPES; i++ )
		{
			extern int gmsgWeaponUpdate;
			if (m_rgpPlayerItems[i])
			{
				MESSAGE_BEGIN( MSG_ONE, gmsgWeaponUpdate, NULL, pev );
					WRITE_CHAR( m_rgpPlayerItems[i]->m_iId );
				MESSAGE_END();
			}
		}
	}


	/* removed by harSens
	SendAmmoUpdate();
	*/

	// Update all the items
	for ( int i = 0; i < MAX_ITEM_TYPES; i++ )
	{
		if ( m_rgpPlayerItems[i] )  // each item updates it's successors
		{	m_rgpPlayerItems[i]->UpdateClientData( this );
		}
	}

	// Cache and client weapon change
	m_pClientActiveItem = m_pActiveItem;
	m_iClientFOV = m_iFOV;

	/* removed by harSens. This won't be needed
	// Update Status Bar
	if ( m_flNextSBarUpdateTime < gpGlobals->time )
	{
		UpdateStatusBar();
		m_flNextSBarUpdateTime = gpGlobals->time + 0.2;
	}
	*/
}


//=========================================================
// FBecomeProne - Overridden for the player to set the proper
// physics flags when a barnacle grabs player.
//=========================================================
BOOL CBasePlayer :: FBecomeProne ( void )
{
	m_afPhysicsFlags |= PFLAG_ONBARNACLE;
	return TRUE;
}

//=========================================================
// BarnacleVictimBitten - bad name for a function that is called
// by Barnacle victims when the barnacle pulls their head
// into its mouth. For the player, just die.
//=========================================================
void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle )
{
	TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB );
}

//=========================================================
// BarnacleVictimReleased - overridden for player who has
// physics flags concerns. 
//=========================================================
void CBasePlayer :: BarnacleVictimReleased ( void )
{
	m_afPhysicsFlags &= ~PFLAG_ONBARNACLE;
}


//=========================================================
// Illumination 
// return player light level plus virtual muzzle flash
//=========================================================
int CBasePlayer :: Illumination( void )
{
	int iIllum = CBaseEntity::Illumination( );

	iIllum += m_iWeaponFlash;
	if (iIllum > 255)
		return 255;
	return iIllum;
}


void CBasePlayer :: EnableControl(BOOL fControl)
{
	if (!fControl)
		pev->flags |= FL_FROZEN;
	else
		pev->flags &= ~FL_FROZEN;

}


#define DOT_1DEGREE   0.9998476951564
#define DOT_2DEGREE   0.9993908270191
#define DOT_3DEGREE   0.9986295347546
#define DOT_4DEGREE   0.9975640502598
#define DOT_5DEGREE   0.9961946980917
#define DOT_6DEGREE   0.9945218953683
#define DOT_7DEGREE   0.9925461516413
#define DOT_8DEGREE   0.9902680687416
#define DOT_9DEGREE   0.9876883405951
#define DOT_10DEGREE  0.9848077530122
#define DOT_15DEGREE  0.9659258262891
#define DOT_20DEGREE  0.9396926207859
#define DOT_25DEGREE  0.9063077870367

//=========================================================
// Autoaim
// set crosshair position to point to enemey
//=========================================================
/* disabled by harSens
Vector CBasePlayer :: GetAutoaimVector( float flDelta )
{
	if (g_iSkillLevel == SKILL_HARD)
	{
		UTIL_MakeVectors( pev->v_angle + pev->punchangle );
		return gpGlobals->v_forward;
	}

	Vector vecSrc = GetGunPosition( );
	float flDist = 8192;

	// always use non-sticky autoaim
	// UNDONE: use sever variable to chose!
	if (1 || g_iSkillLevel == SKILL_MEDIUM)
	{
		m_vecAutoAim = Vector( 0, 0, 0 );
		// flDelta *= 0.5;
	}

	BOOL m_fOldTargeting = m_fOnTarget;
	Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta );

	// update ontarget if changed
	if ( !g_pGameRules->AllowAutoTargetCrosshair() )
		m_fOnTarget = 0;
	else if (m_fOldTargeting != m_fOnTarget)
	{
		m_pActiveItem->UpdateItemInfo( );
	}

	if (angles.x > 180)
		angles.x -= 360;
	if (angles.x < -180)
		angles.x += 360;
	if (angles.y > 180)
		angles.y -= 360;
	if (angles.y < -180)
		angles.y += 360;

	if (angles.x > 25)
		angles.x = 25;
	if (angles.x < -25)
		angles.x = -25;
	if (angles.y > 12)
		angles.y = 12;
	if (angles.y < -12)
		angles.y = -12;


	// always use non-sticky autoaim
	// UNDONE: use sever variable to chose!
	if (0 || g_iSkillLevel == SKILL_EASY)
	{
		m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33;
	}
	else
	{
		m_vecAutoAim = angles * 0.9;
	}

	// m_vecAutoAim = m_vecAutoAim * 0.99;

	// Don't send across network if sv_aim is 0
	if ( g_psv_aim->value != 0 )
	{
		if ( m_vecAutoAim.x != m_lastx ||
			 m_vecAutoAim.y != m_lasty )
		{
			SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y );
			
			m_lastx = m_vecAutoAim.x;
			m_lasty = m_vecAutoAim.y;
		}
	}

	// ALERT( at_console, "%f %f\n", angles.x, angles.y );

	UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim );
	return gpGlobals->v_forward;
}
*/

/* disabled by harSens
Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta  )
{
	edict_t		*pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 );
	CBaseEntity	*pEntity;
	float		bestdot;
	Vector		bestdir;
	edict_t		*bestent;
	TraceResult tr;

	if ( g_psv_aim->value == 0 )
	{
		m_fOnTarget = FALSE;
		return g_vecZero;
	}

	UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim );

	// try all possible entities
	bestdir = gpGlobals->v_forward;
	bestdot = flDelta; // +- 10 degrees
	bestent = NULL;

	m_fOnTarget = FALSE;

	UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr );


	if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO)
	{
		// don't look through water
		if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) 
			|| (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0)))
		{
			if (tr.pHit->v.takedamage == DAMAGE_AIM)
				m_fOnTarget = TRUE;

			return m_vecAutoAim;
		}
	}

	for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ )
	{
		Vector center;
		Vector dir;
		float dot;

		if ( pEdict->free )	// Not in use
			continue;
		
		if (pEdict->v.takedamage != DAMAGE_AIM)
			continue;
		if (pEdict == edict())
			continue;
//		if (pev->team > 0 && pEdict->v.team == pev->team)
//			continue;	// don't aim at teammate
		if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) )
			continue;

		pEntity = Instance( pEdict );
		if (pEntity == NULL)
			continue;

		if (!pEntity->IsAlive())
			continue;

		// don't look through water
		if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) 
			|| (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0))
			continue;

		center = pEntity->BodyTarget( vecSrc );

		dir = (center - vecSrc).Normalize( );

		// make sure it's in front of the player
		if (DotProduct (dir, gpGlobals->v_forward ) < 0)
			continue;

		dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) 
			+ fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5;

		// tweek for distance
		dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist);

		if (dot > bestdot)
			continue;	// to far to turn

		UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr );
		if (tr.flFraction != 1.0 && tr.pHit != pEdict)
		{
			// ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) );
			continue;
		}

		// don't shoot at friends
		if (IRelationship( pEntity ) < 0)
		{
			if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch())
				// ALERT( at_console, "friend\n");
				continue;
		}

		// can shoot at this one
		bestdot = dot;
		bestent = pEdict;
		bestdir = dir;
	}

	if (bestent)
	{
		bestdir = UTIL_VecToAngles (bestdir);
		bestdir.x = -bestdir.x;
		bestdir = bestdir - pev->v_angle - pev->punchangle;

		if (bestent->v.takedamage == DAMAGE_AIM)
			m_fOnTarget = TRUE;

		return bestdir;
	}

	return Vector( 0, 0, 0 );
}
*/

/* disabled by harSens
void CBasePlayer :: ResetAutoaim( )
{
	if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0)
	{
		m_vecAutoAim = Vector( 0, 0, 0 );
		SET_CROSSHAIRANGLE( edict(), 0, 0 );
	}
	m_fOnTarget = FALSE;
}
*/

/*
=============
SetCustomDecalFrames

  UNDONE:  Determine real frame limit, 8 is a placeholder.
  Note:  -1 means no custom frames present.
=============
*/
void CBasePlayer :: SetCustomDecalFrames( int nFrames )
{
	if (nFrames > 0 &&
		nFrames < 8)
		m_nCustomSprayFrames = nFrames;
	else
		m_nCustomSprayFrames = -1;
}

/*
=============
GetCustomDecalFrames

  Returns the # of custom frames this player's custom clan logo contains.
=============
*/
int CBasePlayer :: GetCustomDecalFrames( void )
{
	return m_nCustomSprayFrames;
}


//=========================================================
// DropPlayerItem - drop the named item, or if no name,
// the active item. 
//=========================================================
void CBasePlayer::DropPlayerItem ( char *pszItemName )
{
	if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) )
	{
		// no dropping in single player.
		return;
	}

	if ( !strlen( pszItemName ) )
	{
		// if this string has no length, the client didn't type a name!
		// assume player wants to drop the active item.
		// make the string null to make future operations in this function easier
		pszItemName = NULL;
	} 

	CBasePlayerItem *pWeapon;
	int i;

	for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
	{
		pWeapon = m_rgpPlayerItems[ i ];

		while ( pWeapon )
		{
			if ( pszItemName )
			{
				// try to match by name. 
				if ( !strcmp( pszItemName, STRING( pWeapon->pev->classname ) ) )
				{
					// match! 
					break;
				}
			}
			else
			{
				// trying to drop active item
				if ( pWeapon == m_pActiveItem )
				{
					// active item!
					break;
				}
			}

			pWeapon = pWeapon->m_pNext; 
		}

		
		// if we land here with a valid pWeapon pointer, that's because we found the 
		// item we want to drop and hit a BREAK;  pWeapon is the item.
		if ( pWeapon )
		{
			g_pGameRules->GetNextBestWeapon( this, pWeapon );

			UTIL_MakeVectors ( pev->angles ); 

			/*disabled by harSens
			pev->weapons &= ~(1<<pWeapon->m_iId);// take item off hud

			CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() );
			pWeaponBox->pev->angles.x = 0;
			pWeaponBox->pev->angles.z = 0;
			pWeaponBox->PackWeapon( pWeapon );
			pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100;
			
			// drop half of the ammo for this weapon.
			int	iAmmoIndex;

			iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ???
			
			if ( iAmmoIndex != -1 )
			{
				// this weapon weapon uses ammo, so pack an appropriate amount.
				if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE )
				{
					// pack up all the ammo, this weapon is its own ammo type
					pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] );
					m_rgAmmo[ iAmmoIndex ] = 0; 

				}
				else
				{
					// pack half of the ammo
					pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 );
					m_rgAmmo[ iAmmoIndex ] /= 2; 
				}

			}*/

			return;// we're done, so stop searching with the FOR loop.
		}
	}
}

//=========================================================
// HasPlayerItem Does the player already have this item?
//=========================================================
BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem )
{
	CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()];

	while (pItem)
	{
		if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) ))
		{
			return TRUE;
		}
		pItem = pItem->m_pNext;
	}

	return FALSE;
}

//=========================================================
// HasNamedPlayerItem Does the player already have this item?
//=========================================================
BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName )
{
	CBasePlayerItem *pItem;
	int i;
 
	for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
	{
		pItem = m_rgpPlayerItems[ i ];
		
		while (pItem)
		{
			if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) )
			{
				return TRUE;
			}
			pItem = pItem->m_pNext;
		}
	}

	return FALSE;
}

//=========================================================
// 
//=========================================================
BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) 
{
	if ( !pWeapon->CanDeploy() )
	{
		return FALSE;
	}
	
	/* removed by harSens	
	ResetAutoaim( );
	*/
	if (m_pActiveItem)
	{	//added by harSens
		if(!m_pActiveItem->CanHolster())
		{	return FALSE;
		}
		m_pActiveItem->Holster( );

		// Added by Pcjoe, reset animation trigger
		m_eAnimationTrigger = PLAYER_NULL;
		m_fSwat = false;
	}

	m_pActiveItem = pWeapon;
	pWeapon->Deploy( );

	return TRUE;
}

//=========================================================
// Dead HEV suit prop
//=========================================================
class CDeadHEV : public CBaseMonster
{
public:
	void Spawn( void );
	int	Classify ( void ) { return	CLASS_HUMAN_MILITARY; }

	void KeyValue( KeyValueData *pkvd );

	int	m_iPose;// which sequence to display	-- temporary, don't need to save
	static char *m_szPoses[4];
};

char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" };

void CDeadHEV::KeyValue( KeyValueData *pkvd )
{
	if (FStrEq(pkvd->szKeyName, "pose"))
	{
		m_iPose = atoi(pkvd->szValue);
		pkvd->fHandled = TRUE;
	}
	else 
		CBaseMonster::KeyValue( pkvd );
}

LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV );

//=========================================================
// ********** DeadHEV SPAWN **********
//=========================================================
void CDeadHEV :: Spawn( void )
{
	PRECACHE_MODEL("models/player.mdl");
	SET_MODEL(ENT(pev), "models/player.mdl");

	pev->effects		= 0;
	pev->yaw_speed		= 8;
	pev->sequence		= 0;
	pev->body			= 1;
	m_bloodColor		= BLOOD_COLOR_RED;

	pev->sequence = LookupSequence( m_szPoses[m_iPose] );

	if (pev->sequence == -1)
	{
		ALERT ( at_console, "Dead hevsuit with bad pose\n" );
		pev->sequence = 0;
		pev->effects = EF_BRIGHTFIELD;
	}

	// Corpses have less health
	pev->health			= 8;

	MonsterInitDead();
}


class CStripWeapons : public CPointEntity
{
public:
	void	Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

private:
};

LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons );

void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	CBasePlayer *pPlayer = NULL;

	if ( pActivator && pActivator->IsPlayer() )
	{
		pPlayer = (CBasePlayer *)pActivator;
	}
	else if ( !g_pGameRules->IsDeathmatch() )
	{
		pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) );
	}

	if ( pPlayer )
		pPlayer->RemoveAllItems( FALSE );
}


class CRevertSaved : public CPointEntity
{
public:
	void	Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
	void	EXPORT MessageThink( void );
	void	EXPORT LoadThink( void );
	void	KeyValue( KeyValueData *pkvd );

	virtual int		Save( CSave &save );
	virtual int		Restore( CRestore &restore );
	static	TYPEDESCRIPTION m_SaveData[];

	inline	float	Duration( void ) { return pev->dmg_take; }
	inline	float	HoldTime( void ) { return pev->dmg_save; }
	inline	float	MessageTime( void ) { return m_messageTime; }
	inline	float	LoadTime( void ) { return m_loadTime; }

	inline	void	SetDuration( float duration ) { pev->dmg_take = duration; }
	inline	void	SetHoldTime( float hold ) { pev->dmg_save = hold; }
	inline	void	SetMessageTime( float time ) { m_messageTime = time; }
	inline	void	SetLoadTime( float time ) { m_loadTime = time; }

private:
	float	m_messageTime;
	float	m_loadTime;
};

LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved );

TYPEDESCRIPTION	CRevertSaved::m_SaveData[] = 
{
	DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ),	// These are not actual times, but durations, so save as floats
	DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ),
};

IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity );

void CRevertSaved :: KeyValue( KeyValueData *pkvd )
{
	if (FStrEq(pkvd->szKeyName, "duration"))
	{
		SetDuration( atof(pkvd->szValue) );
		pkvd->fHandled = TRUE;
	}
	else if (FStrEq(pkvd->szKeyName, "holdtime"))
	{
		SetHoldTime( atof(pkvd->szValue) );
		pkvd->fHandled = TRUE;
	}
	else if (FStrEq(pkvd->szKeyName, "messagetime"))
	{
		SetMessageTime( atof(pkvd->szValue) );
		pkvd->fHandled = TRUE;
	}
	else if (FStrEq(pkvd->szKeyName, "loadtime"))
	{
		SetLoadTime( atof(pkvd->szValue) );
		pkvd->fHandled = TRUE;
	}
	else 
		CPointEntity::KeyValue( pkvd );
}

void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), pev->renderamt, FFADE_OUT );
	pev->nextthink = gpGlobals->time + MessageTime();
	SetThink( &CRevertSaved::MessageThink );
}


void CRevertSaved :: MessageThink( void )
{
	UTIL_ShowMessageAll( STRING(pev->message) );
	float nextThink = LoadTime() - MessageTime();
	if ( nextThink > 0 ) 
	{
		pev->nextthink = gpGlobals->time + nextThink;
		SetThink( &CRevertSaved::LoadThink );
	}
	else
		LoadThink();
}


void CRevertSaved :: LoadThink( void )
{
	if ( !gpGlobals->deathmatch )
	{
		SERVER_COMMAND("reload\n");
	}
}


//=========================================================
// Multiplayer intermission spots.
//=========================================================
class CInfoIntermission:public CPointEntity
{
	void Spawn( void );
	void Think( void );
};

void CInfoIntermission::Spawn( void )
{
	UTIL_SetOrigin( pev, pev->origin );
	pev->solid = SOLID_NOT;
	pev->effects = EF_NODRAW;
	pev->v_angle = g_vecZero;

	pev->nextthink = gpGlobals->time + 2;// let targets spawn!

}

void CInfoIntermission::Think ( void )
{
	edict_t *pTarget;

	// find my target
	pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) );

	if ( !FNullEnt(pTarget) )
	{
		pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() );
		pev->v_angle.x = -pev->v_angle.x;
	}
}

LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission );

