//-----------------------------------------------------------------------------
//
//  $Logfile:: /EF2/Code/DLLs/game/player.cpp                                $
// $Revision:: 590                                                            $
//   $Author:: Singlis                                                        $
//     $Date:: 9/26/03 2:36p                                                  $
//
// Copyright (C) 1997 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
//
// DESCRIPTION:
// Class definition of the player.
//
#include "_pch_cpp.h"
#include "entity.h"
#include "player.h"
#include "worldspawn.h"
#include "weapon.h"
#include "trigger.h"
#include "scriptmaster.h"
#include "path.h"
#include "navigate.h"
#include "misc.h"
#include "gravpath.h"
#include "armor.h"
#include "inventoryitem.h"
#include "gibs.h"
#include "actor.h"
#include "object.h"
#include "characterstate.h"
#include "weaputils.h"
#include "mp_manager.hpp"
#include "body.h"
#include "viewthing.h"
#include "equipment.h"
#include "powerups.h"
#include "gamecmds.h"
#include "teammateroster.hpp"
#include <qcommon/gameplaymanager.h>

//Forward
//Back
//TurnRight
//TurnLeft
//Moveleft (strafe)
//Moveright (strafe)
//Moveup (Jump)
//Movedown (Duck)
//Action (Use)
//Sneak (Toggle or Momentary)
//Speed/Walk (Toggle or Momentary)
//Fire Left hand
//Fire Right hand

#define SLOPE_45_MIN    0.7071f
#define SLOPE_45_MAX    0.831f
#define SLOPE_22_MIN    SLOPE_45_MAX
#define SLOPE_22_MAX    0.95f

#define PUSH_OBJECT_DISTANCE  16.0f

#define R_ARM_NAME "Bip01 R UpperArm"
#define L_ARM_NAME "Bip01 L UpperArm"

#define MELEE_ATTACK_LEFT	(1<<0)
#define MELEE_ATTACK_RIGHT	(1<<1)

const float	standardTorsoMult = 0.75f;

const Vector power_color( 0.0f, 1.0f, 0.0f );
const Vector acolor( 1.0f, 1.0f, 1.0f );
const Vector bcolor( 0.5f, 0.0f, 0.0f );

const Vector damageNormalColor( 0.5f, 0.0f, 0.0f );
const Vector damageFireColor( 0.5f, 0.25f, 0.0f );

qboolean TryPush( int entnum, vec3_t move_origin, vec3_t move_end );

Event EV_Player_DumpState
(
	"state",
	EV_CHEAT,
	NULL,
	NULL,
	"Dumps the player's state to the console."
);
Event EV_Player_ForceTorsoState
(
	"forcetorsostate",
	EV_DEFAULT,
	"s",
	"torsostate",
	"Force the player's torso to a certain state"
);
Event EV_Player_GiveAllCheat
(
	"wuss",
	EV_CHEAT,
	NULL,
	NULL,
	"Gives player all weapons."
);
Event EV_Player_EndLevel
(
	"endlevel",
	EV_DEFAULT,
	NULL,
	NULL,
	"Called when the player gets to the end of the level."
);
Event EV_Player_DevGodCheat
(
	"god",
	EV_CHEAT,
	"I",
	"god_mode",
	"Sets the god mode cheat or toggles it."
);
Event EV_Player_DevNoTargetCheat
(
	"notarget",
	EV_CHEAT,
	NULL,
	NULL,
	"Toggles the notarget cheat."
);
Event EV_Player_DevNoClipCheat
(
	"noclip",
	EV_CHEAT,
	NULL,
	NULL,
	"Toggles the noclip cheat."
);
Event EV_Player_PrevItem
(
	"invprev",
	EV_CONSOLE,
	NULL,
	NULL,
	"Cycle to player's previous item."
);
Event EV_Player_NextItem
(
	"invnext",
	EV_CONSOLE,
	NULL,
	NULL,
	"Cycle to player's next item."
);
Event EV_Player_GiveCheat
(
	"give",
	EV_CHEAT | EV_TIKIONLY | EV_SCRIPTONLY,
	"sI",
	"name amount",
	"Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount."
);
Event EV_Player_GiveWeaponCheat
(
	"giveweapon",
	EV_CHEAT,
	"s",
	"weapon_name",
	"Gives the player the specified weapon."
);
Event EV_Player_UseItem
(
	"use",
	EV_CONSOLE,
	"sI",
	"name weapon_hand",
	"Use the specified weapon in the hand choosen (optional)."
);
Event EV_Player_GameVersion
(
	"gameversion",
	EV_CONSOLE,
	NULL,
	NULL,
	"Prints the game version."
);
Event EV_Player_Fov
(
	"fov",
	EV_CONSOLE,
	"F",
	"fov",
	"Sets the fov."
);
Event EV_Player_Dead
(
	"dead",
	EV_CODEONLY,
	NULL,
	NULL,
	"Called when the player is dead."
);
Event EV_Player_SpawnEntity
(
	"spawn",
	EV_CHEAT | EV_SCRIPTONLY,
	"sSSSSSSSS",
	"entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
	"Spawns an entity."
);
Event EV_Player_SpawnActor
(
	"actor",
	EV_CHEAT,
	"sSSSSSSSS",
	"modelname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
	"Spawns an actor."
);
Event EV_Player_Respawn
(
	"respawn",
	EV_CODEONLY,
	NULL,
	NULL,
	"Respawns the player."
);
Event EV_Player_TestThread
(
	"testthread",
	EV_CHEAT,
	"sS",
	"scriptfile label",
	"Starts the named thread at label if provided."
);
Event EV_Player_ResetState
(
	"resetstate",
	EV_CHEAT,
	NULL,
	NULL,
	"Reset the player's state table."
);
Event EV_Player_WhatIs
(
	"whatis",
	EV_CHEAT,
	"i",
	"entity_number",
	"Prints info on the specified entity."
);
Event EV_Player_ActorInfo
(
	"actorinfo",
	EV_CHEAT,
	"i",
	"actor_number",
	"Prints info on the specified actor."
);
Event EV_Player_ShowHeuristics
(
	"showheuristics",
	EV_CHEAT,
	NULL,
	NULL,
	"Shows the current heuristic numbers"
);
Event EV_Player_KillEnt
(
	"killent",
	EV_CHEAT  | EV_SCRIPTONLY,
	"i",
	"entity_number",
	"Kills the specified entity."
);
Event EV_Player_KillClass
(
	"killclass",
	EV_CHEAT  | EV_SCRIPTONLY,
	"sI",
	"classname except_entity_number",
	"Kills all of the entities in the specified class."
);
Event EV_Player_RemoveEnt
(
	"removeent",
	EV_CHEAT  | EV_SCRIPTONLY,
	"i",
	"entity_number",
	"Removes the specified entity."
);
Event EV_Player_RemoveClass
(
	"removeclass",
	EV_CHEAT  | EV_SCRIPTONLY,
	"sI",
	"classname except_entity_number",
	"Removes all of the entities in the specified class."
);
Event EV_Player_ActivateNewWeapon
(
	"activatenewweapon",
	EV_DEFAULT,
	NULL,
	NULL,
	"Active the new weapon specified by useWeapon."
);
Event EV_Player_DeactivateWeapon
(
	"deactivateweapon",
	EV_DEFAULT,
	"s",
	"side",
	"Deactivate the weapon in the specified hand."
);
Event EV_Player_Jump
(
	"jump",
	EV_TIKIONLY,
	"f",
	"height",
	"Makes the player jump."
);
Event EV_Player_AnimLoop_Torso
(
	"animloop_torso",
	EV_CODEONLY,
	NULL,
	NULL,
	"Called when the torso animation has finished."
);
Event EV_Player_AnimLoop_Legs
(
	"animloop_legs",
	EV_CODEONLY,
	NULL,
	NULL,
	"Called when the legs animation has finished."
);
Event EV_Player_DoUse
(
	"usestuff",
	EV_DEFAULT,
	"E",
	"usingEntity",
	"Makes the player try to use whatever is in front of her."
);
Event EV_Player_SetHeadTarget
(
	"headtarget",
	EV_CONSOLE,
	NULL,
	NULL,
	"Sets the Makes the player try to use whatever is in front of her."
);
Event EV_Player_ListInventory
(
	"listinventory",
	EV_CONSOLE,
	NULL,
	NULL,
	"List of the player's inventory."
);
Event EV_Player_ClearTarget
(
	"cleartarget",
	EV_DEFAULT,
	NULL,
	NULL,
	"Clears the target of the player"
);
Event EV_Player_ActivateShield
(
	"activateshield",
	EV_DEFAULT,
	NULL,
	NULL,
	"Activates the player's shield"
);
Event EV_Player_DeactivateShield
(
	"deactivateshield",
	EV_DEFAULT,
	NULL,
	NULL,
	"Deactivates the player's shield"
);
Event EV_Player_AdjustTorso
(
	"adjust_torso",
	EV_DEFAULT,
	"b",
	"boolean",
	"Turn or off the torso adjustment"
);
Event EV_Player_DualWield
(
	"dualwield",
	EV_CONSOLE,
	"ss",
	"weaponleft weaponright",
	"Dual wield the specified weapons"
);
Event EV_Player_UseDualWield
(
	"usedualwield",
	EV_CONSOLE,
	NULL,
	NULL,
	"Use the weapons that are on the dual wield list"
);
Event EV_Player_EvaluateTorsoAnim
(
	"evaluatetorsoanim",
	EV_CONSOLE,
	NULL,
	NULL,
	"Evaluate the torso anim for possible changes"
);
Event EV_Player_Turn
(
	"turn",
	EV_SCRIPTONLY,
	"fF",
	"yawangle time",
	"Causes player to turn the specified amount."
);
Event EV_Player_TurnTowardsEntity
(
	"turnTowardsEntity",
	EV_SCRIPTONLY,
	"e",
	"entity",
	"Causes the player to turn towards the specified entity."
);
Event EV_Player_TurnUpdate
(
	"turnupdate",
	EV_SCRIPTONLY,
	"ff",
	"yaw timeleft",
	"Causes player to turn the specified amount."
);
Event EV_Player_TurnLegs
(
	"turnlegs",
	EV_SCRIPTONLY,
	"f",
	"yawangle",
	"Turns the players legs instantly by the specified amount."
);
Event EV_Player_DontTurnLegs
(
	"dontturnlegs",
	EV_CODEONLY,
	"b",
	"flag",
	"Specifies whether or not to turn the legs while strafing."
);
Event EV_Player_NextPainTime
(
	"nextpaintime",
	EV_CODEONLY,
	"f",
	"seconds",
	"Set the next time the player experiences pain (Current time + seconds specified)."
);
Event EV_Player_FinishUseAnim
(
	"finishuseanim",
	EV_DEFAULT,
	NULL,
	NULL,
	"Fires off all targets associated with a particular useanim."
);
Event EV_Player_Nightvision
(
	"nightvision",
	EV_CODEONLY | EV_CONSOLE,
	NULL,
	NULL,
	"Toggles player nightvision mode"
);
Event EV_Player_Holster
(
	"holster",
	EV_SCRIPTONLY,
	NULL,
	NULL,
	"Holsters all wielded weapons, or unholsters previously put away weapons"
);
Event EV_Player_SafeHolster
(
	"safeholster",
	EV_SCRIPTONLY,
	"b",
	"putaway",
	"Holsters all wielded weapons, or unholsters previously put away weapons\n"
	"preserves state, so it will not holster or unholster unless necessary"
);
Event EV_Player_StartUseObject
(
	"startuseobject",
	EV_DEFAULT,
	NULL,
	NULL,
	"starts up the useobject's animations."
);
Event EV_Player_FinishUseObject
(
	"finishuseobject",
	EV_DEFAULT,
	NULL,
	NULL,
	"Fires off all targets associated with a particular useobject."
);
Event EV_Player_WatchActor
(
	"watchactor",
	EV_SCRIPTONLY,
	"eFFB",
	"entity_to_watch time angle watchEntireDuration",
	"Makes the player's camera watch the specified entity."
);
Event EV_Player_WatchEntity
(
	"watchentity",
	EV_SCRIPTONLY,
	"eFFB",
	"entityToWatch time angle watchEntireDuration",
	"Makes the player's camera watch the specified entity."
);
Event EV_Player_StopWatchingEntity
(
	"stopwatchingactor",
	EV_SCRIPTONLY,
	"e",
	"entity_to_stop_watching",
	"Makes the player's camera stop watching the specified entity."
);
Event EV_Player_PutawayWeapon
(
	"putawayweapon",
	EV_DEFAULT,
	"s",
	"whichHand",
	"Put away or deactivate the current weapon, whichHand can be left, right or dual."
);
Event EV_Player_Weapon
(
	"weaponcommand",
	EV_CODEONLY,
	"sSSSSSSS",
	"hand arg1 arg2 arg3 arg4 arg5 arg6 arg7",
	"Pass the args to the active weapon in the specified hand"
);
Event EV_Player_Done
(
	"playerdone",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears the waitForPlayer script command, allowing threads to run"
);
Event EV_Player_ActivateDualWeapons
(
	"activatedualweapons",
	EV_DEFAULT,
	NULL,
	NULL,
	"Activates 2 weapons at once"
);
Event EV_Player_StartCoolItem
(
	"startcoolitem",
	EV_CODEONLY,
	NULL,
	NULL,
	"Player is starting to show off the cool item"
);
Event EV_Player_StopCoolItem
(
	"stopcoolitem",
	EV_CODEONLY,
	NULL,
	NULL,
	"Player is starting to show off the cool item"
);
Event EV_Player_ShowCoolItem
(
	"showcoolitem",
	EV_CODEONLY,
	NULL,
	NULL,
	"Player is showing the cool item, actually display it"
);
Event EV_Player_HideCoolItem
(
	"hidecoolitem",
	EV_CODEONLY,
	NULL,
	NULL,
	"Player is finished showing the cool item, now hide it"
);
Event EV_Player_SetDamageMultiplier
(
	"damage_multiplier",
	EV_SCRIPTONLY,
	"f",
	"damage_multiplier",
	"Sets the current damage multiplier"
);
Event EV_Player_WaitForState
(
	"waitForState",
	EV_SCRIPTONLY,
	"s",
	"stateToWaitFor",
	"When set, the player will clear waitforplayer when this state is hit\n"
	"in the legs or torso."
);
Event EV_Player_LogStats
(
	"logstats",
	EV_CHEAT,
	"b",
	"state",
	"Turn on/off the debugging playlog"
);
Event EV_Player_TakePain
(
	"takepain",
	EV_DEFAULT,
	"b",
	"bool",
	"Set whether or not to take pain"
);
Event EV_Player_SkipCinematic
(
	"skipcinematic",
	EV_CONSOLE,
	NULL,
	NULL,
	"Skip the current cinematic"
);
Event EV_Player_ResetHaveItem
(
	"resethaveitem",
	EV_CONSOLE,
	"s",
	"weapon_name",
	"Resets the game var that keeps track that we have gotten this weapon"
);
Event EV_Player_Score
(
	"score",
	EV_CONSOLE,
	NULL,
	NULL,
	"Show the score for the current deathmatch game"
);
Event EV_Player_CallVote
(
	"callvote",
	EV_CONSOLE,
	"sS",
	"arg1 arg2",
	"Player calls a vote"
);
Event EV_Player_Vote
(
	"vote",
	EV_CONSOLE,
	"s",
	"arg1",
	"Player votes either yes or no"
);
Event EV_Player_JoinTeam
(
	"joinmpteam",
	EV_CONSOLE,
	"s",
	"teamName",
	"Makes the player join the specified team."
);
Event EV_Player_MultiplayerCommand
(
	"mpCmd",
	EV_CONSOLE,
	"ss",
	"command parm",
	"Sends a command from the player to the multiplayer system."
);
Event EV_Player_DeadBody
(
	"deadbody",
	EV_CODEONLY,
	NULL,
	NULL,
	"Spawn a dead body"
);
Event EV_Player_SetAimType
(
	"setaim",
	EV_DEFAULT,
	"s",
	"aimtype",
	"Sets the accuracy modifiers for the player"
);
Event EV_Player_ReloadWeapon
(
	"forcereload",
	EV_TIKIONLY,
	NULL,
	NULL,
	"Tells the weapon to reload"
);
Event EV_Player_AnimateWeapon
(
	"animateweapon",
	EV_DEFAULT,
	"sSB",
	"anim hand animatingFlag",
	"Animates the weapon, optionally, in the specific hand (defaults to DUAL)"
	"If the animatingFlag is set to false, it will not set the WEAPON_ANIMATING"
	"as the status for this animation."
);
Event EV_Player_SwitchWeaponMode
(
	"switchmode",
	EV_TIKIONLY,
	NULL,
	NULL,
	"Tells the weapon to switch modes of fire"
);
Event EV_Player_ReloadTiki
(
	"reloadviewtiki",
	EV_CHEAT,
	"s",
	"tikiname",
	"Reloads the specified TIKI file from disk"
);
Event EV_Player_SetViewAngles
(
	"playerviewangles",
	EV_CHEAT,
	"v[0,360][0,360][0,360]",
	"newAngles",
	"set the angles of the player to newAngles."
 );
Event EV_Player_ProjDetonate
(
	"projdetonate",
	EV_CODEONLY,
	"b",
	"detonate",
	"Event that sets the whether or not to detonate a trigger projectile (grenade launcher)"
);
Event EV_Player_UseEntity
(
	"useentity",
	EV_DEFAULT,
	"e",
	"entity",
	"makes player use the passed in entity"
);
Event EV_Player_SetupDialog
(
	"setupdialog",
	EV_CODEONLY,
	"is",
	"entnum soundname",
	"Sets up the dialog for the player"
);
Event EV_Player_ClearDialog
(
	"cleardialog",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears the dialog for the player"
);

Event EV_Player_ClearTextDialog
(
	"cleartextdialog",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears the text dialog of the player"
);

//
// Objective Events
//
Event EV_Player_LoadObjectives
(
	"loadobjectives",
	EV_SCRIPTONLY,
	"s",
	"name",
	"Loads the a set of objectives"
);
Event EV_Player_SetObjectiveShow
(
	"setobjectiveshow",
	EV_SCRIPTONLY,
	"sb",
	"name show",
	"Sets whether or not a specified objective is shown"
);
Event EV_Player_SetObjectiveComplete
(
	"setobjectivecomplete",
	EV_SCRIPTONLY,
	"sb",
	"name complete",
	"Sets whether or not a specified objective is complete"
);
Event EV_Player_SetObjectiveFailed
(
	"setobjectivefailed",
	EV_SCRIPTONLY,
	"sb",
	"name failed",
	"Sets whether or not a specified objective is failed"
);

//
// Information Events
//
Event EV_Player_SetInformationShow
(
	"setinformationshow",
	EV_SCRIPTONLY,
	"sb",
	"name show",
	"Sets whether or not a specified information is shown"
);
Event EV_Player_MissionFailed
(
	"missionfailed",
	EV_SCRIPTONLY,
	"S",
	"reason",
	"Displays the mission failed screen on the client side"
);
Event EV_Player_SetStat
(
	"setstat",
	EV_SCRIPTONLY,
	"si",
	"stat_name stat_value",
	"Sets a stat value"
);
Event EV_Player_SpecialMoveChargeStart
(
	"specialmovestart",
	EV_CODEONLY,
	NULL,
	NULL,
	"Starts charging up for a special move"
);
Event EV_Player_SpecialMoveChargeEnd
(
	"specialmoveend",
	EV_CODEONLY,
	NULL,
	NULL,
	"Ends charging up for a special move"
);
Event EV_Player_SpecialMoveChargeTime
(
	"specialmovetime",
	EV_CODEONLY,
	"f",
	"time",
	"Sets how long to wait before triggering the special move."
);
Event EV_Player_ChangeChar
(
	"changechar",
	EV_SCRIPTONLY,
	"ssss",
	"statefile model replacemodelName spawnNPC",
	"Changes the character state and model."
);
Event EV_Player_SetPlayerCharacter
(
	"setplayerchar",
	EV_SCRIPTONLY,
	"ss",
	"statefile model",
	"Sets the player character."
);
Event EV_Player_PlayerKnockback
(
	"playerknockback",
	EV_CODEONLY,
	"f",
	"knockback",
	"Sets knockback for the player"
);
Event EV_Player_KnockbackMultiplier
(
	"knockbackmultiplier",
	EV_CODEONLY,
	"i",
	"knockbackmult",
	"Sets knockback multiplierfor the player"
);
Event EV_Player_Melee
(
	"melee",
	EV_DEFAULT,
	"FSF",
	"damage means_of_death knockback",
	"Makes the player do a weapon-less melee attack. "
);
Event EV_Player_ChangeStance
(
	"stance",
	EV_CONSOLE,
	"i",
	"stanceNumber",
	"Makes the player change to the specified stance"
);
Event EV_Player_ClearStanceTorso
(
	"clearstancetorso",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears internal torso stance data."
);
Event EV_Player_ClearStanceLegs
(
	"clearstancelegs",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears internal legs stance data."
);
Event EV_Player_GivePoints
(
	"givepoints",
	EV_SCRIPTONLY,
	"i",
	"points",
	"Gives the player points (added to current points)"
);
Event EV_Player_SetPoints
(
	"setpoints",
	EV_SCRIPTONLY,
	"i",
	"points",
	"Sets the players number of points."
);
Event EV_Player_ChangeCharFadeIn
(
	"changecharfadein",
	EV_CODEONLY,
	NULL,
	NULL,
	"Begins the fade in and swaps character."
);
Event EV_Player_ClearIncomingMelee
(
	"clearincomingmelee",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears the incoming melee flag."
);
Event EV_Player_BendTorso
(
	"bendtorso",
	EV_DEFAULT,
	"F",
	"multiplier",
	"Sets multiplier for the torso bend angles, defaults to 0.75"
);
Event EV_Player_RemovePowerup
(
	"removepowerup",
	EV_CODEONLY,
	NULL,
	NULL,
	"Removes the current powerup."
);
Event EV_Player_DropRune
(
	"droprune",
	EV_CODEONLY,
	NULL,
	NULL,
	"Drops the player's current rune."
);
Event EV_Player_SetCanTransferEnergy
(
	"canTransferEnergy",
	EV_DEFAULT,
	NULL,
	NULL,
	"Makes the player able to transfer energy from ammo to armor."
);
Event EV_Player_SetDoDamageScreenFlash
(
	"doDamageScreenFlash",
	EV_DEFAULT,
	"B",
	"bool",
	"Makes the screen flash when the player is damaged (or turns it off)."
);
Event EV_Player_MeleeDamageStart
(
	"meleedamagestart",
	EV_DEFAULT,
	"S",
	"hand",
	"Start doing melee damage with the weapon in the specified hand."
);
Event EV_Player_MeleeDamageEnd
(
	"meleedamageend",
	EV_DEFAULT,
	"S",
	"hand",
	"Stop doing melee damage with the weapon in the specified hand."
);
Event EV_Player_PointofView
(
	"pointofview",
	EV_DEFAULT,
	NULL,
	NULL,
	"Changes the viewpoint of the player, alternates between 1st and 3rd person"
);
Event EV_Player_FinishingMove
(
	"finishingmove",
	EV_TIKIONLY,
	"ssFFFF",
	"state direction coneangle distance enemyyaw chance",
	"Changes the viewpoint of the player, alternates between 1st and 3rd person"
);
Event EV_Player_ClearFinishingMove
(
	"clearfinishingmovelist",
	EV_DEFAULT,
	NULL,
	NULL,
	"Clears the finishing move list."
);
Event EV_Player_DoFinishingMove
(
	"dofinishingmove",
	EV_DEFAULT,
	NULL,
	NULL,
	"Fires off the finishing move."
);
Event EV_Player_ForceTimeScale
(
	"forcetimescale",
	EV_DEFAULT,
	"F",
	"timescale",
	"Sets the timescale for the game"
);
Event EV_Player_Freeze
(
	"freeze",
	EV_DEFAULT,
	"B",
	"freeze",
	"Freezes the player until the freeze 0 is called"
);
Event EV_Player_Immobilize
(
	"immobilize",
	EV_DEFAULT,
	"B",
	"immobilize",
	"Immobilizes the player until the immobilize 0 is called (can only look around)"
);
Event EV_Player_DoUseEntity
(
	"douseentity",
	EV_DEFAULT,
	NULL,
	NULL,
	"Called from the tiki on a frame to use an entity."
);
Event EV_Player_DoneUseEntity
(
	"doneuseentity",
	EV_DEFAULT,
	NULL,
	NULL,
	"When the useentity animation is complete"
);
Event EV_Player_SetAttackType
(
	"attacktype",
	EV_DEFAULT,
	"s",
	"attacktype",
	"Sets the attack type of the attack"
);
Event EV_Player_NextGameplayAnim
(
	"nextgameplayanim",
	EV_CODEONLY,
	"s",
	"objname",
	"Increments the gameplay animation index."
);
Event EV_Player_SetGameplayAnim
(
	"setgameplayanim",
	EV_CODEONLY,
	"I",
	"index",
	"Sets the gameplay animation index directly."
);
Event EV_Player_DisableUseWeapon
(
	"disableuseweapon",
	EV_DEFAULT,
	"B",
	"disable",
	"Disables the weapon use"
);
Event EV_Player_DisableInventory
(
	"disableinventory",
	EV_DEFAULT,
	"f",
	"disable",
	"Disables the player's inventory"
);

Event EV_Player_EquipItems
(
	"equipitems",
	EV_DEFAULT,
	NULL,
	NULL,
	"Equips active items from the database."
);
Event EV_Player_AddRosterTeammate1
(
	"addrosterteammate1",
	EV_DEFAULT,
	"e",
	"entity",
	"Sets the teammate to roster position 1"
);
Event EV_Player_AddRosterTeammate2
(
	"addrosterteammate2",
	EV_DEFAULT,
	"e",
	"entity",
	"Sets the teammate to roster position 2"
);
Event EV_Player_AddRosterTeammate3
(
	"addrosterteammate3",
	EV_DEFAULT,
	"e",
	"entity",
	"Sets the teammate to roster position 3"
);
Event EV_Player_AddRosterTeammate4
(
	"addrosterteammate4",
	EV_DEFAULT,
	"e",
	"entity",
	"Sets the actor to roster position 4"
);
Event EV_Player_RemoveRosterTeammate1
(
	"removerosterteammate1",
	EV_DEFAULT,
	NULL,
	NULL,
	"Removed the teammate from roster position 1"
);
Event EV_Player_RemoveRosterTeammate2
(
	"removerosterteammate2",
	EV_DEFAULT,
	NULL,
	NULL,
	"Removed the teammate from roster position 2"
);
Event EV_Player_RemoveRosterTeammate3
(
	"removerosterteammate3",
	EV_DEFAULT,
	NULL,
	NULL,
	"Removed the teammate from roster position 3"
);
Event EV_Player_RemoveRosterTeammate4
(
	"removerosterteammate4",
	EV_DEFAULT,
	NULL,
	NULL,
	"Removed the teammate from roster position 4"
);

Event EV_Player_HudPrint
(
	"hudPrint",
	EV_DEFAULT,
	"s",
	"string",
	"Prints to the hud."
);
Event EV_Player_ClearItemText
(
	"clearItemText",
	EV_CODEONLY,
	NULL,
	NULL,
	"Clears the item text."
);
Event EV_Player_ValidPlayerModel
(
	"validPlayerModel",
	EV_TIKIONLY,
	NULL,
	NULL,
	"Specifies that this model is valid for the player."
);
Event EV_Player_AddHud
(
	"addHud",
	EV_SCRIPTONLY,
	"s",
	"hudName",
	"Tells the player to add a hud to his display."
);
Event EV_Player_RemoveHud
(
	"removeHud",
	EV_SCRIPTONLY,
	"s",
	"hudName",
	"Tells the player to remove a hud from his display."
);

Event EV_Player_KillAllDialog
(
	"killalldialog",
	EV_DEFAULT,
	NULL,
	NULL,
	"Calls stopdialog on all the actors in the level"
);
Event EV_Player_ForceMoveType
(
	"forceMoveType",
	EV_DEFAULT,
	"s",
	"moveTypeName",
	"Forces the player to use the named move type"
);
Event EV_Player_IsOnGround
(
	"isplayeronground",
	EV_DEFAULT,
	"@f",
	"onground",
	"Checks if the player is on the ground -- returns 1 if true 0 if false"
);
Event EV_Player_BackpackAttachOffset
(
	"backpackAttachOffset",
	EV_DEFAULT,
	"v",
	"offset",
	"Sets the attachment offset for backpacks"
);
Event EV_Player_BackpackAttachAngles
(
	"backpackAttachAngles",
	EV_DEFAULT,
	"v",
	"anglesOffset",
	"Sets the attachment angles offset for backpacks"
);
Event EV_Player_FlagAttachOffset
(
	"flagAttachOffset",
	EV_DEFAULT,
	"v",
	"offset",
	"Sets the attachment offset for flags"
);
Event EV_Player_FlagAttachAngles
(
	"flagAttachAngles",
	EV_DEFAULT,
	"v",
	"anglesOffset",
	"Sets the attachment angles offset for flags"
);
Event EV_Player_BackupModel
(
	"backupModel",
	EV_DEFAULT,
	"s",
	"backupModelName",
	"Sets the name of the model to use as backup if the client doesn't have this one"
);

/*
==============================================================================

PLAYER

==============================================================================
*/

CLASS_DECLARATION( Sentient, Player, "player" )
{
	{ &EV_ClientMove,										&Player::ClientThink },
	{ &EV_ClientEndFrame,									&Player::EndFrame },
	{ &EV_Vehicle_Enter,									&Player::EnterVehicle },
	{ &EV_Vehicle_Exit,										&Player::ExitVehicle },
	{ &EV_Player_EndLevel,									&Player::EndLevel },
	{ &EV_Player_UseItem,									&Player::EventUseItem },
	{ &EV_Player_GiveCheat,									&Player::GiveCheat },
	{ &EV_Player_GiveWeaponCheat,							&Player::GiveWeaponCheat },
	{ &EV_Player_GiveAllCheat,								&Player::GiveAllCheat },
	{ &EV_Player_DevGodCheat,								&Player::GodCheat },
	{ &EV_Player_DevNoTargetCheat,							&Player::NoTargetCheat },
	{ &EV_Player_DevNoClipCheat,							&Player::NoclipCheat },
	{ &EV_Player_GameVersion,								&Player::GameVersion },
	{ &EV_Player_DumpState,	    							&Player::DumpState },
	{ &EV_Player_ForceTorsoState,							&Player::ForceTorsoState },
	{ &EV_Player_Fov,										&Player::Fov },
	{ &EV_Kill,												&Player::Kill },
	{ &EV_Player_Dead,										&Player::Dead },
	{ &EV_Player_SpawnEntity,								&Player::SpawnEntity },
	{ &EV_Player_SpawnActor,								&Player::SpawnActor },
	{ &EV_Player_Respawn,									&Player::Respawn },
	{ &EV_Player_DoUse,										&Player::DoUse },
	{ &EV_Pain,												&Player::Pain },
	{ &EV_Killed,											&Player::Killed },
	{ &EV_Gib,												&Player::GibEvent },
	{ &EV_GotKill,											&Player::GotKill },
	{ &EV_Player_TestThread,								&Player::TestThread },
	{ &EV_Player_ResetState,								&Player::ResetState },
	{ &EV_Player_WhatIs,									&Player::WhatIs },
	{ &EV_Player_ActorInfo,									&Player::ActorInfo },
	{ &EV_Player_ShowHeuristics,							&Player::ShowHeuristics	},
	{ &EV_Player_KillEnt,									&Player::KillEnt },
	{ &EV_Player_RemoveEnt,									&Player::RemoveEnt },
	{ &EV_Player_KillClass,									&Player::KillClass },
	{ &EV_Player_RemoveClass,								&Player::RemoveClass },
	{ &EV_Player_AnimLoop_Legs,								&Player::EndAnim_Legs },
	{ &EV_Player_AnimLoop_Torso,							&Player::EndAnim_Torso },
	{ &EV_Player_Jump,               						&Player::Jump },
	{ &EV_Sentient_JumpXY,									&Player::JumpXY },
	{ &EV_Player_ActivateNewWeapon,							&Player::ActivateNewWeapon },
	{ &EV_Player_DeactivateWeapon,							&Player::DeactivateWeapon },
	{ &EV_Player_SetHeadTarget,								&Player::SetHeadTarget },
	{ &EV_Player_ListInventory,								&Player::ListInventoryEvent },
	{ &EV_Player_ClearTarget,								&Player::ClearTarget },
	{ &EV_Player_ActivateShield,							&Player::ActivateShield },
	{ &EV_Player_DeactivateShield,							&Player::DeactivateShield },
	{ &EV_Player_AdjustTorso,								&Player::AdjustTorso },
	{ &EV_Player_DualWield,									&Player::DualWield },
	{ &EV_Player_UseDualWield,								&Player::UseDualWield },
	{ &EV_Player_EvaluateTorsoAnim,							&Player::EvaluateTorsoAnim },
	{ &EV_Player_NextPainTime,								&Player::NextPainTime },
	{ &EV_Player_Turn,										&Player::Turn },
	{ &EV_Player_TurnTowardsEntity,							&Player::turnTowardsEntity },
	{ &EV_Player_TurnUpdate,								&Player::TurnUpdate },
	{ &EV_Player_TurnLegs,									&Player::TurnLegs },
	{ &EV_Player_DontTurnLegs,								&Player::DontTurnLegs },
	{ &EV_Player_FinishUseAnim,								&Player::FinishUseAnim },
	{ &EV_Sentient_SetMouthAngle,							&Player::SetMouthAngle },
	{ &EV_Player_Holster,									&Player::HolsterToggle },
	{ &EV_Player_Nightvision,								&Player::NightvisionToggle },
	{ &EV_Player_SafeHolster,								&Player::Holster },
	{ &EV_Player_StartUseObject,							&Player::StartUseObject },
	{ &EV_Player_FinishUseObject,							&Player::FinishUseObject },
	{ &EV_Player_WatchActor,								&Player::WatchEntity },
	{ &EV_Player_WatchEntity,								&Player::WatchEntity },
	{ &EV_Player_StopWatchingEntity,						&Player::StopWatchingEntity },
	{ &EV_Player_PutawayWeapon,								&Player::PutawayWeapon },
	{ &EV_Player_Weapon,									&Player::WeaponCommand },
	{ &EV_Player_Done,										&Player::PlayerDone },
	{ &EV_Player_ActivateDualWeapons,						&Player::ActivateDualWeapons },
	{ &EV_Player_StartCoolItem,								&Player::StartCoolItem },
	{ &EV_Player_StopCoolItem,								&Player::StopCoolItem },
	{ &EV_Player_ShowCoolItem,								&Player::ShowCoolItem },
	{ &EV_Player_HideCoolItem,								&Player::HideCoolItem },
	{ &EV_Player_SetDamageMultiplier,						&Player::SetDamageMultiplier },
	{ &EV_Player_WaitForState,								&Player::WaitForState },
	{ &EV_Player_LogStats,									&Player::LogStats },
	{ &EV_Player_TakePain,									&Player::SetTakePain },
	{ &EV_Player_SkipCinematic,								&Player::SkipCinematic },
	{ &EV_Player_ResetHaveItem,								&Player::ResetHaveItem },
	{ &EV_Show,												&Player::PlayerShowModel },
	{ &EV_Player_Score,										&Player::Score },
	{ &EV_Player_CallVote,									&Player::CallVote },
	{ &EV_Player_Vote,										&Player::Vote },
	{ &EV_Player_JoinTeam,									&Player::joinTeam },
	{ &EV_Player_MultiplayerCommand,						&Player::multiplayerCommand },
	{ &EV_Player_DeadBody,									&Player::DeadBody },
	{ &EV_Player_SetAimType,								&Player::SetAimType },
	{ &EV_Player_ReloadWeapon,								&Player::ReloadWeapon },
	{ &EV_Player_AnimateWeapon,								&Player::AnimateWeapon },	
	{ &EV_Player_SwitchWeaponMode,							&Player::SwitchWeaponMode },
	{ &EV_Player_ReloadTiki,								&Player::ReloadTiki },
	{ &EV_Player_SetViewAngles,								&Player::SetViewAnglesEvent },
	{ &EV_Player_ProjDetonate,								&Player::ProjDetonate },
	{ &EV_Player_UseEntity,									&Player::UseSpecifiedEntity },
	{ &EV_Player_SetupDialog,								&Player::SetupDialog },
	{ &EV_Player_ClearDialog,								&Player::ClearDialog },
	{ &EV_Player_ClearTextDialog,							&Player::ClearTextDialog },
	{ &EV_Player_LoadObjectives,							&Player::LoadObjectives },
	{ &EV_Player_SetObjectiveShow,							&Player::SetObjectiveShow },
	{ &EV_Player_SetObjectiveComplete,						&Player::SetObjectiveComplete },
	{ &EV_Player_SetObjectiveFailed,						&Player::SetObjectiveFailed },
	{ &EV_Player_SetInformationShow,						&Player::SetInformationShow },
	{ &EV_Player_MissionFailed,								&Player::MissionFailed },
	   
	{ &EV_Player_SetStat,									&Player::SetStat },
	{ &EV_Player_SpecialMoveChargeStart,					&Player::SpecialMoveChargeStart },
	{ &EV_Player_SpecialMoveChargeEnd,						&Player::SpecialMoveChargeEnd },
	{ &EV_Player_SpecialMoveChargeTime,						&Player::SpecialMoveChargeTime },
	{ &EV_Player_ChangeChar,								&Player::ChangeChar },
	{ &EV_Player_SetPlayerCharacter,						&Player::SetPlayerChar },
	{ &EV_Player_PlayerKnockback,							&Player::PlayerKnockback },
	{ &EV_Player_KnockbackMultiplier,						&Player::KnockbackMultiplier },
	{ &EV_Player_Melee,										&Player::MeleeEvent },
	{ &EV_Player_ChangeStance,								&Player::ChangeStance },
	{ &EV_Player_ClearStanceTorso,							&Player::ClearStanceTorso },
	{ &EV_Player_ClearStanceLegs,							&Player::ClearStanceLegs },
	   
	{ &EV_Player_MeleeDamageStart,							&Player::MeleeDamageStart },
	{ &EV_Player_MeleeDamageEnd,							&Player::MeleeDamageEnd },
	{ &EV_Player_GivePoints,								&Player::GivePointsEvent },
	{ &EV_Player_SetPoints,									&Player::SetPointsEvent },
	{ &EV_Player_ChangeCharFadeIn,							&Player::ChangeCharFadeIn },
	{ &EV_Player_ClearIncomingMelee,						&Player::ClearIncomingMelee },
	{ &EV_Player_BendTorso,									&Player::SetBendTorso },
	{ &EV_Sentient_HeadWatchAllowed,						&Player::HeadWatchAllowed },
	   
	{ &EV_Player_RemovePowerup,								&Player::removePowerupEvent },
	{ &EV_Player_DropRune,									&Player::dropRune },
	{ &EV_Sentient_AddMeleeAttacker,						&Player::AddMeleeAttacker },
	   
	{ &EV_Player_SetCanTransferEnergy,						&Player::setCanTransferEnergy },
	{ &EV_Player_SetDoDamageScreenFlash,					&Player::setDoDamageScreenFlash },
	{ &EV_Player_PointofView,								&Player::pointOfView },
	{ &EV_Player_FinishingMove,								&Player::addFinishingMove },
	{ &EV_Player_ClearFinishingMove,						&Player::clearFinishingMove },
	{ &EV_Player_DoFinishingMove,							&Player::doFinishingMove },
	{ &EV_Player_ForceTimeScale,							&Player::forceTimeScale },
	{ &EV_Player_Freeze,									&Player::freezePlayer },
	{ &EV_Player_Immobilize,								&Player::immobilizePlayer },
	{ &EV_Player_DoUseEntity,								&Player::doUseEntity },
	{ &EV_Player_DoneUseEntity,								&Player::doneUseEntity },
	{ &EV_Player_SetAttackType,								&Player::setAttackType },
	{ &EV_Player_NextGameplayAnim,							&Player::nextGameplayAnim },
	{ &EV_Player_SetGameplayAnim,							&Player::setGameplayAnim },
	{ &EV_Player_DisableUseWeapon,							&Player::setDisableUseWeapon },
	{ &EV_Player_DisableInventory,							&Player::setDisableInventory },
	{ &EV_Player_EquipItems,								&Player::equipItems },
	   
	{ &EV_Use,												&Player::usePlayer },
	   
	{ &EV_Player_AddRosterTeammate1,						&Player::addRosterTeammate1 },
	{ &EV_Player_AddRosterTeammate2,						&Player::addRosterTeammate2 },
	{ &EV_Player_AddRosterTeammate3,						&Player::addRosterTeammate3 },
	{ &EV_Player_AddRosterTeammate4,						&Player::addRosterTeammate4 },
	   
	{ &EV_Player_RemoveRosterTeammate1,						&Player::removeRosterTeammate1 },
	{ &EV_Player_RemoveRosterTeammate2,						&Player::removeRosterTeammate2 },
	{ &EV_Player_RemoveRosterTeammate3,						&Player::removeRosterTeammate3 },
	{ &EV_Player_RemoveRosterTeammate4,						&Player::removeRosterTeammate4 },

	{ &EV_Player_HudPrint,									&Player::hudPrint },

	{ &EV_Player_ClearItemText,								&Player::clearItemText },

	{ &EV_Player_ValidPlayerModel,							&Player::setValidPlayerModel },

	{ &EV_Player_AddHud,									&Player::addHud },
	{ &EV_Player_RemoveHud,									&Player::removeHud },
		   
	//Vehicle Event Handoff
	{ &EV_Driver_AnimDone,									&Player::PassEventToVehicle },

	{ &EV_Warp,												&Player::warp },
	{ &EV_Player_KillAllDialog,								&Player::killAllDialog	},

	{ &EV_Player_ForceMoveType,								&Player::forceMoveType },
	{ &EV_Player_IsOnGround,								&Player::isPlayerOnGround },

	{ &EV_Player_BackpackAttachOffset,						&Player::setBackpackAttachOffset },
	{ &EV_Player_BackpackAttachAngles,						&Player::setBackpackAttachAngles },

	{ &EV_Player_FlagAttachOffset,							&Player::setFlagAttachOffset },
	{ &EV_Player_FlagAttachAngles,							&Player::setFlagAttachAngles },
	
	{ &EV_Player_BackupModel,								&Player::setBackupModel },
	{ NULL, NULL }
};

qboolean Player::checkturnleft( Conditional &condition )
{
	float yaw;
	
	yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] );
	
	return ( angledist( old_v_angle[ YAW ] - yaw ) < -8.0f );
}

qboolean Player::checkturnright( Conditional &condition )
{
	float yaw;
	
	yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] );
	
	return ( angledist( old_v_angle[ YAW ] - yaw ) > 8.0f );
}

qboolean Player::checkforward( Conditional &condition )
{
	return last_ucmd.forwardmove > 0;
}

qboolean Player::checkbackward( Conditional &condition )
{
	return last_ucmd.forwardmove < 0;
}

qboolean Player::checkstrafeleft( Conditional &condition )
{
	return last_ucmd.rightmove < 0;
}

qboolean Player::checkstraferight( Conditional &condition )
{
	return last_ucmd.rightmove > 0;
}

qboolean Player::checkleanleft(Conditional &condition)
{
	if( client->ps.leanDelta > 0 )
	{
		return qtrue;
	}
	
	return qfalse;
}

qboolean Player::checkleanright( Conditional &condition )
{
	
	if(client->ps.leanDelta < 0)
	{
		return qtrue;
	}
	
	return qfalse;
}

qboolean Player::checkduck( Conditional &condition )
{
	if ( client->ps.pm_flags & PMF_DUCKED )
		return qtrue;
	else
		return qfalse;
}

qboolean Player::checkrise( Conditional &condition )
{
	if ( ( do_rise ) && ( velocity.z > 32.0f ) )
	{
		return qtrue;
	}
	do_rise = qfalse;
	
	return qfalse;
}

qboolean Player::checkjump( Conditional &condition )
{
	if ( sv_instantjump->integer )
		return client->ps.jumped;
	else
		return last_ucmd.upmove > 0;
}

qboolean Player::checkcrouch( Conditional &condition )
{
	if ( last_ucmd.upmove < 0 ) // check for downward movement
		return qtrue;
	
	return qfalse;
}

qboolean Player::checkjumpflip( Conditional &condition )
{
	return velocity.z < ( sv_currentGravity->value * 0.5f );
}

qboolean Player::checkanimdone_legs( Conditional &condition )
{
	if ( ( edict->s.anim & ANIM_BLEND ) == 0 )
		return true;
	
	return animdone_Legs;
}

qboolean Player::checkanimdone_torso( Conditional &condition )
{
	if ( ( edict->s.torso_anim & ANIM_BLEND ) == 0 )
		return true;

	return animdone_Torso;
}

qboolean Player::checkattackleft( Conditional &condition )
{
	if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
	{
		return qfalse;
	}
	
	if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
	{
		return qfalse;
	}
	
	// Make sure we aren't leaning
	
	if ( client->ps.leanDelta != 0 )
		return false;
	
	if ( last_ucmd.buttons & BUTTON_ATTACKLEFT )
	{
		Weapon *weapon;
		
		last_attack_button = BUTTON_ATTACKLEFT;
		
		weapon = GetActiveWeapon( WEAPON_LEFT );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE1 );
			return qtrue;
		}
		
		weapon = GetActiveWeapon( WEAPON_RIGHT );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE1 );
			return qtrue;
		}
		
		weapon = GetActiveWeapon( WEAPON_DUAL );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE1 );
			return qtrue;
		}
		
		// No ammo
		return qfalse;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkattackbuttonleft( Conditional &condition )
{
	if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
	{
		return qfalse;
	}
	
	if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
	{
		return qfalse;
	}
	else
	{
		return ( last_ucmd.buttons & BUTTON_ATTACKLEFT );
	}
}

qboolean Player::checkattackright( Conditional &condition )
{
	Weapon *weapon;
	
	if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
	{
		return qfalse;
	}
	
	if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
	{
		return qfalse;
	}
	
	// Make sure we aren't leaning
	
	if ( client->ps.leanDelta != 0 )
		return false;
	
	// If we're in the middle of a reload, we're not done attacking
	/*	weapon = GetActiveWeapon( WEAPON_RIGHT );
	if (weapon )
	{
		if ( weapon->weaponstate == WEAPON_RELOADING )
			return true;
	}*/
	
	if ( last_ucmd.buttons & BUTTON_ATTACKRIGHT )
	{
		last_attack_button = BUTTON_ATTACKRIGHT;
		
		weapon = GetActiveWeapon( WEAPON_RIGHT );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE2 );
			return qtrue;
		}
		
		weapon = GetActiveWeapon( WEAPON_LEFT );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE2 );
			return qtrue;
		}
		
		weapon = GetActiveWeapon( WEAPON_DUAL );
		if ( weapon )
		{
			weapon->CheckReload( FIRE_MODE2 );
			return qtrue;
		}
		
		// No ammo
		return qfalse;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkattackbuttonright( Conditional &condition )
{
	if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
	{
		return qfalse;
	}
	
	if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
	{
		return qfalse;
	}
	else
	{
		return ( last_ucmd.buttons & BUTTON_ATTACKRIGHT );
	}
}

qboolean Player::checksneak( Conditional &condition )
{
	return qfalse; //( last_ucmd.buttons & BUTTON_SNEAK ) != 0;
}

qboolean Player::checkrun( Conditional &condition )
{
	return ( last_ucmd.buttons & BUTTON_RUN ) != 0;
}

qboolean Player::checkwasrunning( Conditional &condition )
{
	return ( pm_lastruntime > MINIMUM_RUNNING_TIME );
}

qboolean Player::checkholsterweapon( Conditional &condition )
{
	if(client->ps.pm_flags & PMF_DISABLE_INVENTORY || _disableUseWeapon)
	{
		return qfalse;
	}

	return ( last_ucmd.buttons & BUTTON_HOLSTERWEAPON ) != 0;
}

qboolean Player::checkuse( Conditional &condition )
{
	return ( last_ucmd.buttons & BUTTON_USE ) != 0;
}

qboolean Player::checkcanturn( Conditional &condition )
{
	float yaw;
	Vector oldang( v_angle );
	qboolean result;
	
	yaw = (float)atof( condition.getParm( 1 ) );
	
	v_angle[ YAW ] = (float)( ( int )( anglemod( v_angle[ YAW ] + yaw ) / 22.5f ) * 22.5f );
	SetViewAngles( v_angle );
	
	result = qtrue; //CheckMove( vec_zero );
	
	SetViewAngles( oldang );
	
	return result;
}

qboolean Player::checkblocked( Conditional &condition )
{
	int test_moveresult;
	
	test_moveresult = moveresult;
	
	if ( flags & FL_IMMOBILE )
		test_moveresult = MOVERESULT_BLOCKED;
	
	if ( condition.numParms() )
	{
		return test_moveresult >= atoi( condition.getParm( 1 ) );
	}
	
	return test_moveresult >= MOVERESULT_BLOCKED;
}

qboolean Player::checkonground( Conditional &condition )
{
	return client->ps.walking;
}

qboolean Player::check22degreeslope( Conditional &condition )
{
	if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) &&
		( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_22_MIN ) )
	{
		return qtrue;
	}
	
	return qfalse;
}

qboolean Player::check45degreeslope( Conditional &condition )
{
	if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_45_MAX ) &&
		( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_45_MIN ) )
	{
		return qtrue;
	}
	
	return qfalse;
}

qboolean Player::checkrightleghigh( Conditional &condition )
{
	float groundyaw;
	float yawdelta;
	int which;
	
	groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
	yawdelta = anglemod( v_angle.y - groundyaw );
	which = ( ( int )yawdelta + 45 ) / 90;
	
	return ( which == 3 );
}

qboolean Player::checkleftleghigh( Conditional &condition )
{
	float groundyaw;
	float yawdelta;
	int which;
	
	groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
	yawdelta = anglemod( v_angle.y - groundyaw );
	which = ( ( int )yawdelta + 45 ) / 90;
	
	return ( which == 1 );
}

qboolean Player::checkfacingupslope( Conditional &condition )
{
	float groundyaw;
	float yawdelta;
	int which;
	
	groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
	yawdelta = anglemod( v_angle.y - groundyaw );
	which = ( ( int )yawdelta + 45 ) / 90;
	
	return ( which == 2 );
}

qboolean Player::checkfacingdownslope( Conditional &condition )
{
	float groundyaw;
	float yawdelta;
	int which;
	
	groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
	yawdelta = anglemod( v_angle.y - groundyaw );
	which = ( ( int )yawdelta + 45 ) / 90;
	
	return ( ( which == 0 ) || ( which == 4 ) );
}

qboolean Player::checkfalling( Conditional &condition )
{
	return falling;
}

qboolean Player::checkgroundentity( Conditional &condition )
{
	return ( groundentity != NULL );
}

qboolean Player::checkhardimpact( Conditional &condition )
{
	return hardimpact;
}

qboolean Player::checkcanfall( Conditional &condition )
{
	return canfall;
}

qboolean Player::checkatdoor( Conditional &condition )
{
	// Check if the player is at a door
	return ( atobject && atobject->isSubclassOf( Door ) );
}

qboolean Player::checkatuseanim( Conditional &condition )
{
	// Check if the player is at a useanim
	if ( atobject && atobject->isSubclassOf( UseAnim ) )
	{
		return ( ( UseAnim * )( Entity * )atobject )->canBeUsed( this );
	}
	
	return qfalse;
}

qboolean Player::checktouchuseanim( Conditional &condition )
{
	if ( toucheduseanim )
	{
		return ( ( UseAnim * )( Entity * )toucheduseanim )->canBeUsed( this );
	}
	
	return qfalse;
}

qboolean Player::checkuseanimfinished( Conditional &condition )
{
	return ( useanim_numloops <= 0 );
}

qboolean Player::checkatuseobject( Conditional &condition )
{
	// Check if the player is at a useanim
	if ( atobject && atobject->isSubclassOf( UseObject ) )
	{
		return ( ( UseObject * )( Entity * )atobject )->canBeUsed( origin, yaw_forward );
	}
	
	return qfalse;
}

qboolean Player::checkloopuseobject( Conditional &condition )
{
	// Check if the player is at a useanim
	if ( useitem_in_use && useitem_in_use->isSubclassOf( UseObject ) )
	{
		return ( ( UseObject * )( Entity * )useitem_in_use )->Loop();
	}
	
	return qfalse;
}

qboolean Player::checkdead( Conditional &condition )
{
	return ( deadflag );
}

qboolean Player::checkhealth( Conditional &condition )
{
	return health < atoi( condition.getParm( 1 ) );
}

qboolean Player::checkpain( Conditional &condition )
{
	return ( ( pain != 0 ) || ( knockdown != 0 ) );
}

qboolean Player::checkknockdown( Conditional &condition )
{
	if ( knockdown )
	{
		knockdown = false;
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkpaintype( Conditional &condition )
{
	if ( pain_type == MOD_NameToNum( condition.getParm( 1 ) ) )
	{
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkpaindirection( Conditional &condition )
{
	if ( pain_dir == Pain_string_to_int( condition.getParm( 1 ) ) )
	{
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkaccumulatedpain( Conditional &condition )
{
	float threshold = (float)atof( condition.getParm( 1 ) );
	
	if ( accumulated_pain >= threshold )
	{
		accumulated_pain = 0; // zero out accumulation
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkpainthreshold( Conditional &condition )
{
	float threshold = (float)atof( condition.getParm( 1 ) );
	
	if ( (  pain >= threshold ) && ( level.time > nextpaintime ) )
	{
		accumulated_pain = 0; // zero out accumulation since we are going into a pain anim right now
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checklegsstate( Conditional &condition )
{
	if ( currentState_Legs )
	{
		str current = currentState_Legs->getName();
		str compare = condition.getParm( 1 );
		
		if ( current == compare )
		{
			return qtrue;
		}
	}
	
	return qfalse;
}

qboolean Player::checktorsostate( Conditional &condition )
{
	if ( currentState_Torso )
	{
		str current = currentState_Torso->getName();
		str compare = condition.getParm( 1 );
		
		if ( current == compare )
		{
			return qtrue;
		}
	}
	
	return qfalse;
}

qboolean Player::checkhasweapon( Conditional &condition )
{
	if ( condition.numParms() > 0 )
	{
		weaponhand_t hand = WeaponHandNameToNum( condition.getParm( 1 ) );
		if ( GetActiveWeapon( hand ) )
			return true;
		else
			return false;
	}
	
	return WeaponsOut();
}

qboolean Player::checkhasdualweapon( Conditional & condition )
{
	return IsDualWeaponActive();
}

qboolean Player::checknewweapon( Conditional &condition )
{
	Weapon * weapon;
	
	weapon = GetNewActiveWeapon();
	
	if ( weapon && _disableUseWeapon == false)
		return qtrue;
	else
		return qfalse;
}

// Check to see if a weapon has been raised
qboolean Player::checkuseweapon( Conditional &condition )
{
	const char     *weaponName;
	const char     *parm;
	
	weaponhand_t   hand;
	Weapon         *weap;
	
	weap = GetNewActiveWeapon();
	parm = condition.getParm( 1 );
	
	if ( !str::icmp( parm, "ERROR" ) )
	{
		if ( weap )
			warning( "Player::checkuseweapon", "%s does not have a valid RAISE_WEAPON state\n", weap->item_name.c_str() );
		else
			warning( "Player::checkuseweapon", "New Active weapon does not exist\n" );
		
		ClearNewActiveWeapon();
		return qtrue;
	}
	
	hand = WeaponHandNameToNum( parm );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	weaponName = condition.getParm( 2 );
	
	if (
        ( weap != NULL ) &&
        ( GetNewActiveWeaponHand() == hand ) &&
        ( !stricmp( weap->item_name, weaponName ) )
		)
	{
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

// Checks to see if any weapon is active in the specified hand
qboolean Player::checkanyweaponactive( Conditional &condition )
{
	weaponhand_t   hand;
	Weapon         *weap;
	
	hand = WeaponHandNameToNum( condition.getParm( 1 ) );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	weap = GetActiveWeapon( hand );
	return ( weap != NULL );
}

// Checks to see if any weapon is active in the specified hand
qboolean Player::checkweaponhasammo( Conditional &condition )
{
	weaponhand_t   hand;
	Weapon         *weap;
	firemode_t     mode = FIRE_MODE1;
	int numShots = 1;
	
	hand = WeaponHandNameToNum( condition.getParm( 1 ) );
	
	if ( condition.numParms() > 1 )
		mode = WeaponModeNameToNum( condition.getParm( 2 ) );
	
	if ( condition.numParms() > 2 )
		numShots = atoi( condition.getParm( 3 ) );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	weap = GetActiveWeapon( hand );
	
	if ( !weap )
		return qfalse;
	else
		return ( weap->HasAmmo( mode, numShots ) );
}

qboolean Player::checkweaponhasfullammo( Conditional &condition )
{
	str ammoName;

	ammoName = condition.getParm( 1 );

	if ( AmmoCount( ammoName ) == MaxAmmoCount( ammoName ) )
		return true;
	else
		return false;
}

// Checks to see if any weapon is active in the specified hand
qboolean Player::checkweaponhasinvammo( Conditional &condition )
{
	weaponhand_t   hand;
	Weapon         *weap;
	firemode_t     mode = FIRE_MODE1;
	
	hand = WeaponHandNameToNum( condition.getParm( 1 ) );
	
	if ( condition.numParms() > 1 )
		mode = WeaponModeNameToNum( condition.getParm( 2 ) );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	weap = GetActiveWeapon( hand );
	
	if ( !weap )
		return qfalse;
	else
		return ( weap->HasInvAmmo( mode ) );
}

// Checks to see if weapon is active
qboolean Player::checkweaponactive( Conditional &condition )
{
	const char *weaponName;
	weaponhand_t hand;
	
	weaponName = condition.getParm( 2 );
	hand = WeaponHandNameToNum( condition.getParm( 1 ) );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	Weapon *weapon = GetActiveWeapon( hand );
	
	return ( weapon && !strcmp( weaponName, weapon->item_name ) );
}

qboolean Player::checkweaponreload( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( weapon )
		if ( weapon->weaponstate == WEAPON_RELOADING )
			return qtrue;
		
		return qfalse;
}

qboolean Player::checkweaponswitchmode( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( weapon )
		if ( weapon->weaponstate == WEAPON_SWITCHINGMODE )
			return qtrue;
		
		return qfalse;
}

qboolean Player::checkweaponinmode( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	str mode;
	
	if ( weapon )
	{
		if ( condition.numParms() > 0 )
			mode = condition.getParm( 1 );
		if ( weapon->GetCurMode() == WeaponModeNameToNum( mode ) )
			return qtrue;
		else
			return qfalse;
	}
	
	return qfalse;
}

qboolean Player::checkweapondonefiring( Conditional &condition )
{
	Weapon      *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	// Weapon there check
	if ( !weapon )
		return qtrue;
	
	return weapon->IsDoneFiring();
}

// Checks to see if weapon is active and ready to fire
qboolean Player::checkweaponreadytofire( Conditional &condition )
{
	firemode_t     mode = FIRE_MODE1;
	str            weaponName="None";
	weaponhand_t   hand;
	qboolean    ready;
	
	if ( level.playerfrozen || ( flags & FL_IMMOBILE ) )
	{
		return qfalse;
	}
	
	hand = WeaponHandNameToNum( condition.getParm( 1 ) );
	
	if ( hand == WEAPON_DUAL )
	{
		gi.DPrintf( "This check should only be used for single handed weapons\n" );
		return qfalse;
	}
	
	if ( condition.numParms() > 1 )
		weaponName = condition.getParm( 2 );
	
	if ( hand == WEAPON_ERROR )
		return qfalse;
	
	Weapon *weapon = GetActiveWeapon( hand );
	
	// Weapon there check
	if ( !weapon )
		return qfalse;
	
	// Name check
	if ( condition.numParms() > 1 )
	{
		if ( strcmp( weaponName, weapon->item_name ) )
		{
			return qfalse;
		}
	}
	
	// Ammo check
	ready = weapon->ReadyToFire( mode );
	return( ready );
}

qboolean Player::checkdualweaponreadytofire( Conditional &condition )
{
	firemode_t  mode      = FIRE_MODE1;
	str         weaponName="None";
	Weapon      *weapon = GetActiveWeapon( WEAPON_DUAL );
	qboolean    ready;


	mode = WeaponModeNameToNum( condition.getParm( 1 ) );

	if ( condition.numParms() > 1 )
		weaponName = condition.getParm( 2 );

	// Make sure we aren't leaning

	if ( client->ps.leanDelta != 0 )
		return false;

	// Weapon there check
	if ( !weapon )
		return qfalse;

	// Name check
	if ( condition.numParms() > 1 )
	{
		if ( strcmp( weaponName, weapon->item_name ) )
		{
			return qfalse;
		}
	}

	// Ammo check
	ready = weapon->ReadyToFire( mode );

	// Fire timer checks

	if ( !weapon->isModeNoDelay( mode ) )
	{
		if ( weapon->next_fire_time[mode] > level.time )
			return qfalse;

		if ( weapon->next_fire_time[FIRE_MODE1] > level.time )
			return qfalse;

		if ( weapon->next_fire_time[FIRE_MODE2] > level.time )
			return qfalse;
	}

	return( ready );
}

qboolean Player::checkweaponlowered( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( !weapon )
		return true;
	else
		return ( weapon->weaponstate == WEAPON_LOWERING );
}

qboolean Player::checkweaponfiretimer( Conditional &condition )
{
	firemode_t mode = FIRE_MODE1;
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( weapon->GetSwitchMode() )
		mode = weapon->GetCurMode();
	else 
		mode = WeaponModeNameToNum( condition.getParm( 1 ) );
	
	if ( weapon->GetFireTime(mode) > level.time )
		return qfalse;
	
	return qtrue;
}

qboolean Player::checkweaponfullclip( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( !weapon )
		return qtrue;
	
	return weapon->HasFullClip();
}

qboolean Player::checkweaponforcereload( Conditional &condition )
{
	return ( last_ucmd.buttons & BUTTON_RELOAD ) != 0;
}

qboolean Player::checkweaponcanreload( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	if ( !weapon )
		return qfalse;

	return weapon->canReload();
}

// Check to see if any of the active weapons need to be put away
qboolean Player::checkputawayleft( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_LEFT );
	
	return weapon && weapon->GetPutaway();
}

qboolean Player::checkputawayright( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
	
	return weapon && weapon->GetPutaway();
}

qboolean Player::checkputawayboth( Conditional &condition )
{
	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );
	
	return weapon && weapon->GetPutaway();
}

qboolean Player::checktargetacquired( Conditional &condition )
{
	return (targetEnemy != NULL);
}

qboolean Player::returntrue( Conditional &condition )
{
	return qtrue;
}

qboolean Player::checkstatename( Conditional &condition )
{
	str part      = condition.getParm( 1 );
	str statename = condition.getParm( 2 );
	
	if ( currentState_Legs && !part.icmp( "legs" ) )
	{
		return ( !statename.icmpn( currentState_Legs->getName(), statename.length() ) );
	}
	else if ( !part.icmp( "torso" ) )
	{
		return ( !statename.icmpn( currentState_Torso->getName(), statename.length() ) );
	}
	
	return qfalse;
}

qboolean Player::checkattackblocked( Conditional &condition )
{
	if ( attack_blocked )
	{
		attack_blocked = false;
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkblockdelay( Conditional &condition )
{
	float t = (float)atof ( condition.getParm( 1 ) );
	return ( level.time > ( attack_blocked_time + t ) );
}

qboolean Player::checkpush( Conditional &condition )
{
	// Check if the player is at a pushobject
	if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) )
	{
		Vector dir;
		
		dir = atobject_dir * 8.0f;
		return ( ( PushObject * )( Entity * )atobject )->canPush( dir );
	}
	
	return qfalse;
}

qboolean Player::checkpull( Conditional &condition )
{
	// Check if the player is at a pushobject
	if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) )
	{
		Vector dir;
		
		dir = atobject_dir * -64.0f;
		return ( ( PushObject * )( Entity * )atobject )->canPush( dir );
	}
	
	return qfalse;
}

qboolean Player::checkcharavailable( Conditional &condition )
{
	str character = condition.getParm( 1 );
	Actor *act = Actor::FindActorByName(character.c_str());
	if ( act )
		return true;
	
	return false;
}

qboolean Player::checkOnLadder( Conditional &condition )
{
	return _onLadder;
}

qboolean Player::checkcanstand( Conditional &condition )
{
	Vector newmins( mins );
	Vector newmaxs( maxs );
	Vector tmporg( origin );
	trace_t trace;
	
	// Start the trace alittle higher than the origin, for some
	// reason crouching causes the trace to start allsolid if you're 
	// on a slope
	tmporg[ 2 ] += 2.0f;
	newmins[ 2 ] = MINS_Z;
	newmaxs[ 2 ] = MAXS_Z;
	
	trace = G_Trace( tmporg, newmins, newmaxs, tmporg, this, edict->clipmask, true, "checkcanstand" );
	if ( trace.startsolid )
	{
		return qfalse;
	}
	
	return qtrue;
}

qboolean Player::checkdualwield( Conditional &condition )
{
	// Only start the dual wield state if dual wield is set and the hands have no weapons
	
	return ( dual_wield_active );
}

qboolean Player::checkdualweapons( Conditional &condition )
{
	int i,j;
	
	for ( i=1; i<=condition.numParms(); i++ )
	{
		str weaponName;
		weaponName = condition.getParm( i );
		
		for ( j=1; j<=dual_wield_weaponlist.NumObjects(); j++ )
		{
			WeaponSetItem *dw;
			dw = dual_wield_weaponlist.ObjectAt( j );
			
			if ( dw->name == weaponName )
            {
				goto out;
            }
		}
		return qfalse;
out:
		;
	}
	
	return qtrue;
}

qboolean Player::checkchance( Conditional &condition )
{
	float percent_chance;
	
	percent_chance = (float)atof( condition.getParm( 1 ) );
	
	return ( G_Random() < percent_chance );
}

qboolean Player::checkturnedleft( Conditional &condition )
{
	return yawing_left;
}

qboolean Player::checkturnedright( Conditional &condition )
{
	return yawing_right;
}

//-----------------------------------------------------
//
// Name:		checkinvehicle
// Class:		Player
//
// Description:	Checks if the vehicle is in specific type of vehicle
//
// Parameters:	condition - the condition that contains the vehicle type
//
// Returns:		
//-----------------------------------------------------
qboolean Player::checkinvehicle( Conditional &condition )
{
	
	if(vehicle == NULL || vehicle->getArchetype() != condition.getParm(1))
		return qfalse;
	
	return qtrue;
	
}

qboolean Player::checksolidforward( Conditional &condition )
{
	// Trace out forward to see if there is a solid ahead
	float dist = (float)atof( condition.getParm( 1 ) );
	Vector end( centroid + ( yaw_forward * dist ) );
	
	trace_t trace = G_Trace( centroid, Vector( mins.x, mins.y, -8.0f ), Vector( maxs.x, maxs.y, 8.0f ),
		end, this, MASK_SOLID, true, "Player::checksolidforward" );
	
	return ( trace.fraction < 0.7f );
}

qboolean Player::checkweaponsholstered( Conditional &condition )
{
	
	if (
		( holsteredWeapons[WEAPON_DUAL] ) ||
		( holsteredWeapons[WEAPON_LEFT] ) ||
		( holsteredWeapons[WEAPON_RIGHT] )
		)
	{
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}

qboolean Player::checkfakeplayeractive( Conditional &condition )
{
	return fakePlayer_active;
}

qboolean Player::checkspecialmovecharge( Conditional &condition )
{
	if ( specialMoveCharge >= specialMoveEndTime )
		return true;
	return false;
}

qboolean Player::checkstancechangedtorso( Conditional &condition )
{
	return changedStanceTorso;
}

qboolean Player::checkstancechangedlegs( Conditional &condition )
{
	return changedStanceLegs;
}

qboolean Player::checkstance( Conditional &condition )
{
	int stancenum;
	stancenum = (int)atoi( condition.getParm( 1 ) );
	
	if ( stancenum == stanceNumber )
		return true;
	
	return false;
}

qboolean Player::checkpoints( Conditional &condition )
{
	int pointnum;
	pointnum = (int)atoi( condition.getParm( 1 ) );
	
	if ( points >= pointnum )
		return true;
	
	return false;
}

qboolean Player::checkincomingmeleeattack( Conditional &condition )
{
	return incomingMeleeAttack;
}


qboolean Player::checkfinishingmove( Conditional &condition )
{
	if ( _finishActor )
		return true;
	return false;
}

//--------------------------------------------------------------
//
// Name:			checkatuseentity
// Class:			Player
//
// Description:		Conditional to see if the player is standing at a usable entity
//
// Parameters:		Conditional &condition
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkatuseentity(Conditional &condition)
{
	// Check if the player is at a useentity
	if ( atobject )
	   {
	   Entity *ent = (Entity*)atobject;
	   if ( ent->hasUseData() )
		   return qtrue;
	   }

	return qfalse;
}

//--------------------------------------------------------------
//
// Name:			checkusingentity
// Class:			Player
//
// Description:		Conditional to see if the player is in the middle
//					of using an entity.
//
// Parameters:		Conditional &condition
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkusingentity(Conditional &condition)
{
	return _usingEntity;
}

//--------------------------------------------------------------
//
// Name:			checkthirdperson
// Class:			Player
//
// Description:		Conditional to see if the player is in third person
//
// Parameters:		Conditional &condition
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkthirdperson(Conditional &condition)
{
	return _isThirdPerson;
}


//--------------------------------------------------------------
//
// Name:			checkPropChance
// Class:			Player
//
// Description:		Check the chance based on the property passed.
//					This property should be located in the Actor's
//					StateData object in the gameplay database.
//
// Parameters:		Conditional &conditional
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkPropChance( Conditional &condition )
{
	str propname;
	str objname = condition.getParm( 1 );
	if ( condition.numParms() > 1 )
		propname = condition.getParm( 2 );
	
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = getArchetype() + "." + objname;
	if ( !gpm->hasObject(scopestr) )
		return false;
	
	float chance;
	if ( propname.length() )
		chance = gpm->getFloatValue(scopestr, propname);
	else
		chance = gpm->getFloatValue(scopestr, "value");
	
	return ( G_Random() <= chance );
}

//--------------------------------------------------------------
//
// Name:			checkPropExists
// Class:			Player
//
// Description:		Check to see if the property exists
//					The Actor's StateData object will be asked
//					if it has the property.
//
// Parameters:		Conditional &conditional
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkPropExists( Conditional &condition )
{
	str objname = condition.getParm( 1 );
	str propname = condition.getParm( 2 );
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = getArchetype() + "." + objname;
	if ( !gpm->hasProperty(scopestr, propname) )
		return false;
	
	return true;
}

//--------------------------------------------------------------
//
// Name:			checkEndAnimChain
// Class:			Player
//
// Description:		Check to see if the current animation chain is on
//					the last anim.
//
// Parameters:		Conditional &conditional
//
// Returns:			qboolean
//
//--------------------------------------------------------------
qboolean Player::checkEndAnimChain( Conditional &condition )
{
	if ( condition.numParms() < 1 )
		return false;
	
	str objname = condition.getParm( 1 );
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = "CurrentPlayer.ChainedMoves";
	if ( !gpm->hasObject(scopestr) )
		return false;
	
	int max = (int)gpm->getFloatValue(scopestr, "value");
	max++; // Increment to compensate for 0 based skill system, we always have to play the first anim
	if ( _gameplayAnimIdx > max )
		return false; // Loop anim
	
	if ( _gameplayAnimIdx == max )
		return true;
	
	return false;
}

qboolean Player::checkWeaponType( Conditional &condition )
{
	if ( condition.numParms() < 1 )
		return false;
	
	str type = condition.getParm( 1 );
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	Weapon* weap = GetActiveWeapon(WEAPON_RIGHT);
	if ( !weap )
		weap = GetActiveWeapon(WEAPON_LEFT);
	if ( !weap )
		return false;
	
	if ( !gpm->hasObject(weap->getArchetype()) )
		return false;
	
	str weaptype = gpm->getStringValue(weap->getArchetype(), "class");
	if ( weaptype == type )
		return true;
	
	return false;
}

qboolean Player::checkHasAnim( Conditional &condition )
{
	str animName;

	if ( condition.numParms() < 1 )
		return false;
	
	animName = condition.getParm( 1 );

	if ( gi.Anim_NumForName( edict->s.modelindex, animName.c_str() ) < 0 )
		return false;
	else
		return true;
}

qboolean Player::checkIsWeaponControllingProjectile( Conditional &condition )
{
	Weapon *weapon;

	// Only support dual handed weapon for now
		
	weapon = GetActiveWeapon( WEAPON_DUAL );

	if ( weapon )
	{
		if ( weapon->getControllingProjectile() )
			return true;
		else
			return false;
	}

	return false;
}


Condition<Player> Player::Conditions[] =
{
	{ "default",							&Player::returntrue },
	{ "SNEAK",								&Player::checksneak },
	{ "RUN",								&Player::checkrun },
	{ "WAS_RUNNING",						&Player::checkwasrunning },
	{ "HOLSTERWEAPON",						&Player::checkholsterweapon },
	{ "USE",								&Player::checkuse },
	{ "LEFT",								&Player::checkturnleft },
	{ "RIGHT",								&Player::checkturnright },
	{ "FORWARD",							&Player::checkforward },
	{ "BACKWARD",							&Player::checkbackward },
	{ "STRAFE_LEFT",						&Player::checkstrafeleft },
	{ "STRAFE_RIGHT",						&Player::checkstraferight },
	{ "LEAN_LEFT",							&Player::checkleanleft },
	{ "LEAN_RIGHT",							&Player::checkleanright},
	{ "DUCK",								&Player::checkduck },
	{ "JUMP",								&Player::checkjump },
	{ "RISE",								&Player::checkrise },
	{ "CROUCH",								&Player::checkcrouch },
	{ "ANIMDONE_LEGS",						&Player::checkanimdone_legs },
	{ "ANIMDONE_TORSO",						&Player::checkanimdone_torso },
	{ "CAN_TURN",							&Player::checkcanturn },
	{ "BLOCKED",							&Player::checkblocked },
	{ "ONGROUND",							&Player::checkonground },
	{ "CAN_FALL",							&Player::checkcanfall },
	{ "AT_DOOR",							&Player::checkatdoor },
	{ "FALLING",							&Player::checkfalling },
	{ "HARD_IMPACT",						&Player::checkhardimpact },
	{ "KILLED",								&Player::checkdead },
	{ "HEALTH",								&Player::checkhealth },
	{ "PAIN",								&Player::checkpain },
	{ "PAIN_TYPE",							&Player::checkpaintype },
	{ "PAIN_DIRECTION",						&Player::checkpaindirection },
	{ "PAIN_THRESHOLD",						&Player::checkpainthreshold },
	{ "PAIN_ACCUMULATED",					&Player::checkaccumulatedpain },
	{ "KNOCKDOWN",							&Player::checkknockdown },
	{ "LEGS",								&Player::checklegsstate },
	{ "TORSO",								&Player::checktorsostate },
	{ "AT_USEANIM",							&Player::checkatuseanim },
	{ "TOUCHEDUSEANIM",						&Player::checktouchuseanim },
	{ "FINISHEDUSEANIM",					&Player::checkuseanimfinished },
	{ "AT_USEOBJECT",						&Player::checkatuseobject },
	{ "AT_USEENTITY",						&Player::checkatuseentity },
	{ "LOOP_USEOBJECT",						&Player::checkloopuseobject },
	{ "CAN_PUSH",							&Player::checkpush },
	{ "CAN_PULL",							&Player::checkpull },
	{ "ON_LADDER",							&Player::checkOnLadder },
	{ "CAN_STAND",							&Player::checkcanstand },
	{ "CHANCE",								&Player::checkchance },
	{ "TURNED_LEFT",						&Player::checkturnedleft },
	{ "TURNED_RIGHT",						&Player::checkturnedright },
	{ "IN_VEHICLE",							&Player::checkinvehicle },
	//      { "WATER_LEVEL",				checkwaterlevel },
	{ "SOLID_FORWARD",						&Player::checksolidforward },
	{ "GROUNDENTITY",						&Player::checkgroundentity },
	{ "FAKEPLAYERACTIVE",					&Player::checkfakeplayeractive },
	{ "SLOPE_22",							&Player::check22degreeslope },
	{ "SLOPE_45",							&Player::check45degreeslope },
	{ "RIGHT_LEG_HIGH",						&Player::checkrightleghigh },
	{ "LEFT_LEG_HIGH",						&Player::checkleftleghigh },
	{ "FACING_UP_SLOPE",					&Player::checkfacingupslope },
	{ "FACING_DOWN_SLOPE",					&Player::checkfacingdownslope },
	
	// Weapon conditions
	{ "ATTACKLEFT",							&Player::checkattackleft },  // Checks to see if there is an active weapon as well as the button being pressed
	{ "ATTACKRIGHT",						&Player::checkattackright }, // Checks to see if there is an active weapon as well as the button being pressed
	{ "ATTACKLEFTBUTTON",					&Player::checkattackbuttonleft }, // Checks to see if the left attack button is pressed
	{ "ATTACKRIGHTBUTTON",					&Player::checkattackbuttonright },// Checks to see if the right attack button is pressed
	{ "HAS_DUAL_WEAPON",					&Player::checkhasdualweapon},
	{ "HAS_WEAPON",							&Player::checkhasweapon },
	{ "NEW_WEAPON",							&Player::checknewweapon },
	{ "IS_NEW_WEAPON",						&Player::checkuseweapon },
	{ "IS_WEAPON_ACTIVE",					&Player::checkweaponactive },
	{ "IS_WEAPON_RELOADING",				&Player::checkweaponreload },
	{ "IS_IN_MODE",							&Player::checkweaponinmode },
	{ "IS_WEAPON_SWITCHINGMODE",			&Player::checkweaponswitchmode },
	{ "IS_WEAPON_READY_TO_FIRE",			&Player::checkweaponreadytofire },
	{ "IS_DUALWEAPON_READY_TO_FIRE",		&Player::checkdualweaponreadytofire },
	{ "IS_WEAPON_FINISHED_FIRING",			&Player::checkweapondonefiring		},
	{ "PUTAWAYBOTH",						&Player::checkputawayboth },
	{ "PUTAWAYLEFT",						&Player::checkputawayleft },
	{ "PUTAWAYRIGHT",						&Player::checkputawayright },
	{ "TARGET_ACQUIRED",					&Player::checktargetacquired },
	{ "ANY_WEAPON_ACTIVE",					&Player::checkanyweaponactive },
	{ "ATTACK_BLOCKED",						&Player::checkattackblocked },
	{ "STATE_ACTIVE",						&Player::checkstatename },
	{ "BLOCK_DELAY",						&Player::checkblockdelay },
	{ "DUALWIELD",							&Player::checkdualwield },
	{ "DUALWIELDWEAPONS",					&Player::checkdualweapons },
	{ "HAS_AMMO",							&Player::checkweaponhasammo },
	{ "HAS_FULLAMMO",						&Player::checkweaponhasfullammo },
	{ "HAS_INVAMMO",						&Player::checkweaponhasinvammo },
	{ "WEAPONS_HOLSTERED",					&Player::checkweaponsholstered },
	{ "WEAPON_LOWERED",						&Player::checkweaponlowered }, // See if we're done with our putaway anim
	{ "WEAPON_FIRETIMER",					&Player::checkweaponfiretimer },
	{ "WEAPON_FORCERELOAD",					&Player::checkweaponforcereload },
	{ "WEAPON_CAN_RELOAD",					&Player::checkweaponcanreload },
	{ "WEAPON_FULLCLIP",					&Player::checkweaponfullclip },
	{ "IS_SPECIALMOVE_CHARGED",				&Player::checkspecialmovecharge },
	{ "IS_CHAR_AVAILABLE",					&Player::checkcharavailable },
	
	{ "STANCE_CHANGEDTORSO",				&Player::checkstancechangedtorso },
	{ "STANCE_CHANGEDLEGS",					&Player::checkstancechangedlegs },
	{ "STANCE",								&Player::checkstance },
	{ "POINTS",								&Player::checkpoints },
	{ "INCOMING_MELEE",						&Player::checkincomingmeleeattack },
	{ "FINISHINGMOVE",						&Player::checkfinishingmove },
	{ "USINGENTITY",						&Player::checkusingentity },
	{ "IS_THIRDPERSON",						&Player::checkthirdperson },
	{ "PROP_CHANCE",						&Player::checkPropChance },
	{ "PROP_EXISTS",						&Player::checkPropExists	},
	{ "ANIMCHAIN_END",						&Player::checkEndAnimChain },
	{ "WEAPON_TYPE",						&Player::checkWeaponType },
	{ "HAS_ANIM",							&Player::checkHasAnim },
	{ "IS_WEAPON_CONTROLLING_PROJECTILE",	&Player::checkIsWeaponControllingProjectile },
	
	{ NULL,									NULL },
};

movecontrolfunc_t Player::MoveStartFuncs[] =
{
	NULL,					// MOVECONTROL_USER,       // Quake style
	NULL,					// MOVECONTROL_LEGS,       // Quake style, legs state system active
	NULL,					// MOVECONTROL_ANIM,       // move based on animation, with full collision testing
	NULL,					// MOVECONTROL_ABSOLUTE,   // move based on animation, with full collision testing but no turning
	NULL,					// MOVECONTROL_HANGING
	NULL,					// MOVECONTROL_WALLHUG
	NULL,					// MOVECONTROL_MONKEYBARS
	NULL,					// MOVECONTROL_PIPECRAWL
	NULL,					// MOVECONTROL_PIPEHANG
	NULL,					// MOVECONTROL_STEPUP
	NULL,					// MOVECONTROL_ROPE_GRAB
	NULL,					// MOVECONTROL_ROPE_RELEASE
	NULL,					// MOVECONTROL_ROPE_MOVE
	NULL,					// MOVECONTORL_PICKUPENEMY
	&Player::StartPush,			// MOVECONTROL_PUSH
	NULL,					// MOVECONTORL_CLIMBWALL
	&Player::StartUseAnim,		// MOVECONTROL_USEANIM
	NULL,					// MOVECONTROL_CROUCH
	&Player::StartLoopUseAnim,	// MOVECONTROL_LOOPUSEANIM
	&Player::SetupUseObject,	// MOVECONTROL_USEOBJECT
	&Player::StartCoolItemAnim,	// MOVECONTROL_COOLOBJECT
	&Player::StartFakePlayer	// MOVECONTROL_FAKEPLAYER
};

Player::Player()
{
	//
	// set the entity type
	//
	edict->s.eType       = ET_PLAYER;
	respawn_time         = -1;
	statemap_Legs        = NULL;
	statemap_Torso       = NULL;
	camera               = NULL;
	atobject             = NULL;
	atobject_dist        = 0;
	toucheduseanim       = NULL;
	useitem_in_use       = NULL;
	damage_blood         = 0;
	damage_count         = 0;
	damage_from          = vec_zero;
	damage_alpha         = 0;
	last_attack_button   = 0;
	attack_blocked       = false;
	shield_active        = false;
	canfall              = false;
	moveresult           = MOVERESULT_NONE;
	animspeed            = 0;
	airspeed             = 350;
	vehicle              = NULL;
	action_level         = 0;
	adjust_torso         = false;
	dual_wield_active    = false;
	cool_item            = NULL;
	weapons_holstered_by_code = false;
	actor_camera         = NULL;
	cool_camera          = NULL;

	_started = false;
	
	StopWatchingEntity();
	playerCameraMode = PLAYER_CAMERA_MODE_NORMAL;
	
	damage_multiplier    = 1;
	take_pain            = true;
	look_at_time			= 0;
	fakePlayer_active    = false;
	projdetonate			= false;
	
	_flashMaxTime = 0.0f;
	_flashMinTime = 0.0f;
	
	dont_turn_legs			= false;
	
	specialMoveChargeTime	= 3.0f;
	specialMoveCharge		= 0.0f;
	specialMoveEndTime		= 0.0f;
	playerKnockback			= 0.0f;
	knockbackMultiplier		= 1.0f;
	changedStanceTorso		= false;
	changedStanceLegs		= false;
	incomingMeleeAttack		= false;
	stanceNumber			= 1;
	points					= 0;
	bendTorsoMult			= standardTorsoMult;
	meleeAttackFlags		= 0;
	changingChar			= false;
	_isThirdPerson			= true; // This will get set later
	_finishActor			= 0;
	_finishState			= "";
	_doingFinishingMove		= false;
	_usingEntity			= false;
	_attackType				= "";
	_gameplayAnimIdx		= 1;
	_disableUseWeapon		= false;
	_infoHudOn				= false;
	_nextRegenTime			= 0;
	_useEntityStartTimer	= 0.0f;
	
#ifdef DEDICATED
	p_heuristics = 0;
#else
	p_heuristics = new PlayerHeuristics;
#endif
	
	currentCallVolume = "";
	
	//Add the player to the teammates list 
	//Probably should be a better way to do this.
	TeamMateList.AddObject( this );
	
	// make sure that we are not overflowing the stats for players
	assert( STAT_LAST_STAT <= MAX_STATS );
	
	/* fov = (float)atof( Info_ValueForKey( client->pers.userinfo, "fov" ) );
	if ( fov < 1.0f )
	{
		fov = sv_defaultFov->value;
	}
	else if ( fov > 160.0f )
	{
		fov = 160.0f;
	} */

	fov = sv_defaultFov->value;
	//_userFovChoice = fov;
	
	if ( atoi( Info_ValueForKey( client->pers.userinfo, "mp_autoSwitchWeapons" ) ) )
		_autoSwitchWeapons = true;
	else
		_autoSwitchWeapons = false;
	
	//
	// set targetnameplayer
	//
	if ( !LoadingSavegame )
		SetTargetName( "player" );
	
	_powerup = NULL;
	_rune = NULL;
	_holdableItem = NULL;
	
	if ( !LoadingSavegame )
	{
		GameplayManager *gpm = GameplayManager::getTheGameplayManager();
		
		const str selectedHighlight( "target_selected_highlight" );
		if ( gpm->isDefined( selectedHighlight ) )
		{
			const str targetSelectedHighlightModelName( gpm->getDefine( selectedHighlight ) );
			_targetSelectedHighlight = new Entity;
			_targetSelectedHighlight->setModel( targetSelectedHighlightModelName );
			_targetSelectedHighlight->setSolidType( SOLID_NOT );
			_targetSelectedHighlight->setMoveType( MOVETYPE_NONE );
			_targetSelectedHighlight->takedamage = DAMAGE_NO;
			_targetSelectedHighlight->hideModel();
		}
		
		const str lockedHighlight( "target_locked_highlight" );
		if ( gpm->isDefined( lockedHighlight ) )
		{
			const str targetLockedHighlightModelName( gpm->getDefine( lockedHighlight ) );
			_targetLockedHighlight = new Entity;
			_targetLockedHighlight->setModel( targetLockedHighlightModelName );
			_targetLockedHighlight->setSolidType( SOLID_NOT );
			_targetLockedHighlight->setMoveType( MOVETYPE_NONE );
			_targetLockedHighlight->takedamage = DAMAGE_NO;
			_targetLockedHighlight->hideModel();
		}
	}
	
	Init();
	
	_viewMode = 0;
	
	addAffectingViewModes( gi.GetViewModeClassMask( "player" ) );
	
	_canTransferEnergy = false;
	
	_doDamageScreenFlash = false;
	
	Vector maxs(MAXS_X,MAXS_Y,MAXS_Z),mins(MINS_X,MINS_Y,MINS_Z);

	setSize( mins, maxs );
	
	// Setup ladder stuff
	
	_onLadder = false;
	_nextLadderTime = 0.0f;
	_ladderTop = 0.0f;
	
	_objectiveStates	= 0;
	_informationStates	= 0;
	_objectiveNameIndex = 0;

	_lastDamagedTimeFront = 0.0f;
	_lastDamagedTimeBack  = 0.0f;
	_lastDamagedTimeLeft  = 0.0f;
	_lastDamagedTimeRight = 0.0f;

	_totalGameFrames = 0;
	_updateGameFrames = true;

	_nextPainShaderTime = 0.0f;
	_lastPainShaderMod = MOD_NONE;

	_validPlayerModel = false;

	_secretsFound = 0;

	_allowActionMusic = true;

	setSkill( skill->integer );

	_needToSendBranchDialog = false;
	_branchDialogActor = NULL;
}

Player::~Player()
{	
	if ( p_heuristics )
	{
		p_heuristics->SaveHeuristics( this );	
		delete p_heuristics;
	}
	
	Sentient *player;
	player = this;
	
	if ( TeamMateList.ObjectInList( player ) )
		TeamMateList.RemoveObject( player );
	
	if ( edict->svflags & SVF_BOT )
	{
		BotAIShutdownClient( entnum, qfalse );
	}
	
	edict->s.modelindex = 0;
	
	freeConditionals( legs_conditionals );
	freeConditionals( torso_conditionals );
	
	removePowerup();
	removeRune();
	removeHoldableItem();
	
	clearFinishingMove(NULL);
	
	if ( multiplayerManager.inMultiplayer() )
	{
		multiplayerManager.removePlayer( this );
	}
}

static qboolean logfile_started = false;

void Player::Init( void )
{

	InitClient();
	InitPhysics();
	InitWorldEffects();
	InitSound();
	InitView();
	InitState();
	InitEdict();
	InitModel();
	InitWeapons();
	InitInventory();
	InitHealth();
	//InitArmorValue();
	InitStats();
	
	_dialogEntnum = ENTITYNUM_NONE;
	_dialogSoundIndex = -1;
	_dialogTextSoundIndex = -1;

	client->ps.objectiveNameIndex = -1;
	
	edict->s.clientNum = client->ps.clientNum ;
	
	LoadStateTable();
	
	logfile_started = false;
	
	removePowerup();
	removeRune();
	removeHoldableItem();

	_nextEnergyTransferTime = 0.0f;
	_nextPainShaderTime = 0.0f;
	
	edict->s.renderfx &= ~RF_FORCE_ALPHA;
	
	setAlpha( 1.0f );
	
	if ( multiplayerManager.inMultiplayer() )
	{
		multiplayerManager.addPlayer( this );
	}
	else
	{
		if ( !LoadingSavegame )
		{
			ChooseSpawnPoint();
		}
	}
	
	clearAllHuds();


	_backpackAttachOffset = Vector( -12, -9, 0 );
	_backpackAttachAngles = Vector( 0, 90, 90 );

	_flagAttachOffset = Vector( -96, -16, 0 );
	_flagAttachAngles = Vector( 0, 90, 90 );

	_cameraCutThisFrame = false;

	//Clear out deaththread
	

	// Make sure we put the player back into the world
	
	link();
}

void Player::InitEdict( void )
{
	// entity state stuff
	setSolidType( SOLID_BBOX );
	setMoveType( MOVETYPE_WALK );
	setSize( Vector( MINS_X, MINS_Y, 0.0f ), Vector( MAXS_X, MAXS_Y, MAXS_Z ) );
	edict->clipmask	 = MASK_PLAYERSOLID;
	edict->svflags		&= ~SVF_DEADMONSTER;
	edict->svflags    &= ~SVF_HIDEOWNER;
	edict->ownerNum    = ENTITYNUM_NONE;
	
	// clear entity state values
	edict->s.eFlags		= 0;
	edict->s.frame	      = 0;
	
	// players have precise shadows
	edict->s.renderfx |= RF_SHADOW_PRECISE;
}

void Player::InitSound( void )
{
	//
	// reset the music
	//
	client->ps.current_music_mood  = mood_normal;
	client->ps.fallback_music_mood = mood_normal;
	ChangeMusic( "normal", "normal", false );
	
	client->ps.music_volume           = 1.0f;
	client->ps.music_volume_fade_time = 0.0f;
	
	_allowMusicDucking					= true;
	client->ps.allowMusicDucking		= true;
	
	ChangeMusicVolume( 1.0f, 0.0f );
	
	music_forced = false;
	
	// Reset the reverb stuff
	
	client->ps.reverb_type  = eax_generic;
	client->ps.reverb_level = 0;
	SetReverb( client->ps.reverb_type, client->ps.reverb_level );
}

void Player::InitClient( void )
{
	// deathmatch wipes most client data every spawn
	if ( multiplayerManager.inMultiplayer() )
	{
		float savedTime;
		char userinfo[ MAX_INFO_STRING ];
		//char savedTeamName[ 16 ];
		
		savedTime = client->pers.enterTime;
		//strcpy( savedTeamName, client->pers.lastTeam );
		
		memcpy( userinfo, client->pers.userinfo, sizeof( userinfo ) );
		G_InitClientPersistant( client );
		G_ClientUserinfoChanged( edict, userinfo );
		
		//strcpy( client->pers.lastTeam, savedTeamName );
		client->pers.enterTime = savedTime;
	}
	
	// save things that should be saved before memset-ing the client
	// during loadgame, ps.stats is loaded before this point, so don't trample that data
	int savedstats[ sizeof( client->ps.stats ) ]; // only a few hundred bytes
	assert( sizeof( savedstats ) < 2048 ); // should be allocated if it gets too big

	memcpy( savedstats, client->ps.stats, sizeof( client->ps.stats ) );
	client_persistant_t	savedpers = client->pers;

	memset( client, 0, sizeof( *client ) );

	client->pers = savedpers;
	memcpy( client->ps.stats, savedstats, sizeof( client->ps.stats ) );
	
	client->ps.clientNum = client - game.clients;
	client->ps.vehicleoffset[0] = 0;
	client->ps.vehicleoffset[1] = 0;
	client->ps.vehicleoffset[2] = 0;
	client->ps.in_vehicle = false;

	client->ps.viewheight = (int) sv_defaultviewheight->value;
	client->ps.pm_defaultviewheight = (int) sv_defaultviewheight->value;
}

void Player::InitState( void )
{
	gibbed             = false;
	pain               = 0;
	accumulated_pain   = 0;
	nextpaintime       = 0.0f;
	knockdown          = false;
	pain_dir           = PAIN_NONE;
	pain_type          = MOD_NONE;
	takedamage			 = DAMAGE_AIM;
	deadflag				 = DEAD_NO;
	flags					&= ~FL_NO_KNOCKBACK;
	flags					|= ( FL_BLOOD | FL_DIE_GIBS );
	
	if ( !com_blood->integer )
	{
		flags &= ~FL_BLOOD;
		flags &= ~FL_DIE_GIBS;
	}
}

/*
void Player::InitArmorValue
   (
	void
	)

	{
   //ArmorValue = 0;
	}
*/

void Player::InitHealth( void )
{
	// Don't do anything if we're loading a server game.
	// This is either a loadgame or a restart
	if ( LoadingSavegame )
	{
		return;
	}
	
	// reset the health values
	health	  = 100;
	max_health = 100;
}

void Player::InitModel( const char *modelName )
{
	orientation_t orient;
	int anim;
	int tagnum;
	int i;
	
	
	// Reset all surface to visible
	
	for ( i = 0 ; i < MAX_MODEL_SURFACES ; i++ )
	{
		edict->s.surfaces[ i ] &= ~MDL_SURFACE_NODRAW;
	}
	
	if ( modelName )
		setModel( modelName );
	else
		setModel( str( g_playermodel->string ) + ".tik" );
	
	SetControllerTag( HEAD_TAG,   gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) );
	SetControllerTag( TORSO_TAG,  gi.Tag_NumForName( edict->s.modelindex, "Bip01 Spine1" ) );
	SetControllerTag( R_ARM_TAG,  gi.Tag_NumForName( edict->s.modelindex, R_ARM_NAME ) );
	SetControllerTag( L_ARM_TAG,  gi.Tag_NumForName( edict->s.modelindex, L_ARM_NAME ) );
	SetControllerTag( MOUTH_TAG,   gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ) );
	
	anim = gi.Anim_NumForName( edict->s.modelindex, "stand_idle" );
	
	tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 R Foot" ) & TAG_MASK;
	orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL );
	base_rightfoot_pos = orient.origin;
	base_rightfoot_pos.z = 0;
	
	tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 L Foot" ) & TAG_MASK;
	orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL );
	base_leftfoot_pos = orient.origin;
	base_leftfoot_pos.z = 0;
	
	showModel();
	
	yawing_left = false;
	yawing_right = false;
}

void Player::InitPhysics( void )
{
	// Physics stuff
	oldvelocity = vec_zero;
	velocity    = vec_zero;
	old_v_angle = v_angle;
	gravity     = 1.0;
	falling     = false;
	hardimpact  = false;
	mass			= 200;
	setContents( CONTENTS_BODY );
	memset( &last_ucmd, 0, sizeof( last_ucmd ) );

	_forcedMoveType = PM_NONE;
}

void Player::InitWorldEffects( void )
{
	// world effects
	next_drown_time    = 0;
	next_painsound_time    = 0;
	air_finished       = level.time + 20.0f;
	old_waterlevel     = 0;
	drown_damage       = 0.0f;
}

void Player::InitWeapons( void )
{
	// Don't do anything if we're loading a server game.
	// This is either a loadgame or a restart
	if ( LoadingSavegame )
	{
		return;
	}

	ClearNewActiveWeapon();
}

void Player::InitInventory( void )
{
}

void Player::InitView( void )
{
	// view stuff
	camera         = NULL;
	v_angle			= vec_zero;
	SetViewAngles( v_angle );
	viewheight	   = STAND_EYE_HEIGHT;
	
	head_target       = NULL;
	targetEnemy  = NULL;
	targetEnemyLocked = false;
	_targetedEntity		= NULL;
	
	// blend stuff
	damage_blend	= vec_zero;
}

void Player::InitStats( void )
{
	if ( p_heuristics )
	{
		p_heuristics->LoadHeuristics();
		p_heuristics->ClearLevelStatistics();
	}
}

void Player::ChooseSpawnPoint( void )
{
	str thread;
	// set up the player's spawn location
	SelectSpawnPoint( origin, angles, thread );
	setOrigin( origin	+ Vector( "0 0 1" ) );
	origin.copyTo( edict->s.origin2 );
	edict->s.renderfx |= RF_FRAMELERP;
	
	KillBox( this );
	
	setAngles( angles );
	SetViewAngles( angles );
	
	if ( thread.length() )
	{
		ExecuteThread( thread );
	}
}

void Player::EndLevel( Event *ev )
{
	// this happens here to avoid the last frame (displayed while loading) from being fullbright or whatever
	setViewMode( "none" );

	if ( health > max_health )
	{
		health = max_health;
	}
	
	if ( health < 1.0f )
	{
		health = 1.0f;
	}

	_updateGameFrames = false;
}

void Player::LevelCleanup( void )
{
	// Do any re-initialization things that affect visuals that aren't supposed to be visible to player
	// reset stats that aren't supposed to carry across missions, i.e. only between sublevels
	// should only be called in single player
	
	if( !gi.areSublevels( level.mapname, level.nextmap ) && client )
	{
		client->ps.stats[ STAT_ENEMIES_KILLED ] = 0;
		client->ps.stats[ STAT_TEAMMATES_KILLED ] = 0;
		client->ps.stats[ STAT_SHOTS_FIRED ] = 0;
		client->ps.stats[ STAT_SHOTS_HIT ] = 0;
		client->ps.stats[ STAT_MISSION_DURATION ] =0;
	}

	client->ps.pm_flags &= ~PMF_NIGHTVISION;
}

void Player::Respawn( Event *ev )
{
	if ( multiplayerManager.inMultiplayer() )
	{
		assert ( deadflag == DEAD_DEAD );
		
		respawn_time = level.time;
		
		Init();
		
		// hold in place briefly
		client->ps.pm_time = 50;
		client->ps.pm_flags |= PMF_TIME_TELEPORT;
		
		return;
	}
	else
	{
#ifdef PRE_RELEASE_DEMO
		gi.SendConsoleCommand( "forcemenu demomain; forcemenu loadsave\n" );
#else
//		gi.SendConsoleCommand( "forcemenu main; forcemenu loadsave\n" );
#endif
		logfile_started = false;
	}
}

void Player::SetDeltaAngles( void )
{
	int i;
	
	// Use v_angle since we may be in a camera
	for( i = 0; i < 3; i++ )
	{
		client->ps.delta_angles[ i ] = ANGLE2SHORT( v_angle[ i ] );
	}
}

void Player::Dead( Event *ev )
{
	
	CancelEventsOfType( EV_Player_Dead );
	
	animate->StopAnimatingAtEnd();
	
	if ( edict->s.torso_anim & ANIM_BLEND )
		animate->StopAnimatingAtEnd(torso);
	
	//if ( ( pain_type == MOD_VAPORIZE || pain_type == MOD_VAPORIZE_COMP || pain_type == MOD_VAPORIZE_DISRUPTOR ) && ( edict->s.eFlags | EF_EFFECT_PHASER ) && ( edict->s.alpha > 0.0f ) )
	if ( ( ( pain_type == MOD_VAPORIZE ) || ( pain_type == MOD_VAPORIZE_COMP ) || 
		( pain_type == MOD_VAPORIZE_DISRUPTOR ) || ( pain_type == MOD_VAPORIZE_PHOTON ) || ( pain_type == MOD_SNIPER ) ) && 
		( edict->s.alpha > 0.0f ) && ( level.time < respawn_time ) )
	{
		PostEvent( EV_Player_Dead, FRAMETIME );
		return;
	}
	
	deadflag = DEAD_DEAD;
	
	// stop animating
	//animate->StopAnimating( legs );
	
	// increase player's death count
	if ( p_heuristics )
		p_heuristics->IncrementNumberOfDeaths();	
	++client->ps.stats[ STAT_DEATHS ];
	
	// Heuristics Stay Persistant Regardless of deaths.
	if ( p_heuristics )
		p_heuristics->SaveHeuristics( this );
	
	if ( multiplayerManager.inMultiplayer() )
	{
		multiplayerManager.playerDead( this );
	}
	else
	{
		//pick random player killed string.
		int i = (rand() % 10) + 1;
		str playerKilled = "PlayerKilled";
		playerKilled += i;
		G_MissionFailed(playerKilled);
	}
	
	_updateGameFrames = false;
}

void Player::Killed( Event *ev )
{
	Entity   *attacker;
	Entity   *inflictor;
	int      meansofdeath;
	Vector direction;
	
	attacker     = ev->GetEntity( 1 );
	inflictor    = ev->GetEntity( 3 );
	meansofdeath = ev->GetInteger( 4 );
	direction    = ev->GetVector( 7 );
	
	pain_type = (meansOfDeath_t)meansofdeath;

	damage_from = direction;
	
	if ( multiplayerManager.inMultiplayer() )
	{
		if ( attacker && attacker->isSubclassOf( Player ) )
			multiplayerManager.playerKilled( this, (Player *)attacker, inflictor, meansofdeath );
		else
			multiplayerManager.playerKilled( this, NULL, inflictor, meansofdeath );
	}

	SpawnDamageEffect( (meansOfDeath_t)meansofdeath );

	animate->ClearTorsoAnim();
	animate->ClearLegsAnim();
	
	deadflag	= DEAD_DYING;
	
	respawn_time = level.time + 1.0f;
	
	edict->clipmask = MASK_DEADSOLID;
	edict->svflags |= SVF_DEADMONSTER;
	
	setContents( CONTENTS_CORPSE );
	
	setMoveType( MOVETYPE_NONE );
	
	angles.x = 0;
	angles.z = 0;
	setAngles( angles );
	
	//
	// change music
	//
	ChangeMusic( "failure", "normal", true );
	
	health = 0;
	
	// Stop targeting monsters
	if( _targetedEntity != NULL)
	{
		_targetedEntity->edict->s.eFlags &= ~EF_DISPLAY_INFO;
		_targetedEntity = NULL;
	}
	
	// Post a dead event just in case
	PostEvent( EV_Player_Dead, 5.0f );
	
	dropRune();
	dropPowerup();
	removeHoldableItem();
	
	// In Deathmatch drop your weapon
	
	if ( multiplayerManager.inMultiplayer()	&& !multiplayerManager.checkFlag( MP_FLAG_NO_DROP_WEAPONS ) &&
		 multiplayerManager.checkRule( "dropWeapons", true ) )
	{
		int i;
		for ( i=0; i<MAX_ACTIVE_WEAPONS; i++ )
		{
			Weapon *weap = activeWeaponList[i];
			
			if ( weap )
            {
				weap->Drop();
				activeWeaponList[i] = NULL;
            }
		}
		
	}

	ClearNewActiveWeapon();
	
	// Now take away the rest of the weapons
	FreeInventory();
	

	_updateGameFrames = false;
}

void Player::Pain( Event *ev )
{
	float		damage,yawdiff;
	Entity	*attacker;
	int      meansofdeath;
	Vector   dir,pos,attack_angle;
	
	damage	      = ev->GetFloat( 1 );
	attacker       = ev->GetEntity( 2 );
	meansofdeath   = ev->GetInteger( 3 );
	pos            = ev->GetVector( 4 );
	dir            = ev->GetVector( 5 );
	
	if ( !damage && !knockdown )
		return;
	
	client->ps.stats[ STAT_LAST_PAIN ] = (int) damage;
	
	// Determine direction
	attack_angle = dir.toAngles();
	yawdiff = torsoAngles[YAW] - attack_angle[YAW] + 180.0f;
	yawdiff = AngleNormalize180( yawdiff );
	
	if ( ( yawdiff > -45.0f ) && ( yawdiff < 45.0f ) )
		pain_dir = PAIN_FRONT;
	else if ( ( yawdiff < -45.0f ) && ( yawdiff > -135.0f ) )
		pain_dir = PAIN_LEFT;
	else if ( ( yawdiff > 45.0f ) && ( yawdiff < 135.0f ) )
		pain_dir = PAIN_RIGHT;
	else
		pain_dir = PAIN_REAR;
	
	// accumulate pain for animation purposes
	if ( take_pain )
	{
		accumulated_pain   += damage;
	}
	
	// Spawn off any damage effect if we get hit with a certain type of damage
	SpawnDamageEffect( (meansOfDeath_t)meansofdeath );
	
	pain_type          = (meansOfDeath_t)meansofdeath;
	
	// Only set the regular pain level if enough time since last pain has passed
	if ( ( level.time > nextpaintime ) && take_pain )
	{
		pain = damage;
	}

	if ( ( level.time > next_painsound_time ) && ( health > 0.0f ) )
	{
		if ( G_GetDatabaseFloat( "MOD", MOD_NumToName( meansofdeath ), "DoPainSound" ) )
		{
			next_painsound_time = level.time + 0.25f + G_Random( 0.25f );
			Sound( "snd_pain", CHAN_VOICE, DEFAULT_VOL, 300.0f );
		}
	}
	
	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame

	damage_blood += damage;

	if ( deadflag == DEAD_NO )
	{
		if ( meansofdeath == MOD_DEATH_QUAD )
			damage_from = vec_zero;
		else
			damage_from = ev->GetVector( 5 ) * damage;
	}


	if ( meansofdeath == MOD_FIRE || meansofdeath == MOD_ON_FIRE )
		damage_blend = damageFireColor;
	else
		damage_blend = damageNormalColor;

	// Determine which side was hit

	if ( damage_from == vec_zero )
	{
		_lastDamagedTimeFront = level.time;
		_lastDamagedTimeLeft  = level.time;
		_lastDamagedTimeRight = level.time;
		_lastDamagedTimeBack  = level.time;
	}
	else
	{
		Vector damageAngles;
		float yaw;

		damageAngles = damage_from * -1.0f;
		damageAngles = damageAngles.toAngles();

		yaw = AngleNormalize180( AngleNormalize180( damageAngles[ YAW ] ) - AngleNormalize180( v_angle[ YAW ] ) );

		if ( ( yaw >= -45.0f ) && ( yaw <= 45.0f ) )
			_lastDamagedTimeFront = level.time;
		else if ( ( yaw > 45.0f ) && ( yaw < 135.0f ) )
			_lastDamagedTimeLeft = level.time;
		else if ( ( yaw < -45.0f ) && ( yaw > -135.0f ) )
			_lastDamagedTimeRight = level.time;
		else
			_lastDamagedTimeBack = level.time;
	}
}

void Player::DoUse( Event *ev )
{
	int		   i;
	int		   num;
	int         touch[ MAX_GENTITIES ];
	gentity_t   *hit;
	Event		   *event;
	Vector	   min;
	Vector	   max;
	Vector	   offset;
	trace_t	   trace;
	Vector	   start;
	Vector	   end;
	float		   t;
	Entity		*usingEntity;
	bool entityActuallyUsed;
	Entity *bestActor;
	

	if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
		return;

	if ( ev->NumArgs() > 0 )
		usingEntity = ev->GetEntity( 1 );
	else
		usingEntity = this;
	
	// if we are in a vehicle, we want to use the vehicle always
	if ( vehicle )
	{
		event = new Event( EV_Use );
		event->AddEntity( this );		
		vehicle->ProcessEvent( event );
		return;
	}
	
	start = origin;
	start.z += client->ps.viewheight;
	end = start + ( yaw_forward * 64.0f );
	
	trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_USABLE, true, "Player::DoUse" );
	
	t = 64.0f * trace.fraction - maxs[ 0 ];
	if ( t < 0.0f )
	{
		t = 0.0f;
	}
	
	offset = yaw_forward * t;
	
	min = start + offset + Vector( "-31 -31 -31" );
	max = start + offset + Vector( "31 31 31" );
	
	num = gi.AreaEntities( min, max, touch, MAX_GENTITIES, qfalse );
	
	entityActuallyUsed = false;
	
	bestActor = getBestActorToUse( touch, num );

	// be careful, it is possible to have an entity in this
	// list removed before we get to it (killtriggered)
	for( i = 0; i < num; i++ )
	{
		hit = &g_entities[ touch[ i ] ];
		if ( !hit->inuse )
		{
			continue;
		}
		
		if ( usingEntity == hit->entity )
			continue;

		if ( hit->entity->isSubclassOf( Actor ) && ( hit->entity != bestActor ) )
			continue;
		
		assert( hit->entity );
		
		event = new Event( EV_Use );
		event->AddEntity( usingEntity );
		hit->entity->ProcessEvent( event );
		
		if ( hit->entity->isSubclassOf( Weapon ) )
			continue;

		if ( hit->entity->isSubclassOf( Projectile ) )
			continue;

		if ( hit->entity->getSolidType() == SOLID_NOT )
			continue;

		entityActuallyUsed = true;
	}
	
	// If we didn't use any object in the world, use our holdable item (if any)
	
	if ( !entityActuallyUsed )
		useHoldableItem();
}

Actor *Player::getBestActorToUse( int *entityList, int count )
{
	int i;
	float bestYawDiff = 1000.0f;
	float yawDiff;
	Actor *bestActor = NULL;
	Actor *currentActor;
	gentity_t *edict;
	Vector dir;
	Vector angles;

	for ( i = 0 ; i < count ; i++ )
	{
		edict = &g_entities[ entityList[ i ] ];

		if ( !edict->inuse || !edict->entity || !edict->entity->isSubclassOf( Actor ) )
			continue;

		currentActor = (Actor *)edict->entity;

		dir = currentActor->centroid - centroid;
		dir.normalize();
		angles = dir.toAngles();

		yawDiff = AngleNormalize180( AngleNormalize180( v_angle[ YAW ] ) - AngleNormalize180( angles[ YAW ] ) );
		yawDiff = abs( (int)yawDiff );

		if ( yawDiff < bestYawDiff )
		{
			bestYawDiff = yawDiff;
			bestActor = currentActor;
		}
	}

	return bestActor;
}

void Player::TouchStuff( const pmove_t *pm )
{
	gentity_t  *other;
	Event		*event;
	int		i;
	int		j;
	
	//
	// clear out any conditionals that are controlled by touching
	//
	toucheduseanim = NULL;
	
	if ( GetMovePlayerMoveType() != PM_NOCLIP )
	{
		// See if we should touch all triggers or just teleporters

		if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
			G_TouchTeleporters( this );
		else
			G_TouchTriggers( this );
	}
	
	// touch other objects
	for( i = 0; i < pm->numtouch; i++ )
	{
		other = &g_entities[ pm->touchents[ i ] ];
		
		for( j = 0; j < i ; j++ )
		{
			gentity_t *ge = &g_entities[ j ];
			
			if ( ge == other )
				break;
		}
		
		if ( j != i )
		{
			// duplicated
			continue;
		}
		
		// Don't bother touching the world
		if ( ( !other->entity ) || ( other->entity == world ) )
		{
			continue;
		}
		
		event = new Event( EV_Touch );
		event->AddEntity( this );
		other->entity->ProcessEvent( event );
		
		event = new Event( EV_Touch );
		event->AddEntity( other->entity );
		ProcessEvent( event );
	}
}

//-----------------------------------------------------
//
// Name:		disableInventory
// Class:		Player
//
// Description:	Disables the player's inventory
//
// Parameters:	None
//
// Returns:		None
//-----------------------------------------------------
void Player::disableInventory( void )
{
	client->ps.pm_flags |= PMF_DISABLE_INVENTORY;
}


//-----------------------------------------------------
//
// Name:		enableInventory
// Class:		Player
//
// Description:	Enables the players inventory
//
// Parameters:	None
//
// Returns:		None
//-----------------------------------------------------
void Player::enableInventory( void )
{
	client->ps.pm_flags &= ~PMF_DISABLE_INVENTORY;
}

usercmd_t Player::GetLastUcmd(void) 
{
	return last_ucmd;
}

void Player::GetMoveInfo( pmove_t *pm )
{
	moveresult = pm->moveresult;
	
	if ( !deadflag || ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) ) )
	{
		v_angle[ 0 ] = pm->ps->viewangles[ 0 ];
		v_angle[ 1 ] = pm->ps->viewangles[ 1 ];
		v_angle[ 2 ] = pm->ps->viewangles[ 2 ];
		
		if ( moveresult == MOVERESULT_TURNED )
		{
			angles.y = v_angle[ 1 ];
			setAngles( angles );
			SetViewAngles( angles );
		}
	}
	
	setOrigin( Vector( pm->ps->origin[ 0 ], pm->ps->origin[ 1 ], pm->ps->origin[ 2 ] ) );
	velocity = Vector( pm->ps->velocity[ 0 ], pm->ps->velocity[ 1 ], pm->ps->velocity[ 2 ] );
	
	if ( ( client->ps.pm_flags & PMF_FROZEN ) || ( client->ps.pm_flags & PMF_NO_MOVE ) )
	{
		velocity = vec_zero;
	}
	else
	{
		if ( !vehicle )
			setSize( pm->mins, pm->maxs );
		else
			setSize( vehicle->_DriverBBoxMins , vehicle->_DriverBBoxMaxs );
	}
	
	// water type and level is set in the predicted code
	waterlevel = pm->waterlevel;
	watertype = pm->watertype;
	
	// Set the ground entity
	groundentity = NULL;
	if ( pm->ps->groundEntityNum != ENTITYNUM_NONE )
	{
		groundentity = &g_entities[ pm->ps->groundEntityNum ];
		airspeed = 350;
	}
}

void Player::SetMoveInfo( pmove_t *pm, const usercmd_t *ucmd )
{
	Vector move;
	
	//float test;
	//test = velocity[0];
	//test = velocity[1];
	//test = velocity[2];
	// set up for pmove
	memset( pm, 0, sizeof( pmove_t ) );
	
	velocity.copyTo( client->ps.velocity );
	
	pm->ps             = &client->ps;
	
	if ( ucmd )
	{
		pm->cmd            = *ucmd;
	}
	
	//pm->tracemask      = MASK_PLAYERSOLID;
	pm->tracemask      = edict->clipmask;
	pm->trace          = gi.trace;
	pm->pointcontents  = gi.pointcontents;
	pm->trypush        = TryPush;
	
	pm->ps->origin[ 0 ] = origin.x;
	pm->ps->origin[ 1 ] = origin.y;
	pm->ps->origin[ 2 ] = origin.z;
	
	pm->ps->velocity[ 0 ] = velocity.x;
	pm->ps->velocity[ 1 ] = velocity.y;
	pm->ps->velocity[ 2 ] = velocity.z;
	
	// save off pm_runtime
	if ( pm->ps->pm_runtime )
		pm_lastruntime = pm->ps->pm_runtime;
}

pmtype_t Player::GetMovePlayerMoveType( void )
{
	if ( multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) )
	{
		return PM_SPECTATOR_FOLLOW;
	}
	else if ( multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FREEFORM ) )
	{
		return PM_NOCLIP;
	}
	else if ( multiplayerManager.isPlayerSpectator( this ) )
	{
		return PM_SPECTATOR;
	}
	else if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		return PM_NOCLIP;
	}
	else if ( deadflag )
	{
		return PM_DEAD;
	}
	else if ( _forcedMoveType != PM_NONE )
	{
		return _forcedMoveType;
	}
	else
	{
		return PM_NORMAL;
	}
}

void Player::CheckGround( void )
{
	pmove_t pm;
	
	SetMoveInfo( &pm, current_ucmd );
	Pmove_GroundTrace( &pm );
	GetMoveInfo( &pm );
}

qboolean Player::AnimMove( const Vector &move, Vector *endpos )
{
	trace_t trace;
	int     mask;
	Vector  start( origin );
	Vector  end( origin + move );
	
	mask = MASK_PLAYERSOLID;
	
	// test the player position if they were a stepheight higher
	trace = G_Trace( start, mins, maxs, end, this, mask, true, "AnimMove" );
	if ( trace.fraction < 1 )
	{
		return TestMove( move, endpos );
	}
	else
	{
		if ( endpos )
		{
			*endpos = trace.endpos;
		}
		
		return true;
	}
}

qboolean Player::TestMove( const Vector &move, Vector *endpos )
{
	trace_t trace;
	Vector pos( origin + move );
	
	trace = G_Trace( origin, mins, maxs, pos, this, edict->clipmask, true, "TestMove" );
	if ( trace.allsolid )
	{
		// player is completely trapped in another solid
		if ( endpos )
		{
			*endpos = origin;
		}
		return false;
	}
	
	if ( trace.fraction < 1.0f )
	{
		Vector up( origin );
		up.z += STEPSIZE;
		
		trace = G_Trace( origin, mins, maxs, up, this, edict->clipmask, true, "TestMove" );
		if ( trace.fraction == 0.0f )
		{
			if ( endpos )
            {
				*endpos = origin;
            }
			return false;
		}
		
		Vector temp( trace.endpos );
		Vector end( temp + move );
		
		trace = G_Trace( temp, mins, maxs, end, this, edict->clipmask, true, "TestMove" );
		if ( trace.fraction == 0.0f )
		{
			if ( endpos )
            {
				*endpos = origin;
            }
			return false;
		}
		
		temp = trace.endpos;
		
		Vector down( trace.endpos );
		down.z = origin.z;
		
		trace = G_Trace( temp, mins, maxs, down, this, edict->clipmask, true, "TestMove" );
	}
	
	if ( endpos )
	{
		*endpos = trace.endpos;
	}
	
	return true;
}

//--------------------------------------------------------------
//
// Name:			showObjectInfo
// Class:			Player
//
// Description:		This build the string to be displayed when
//					the sv_showinfo cvar is set.
//
// Parameters:		None
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::showObjectInfo()
{
	str desc;
	char addstr[512];
	
	Entity *ent = (Entity*)atobject;
	desc = "tiki  : " + ent->model + "\n";
	sprintf(addstr,"entnum: %d\n",ent->entnum);
	desc += addstr;
	sprintf(addstr,"origin: (%.2f, %.2f, %.2f)\n",ent->origin.x, ent->origin.y, ent->origin.z);
	desc += addstr;
	sprintf(addstr,"angles: (%.2f, %.2f, %.2f)\n",ent->angles.x, ent->angles.y, ent->angles.z);
	desc += addstr;
	sprintf(addstr,"bounds Mins: ( %.2f, %.2f, %.2f )\n", ent->mins.x, ent->mins.y, ent->mins.z);
	desc += addstr;
	sprintf(addstr,"bounds Maxs: ( %.2f, %.2f, %.2f )\n", ent->maxs.x, ent->maxs.y, ent->maxs.z );
	desc += addstr;
	sprintf(addstr,"size: ( %.2f, %.2f, %.2f )\n", ent->size.x, ent->size.y, ent->size.z );
	desc += addstr;
	sprintf(addstr,"velocity: ( %.2f, %.2f, %.2f )\n\n", ent->velocity.x, ent->velocity.y, ent->velocity.z );
	desc += addstr;
	
	if ( ent->isSubclassOf(Actor) )
	{
		Actor *act = (Actor *)ent;
		desc += "--------- SUBCLASS OF ACTOR ------------\n";
		sprintf(addstr, "Class ID: %s\n", act->getClassID() );
		desc += addstr;
		sprintf(addstr, "Classname: %s\n", act->getClassname() );
		desc += addstr;
		sprintf(addstr, "Name: %s\n", act->name.c_str() );
		desc += addstr;
		if ( act->part_name.length() > 0 )
		{
			sprintf(addstr, "Part name: %s\n", act->part_name.c_str() );
			desc += addstr;
		}
		sprintf(addstr, "Targetname: %s\n", act->TargetName() );
		desc += addstr;
		
		if ( act->behavior )
			sprintf(addstr, "Behavior: %s\n", act->behavior->getClassname() );
		else
			sprintf(addstr, "Behavior: NULL -- was '%s'\n", act->currentBehavior.c_str() );
		desc += addstr;
		
		if ( act->headBehavior )
			sprintf(addstr, "Head Behavior: %s\n", act->headBehavior->getClassname() );
		else
			sprintf(addstr, "Head Behavior: NULL -- was %s\n", act->currentHeadBehavior.c_str() );
		desc += addstr;
		
		if ( act->eyeBehavior )
			sprintf(addstr, "Eye Behavior: %s\n", act->eyeBehavior->getClassname() );
		else
			sprintf(addstr, "Eye Behavior: NULL -- was %s\n", act->currentEyeBehavior.c_str() );
		desc += addstr;
		
		if ( act->torsoBehavior )
			sprintf(addstr, "Torso Behavior: %s\n", act->torsoBehavior->getClassname() );
		else
			sprintf(addstr, "Torso Behavior: NULL -- was %s\n", act->currentTorsoBehavior.c_str() );
		desc += addstr;
		
		if ( act->currentState )
			sprintf(addstr, "State: %s\n", act->currentState->getName() );
		else
			sprintf(addstr, "State: NONE\n" );
		desc += addstr;
		
		if ( act->GetActorFlag( ACTOR_FLAG_AI_ON ) )
			sprintf(addstr, "AI is ON\n" );
		else
			sprintf(addstr, "AI is OFF\n" );
		desc += addstr;
		
		if ( act->isThinkOn() )
			sprintf(addstr, "Think is ON\n" );
		else
			sprintf(addstr, "Think is OFF\n" );
		desc += addstr;
		
		if ( act->mode == ACTOR_MODE_IDLE )
			sprintf(addstr, "Mode: IDLE\n" );
		else if ( act->mode == ACTOR_MODE_AI )
			sprintf(addstr, "Mode: AI\n" );
		else if ( act->mode == ACTOR_MODE_SCRIPT )
			sprintf(addstr, "Mode: SCRIPT\n" );
		else if ( act->mode == ACTOR_MODE_TALK )
			sprintf(addstr, "Mode: TALK\n" );
		desc += addstr;
		
		sprintf(addstr, "Actortype: %d\n", act->actortype );
		desc += addstr;
		sprintf(addstr, "Anim: %s\n", act->animname.c_str() );
		desc += addstr;
		sprintf(addstr, "Health: %f\n", act->health );
		desc += addstr;
		
		sprintf(addstr, "CurrentEnemy: " );
		desc += addstr;
		
		// Get our current enemy
		Entity *currentEnemy;
		currentEnemy = act->enemyManager->GetCurrentEnemy();
		if ( currentEnemy )
			sprintf(addstr, "%d : '%s'\n", currentEnemy->entnum, currentEnemy->targetname.c_str() );
		else
			sprintf(addstr, "None\n" );
		desc += addstr;
		
		switch( act->deadflag )
		{
		case DEAD_NO :
			sprintf(addstr, "deadflag: NO\n" );
			break;
		case DEAD_DYING :
			sprintf(addstr, "deadflag: DYING\n" );
			break;
		case DEAD_DEAD :
			sprintf(addstr, "deadflag: DEAD\n" );
			break;
		case DEAD_RESPAWNABLE :
			sprintf(addstr, "deadflag: RESPAWNABLE\n" );
			break;
		}
		desc += addstr;
		
	}
		
	G_SendCommandToPlayer( edict, "ui_addhud showinfo");
	G_EnableWidgetOfPlayer( edict, "InfoHUD", true );
	G_SetWidgetTextOfPlayer( edict, "InfoHUD", desc);		
}

//--------------------------------------------------------------
//
// Name:			clearActionType
// Class:			Player
//
// Description:		Clears the action icon on the hud and NULL's
//					out use entity.
//
// Parameters:		None
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::clearActionType()
{
	if ( lastActionType.length() )
	{
		G_EnableWidgetOfPlayer( edict, lastActionType.c_str(), false );
		//G_EnableWidgetOfPlayer( edict, "ActionTextArea", false );
		lastActionType = "";
	}
	
	atobject = NULL;
}

//--------------------------------------------------------------
//
// Name:			handleUseEntity
// Class:			Player
//
// Description:		Called from CheckMoveFlags to handle the 
//					case that our trace hit an entity.
//					We test to see if this is a usable entity
//
// Parameters:		Entity *ent -- Entity to test
//					float real_dist -- The real distance away from this entity,
//										ignoring pitch.
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::handleUseEntity(Entity *ent, float real_dist)
{
	if ( ent->hasUseData() )
	{
		// See if this entity is within distance to use.
		if ( real_dist > ent->useData->getUseMaxDist() )
		{
			clearActionType();
			return;
		}
		
		// Check to see if this entity is usable (due to count)
		if ( ent->useData->getUseCount() == 0)
		{
			// Our count is 0, we can't use this entity anymore,
			// so delete the useData for him.
			delete ent->useData;
			ent->useData = NULL;
			clearActionType();
			return;
		}
		
		// If he has a usetype show the HUD icon
		if ( ent->useData->getUseType().length() > 0 && !lastActionType.length() )
		{
			G_EnableWidgetOfPlayer( edict, ent->useData->getUseType().c_str(), true );
			//G_EnableWidgetOfPlayer( edict, "ActionTextArea", true );
			//G_SetWidgetTextOfPlayer( edict, "ActionTextArea", ent->getArchetype().c_str());
			lastActionType = ent->useData->getUseType();
		}
	}
	else
		clearActionType();
}

//--------------------------------------------------------------
//
// Name:			handleUseObject
// Class:			Player
//
// Description:		Called from CheckMoveFlags to handle the 
//					case that our trace hit a useobject
//
// Parameters:		UseObject *uo
//
// Returns:			None		
//
//--------------------------------------------------------------
void Player::handleUseObject(UseObject *uo)
{
	if ( uo->canBeUsed( origin, yaw_forward ) )
	{
		if ( uo->action_type.length() > 0 && !lastActionType.length() )
		{
			G_EnableWidgetOfPlayer( edict, uo->action_type.c_str(), true );
			lastActionType = uo->action_type;
		}
	}
	else // Not usable, clear HUD icon and data
		clearActionType();
}

void Player::CheckMoveFlags()
{
	trace_t trace;
	Vector start, end, fwd, yfwd;
	float oldsp, tracelen, real_dist;
	int content;
	Vector olddir( oldvelocity.x, oldvelocity.y, 0.0f );
	
	//MatrixTransformVector( base_righthand_pos, orientation, righthand_pos );
	//MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos );
	MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos );
	MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos );
	//righthand_pos += origin;
	//lefthand_pos += origin;
	rightfoot_pos += origin;
	leftfoot_pos += origin;
	
	//
	// Check if moving forward will cause the player to fall
	//
	start = origin + ( yaw_forward * 52.0f );
	end	= start;
	end.z -= STEPSIZE * 2.0f;
	
	trace = G_Trace( start, mins, maxs, end, this, edict->clipmask, true, "CheckMoveFlags" );
	canfall = !( trace.fraction < 1.0f );
	
	CheckGround();
	if ( !groundentity && ( velocity.z < -250.0f ) )
	{
		falling = true;
		hardimpact = false;
	}
	else
	{
		hardimpact = ( oldvelocity.z < -1000.0f );
		falling = false;
	}
	
	// check for running into walls
	oldsp = VectorNormalize( olddir );
	if ( ( oldsp > 250.0f ) && ( velocity * olddir < 5.0f ) )
		moveresult = MOVERESULT_HITWALL;
	
	//
	// Check if the useobject or useentity
	//
	start = origin;
	start[ 2 ] += viewheight;	
	GetVAngles().AngleVectors(&fwd);
	yfwd = yaw_forward;
	yfwd.normalize();
	
	// Normal test trace
	tracelen = 96.0f;
	content = MASK_USABLE;
	
	// If we have sv_showinfo on, use a better, longer trace.
	if ( sv_showinfo->integer )
	{
		_infoHudOn = true;
		tracelen = sv_showinfodist->value;
		
		if ( sv_showinfo->integer == 1 )
			content = MASK_ALL;
		else
			content = CONTENTS_BODY | CONTENTS_CORPSE;
	}
	
	// See if the cvar has been turned off, if so, clear the hud.
	if ( !sv_showinfo->integer && _infoHudOn )
	{
		G_EnableWidgetOfPlayer( edict, "InfoHUD", false );
		_infoHudOn = false;
	}
	
	float tracedist = tracelen / (Vector::Dot(fwd, yfwd)); // lengthen the trace to compensate for pitch
	end	= start + ( fwd * tracedist );
	trace = G_Trace( start, Vector(-5,-5,5), Vector(-5,-5,5), end, this, content, true, "CheckMoveFlags -- Checking for UseEntities" );
	if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) )
	{
		atobject = trace.ent->entity;
		if ( trace.startsolid )
			trace.fraction = 0.0;
		atobject_dist = trace.fraction * tracedist;
		real_dist = (atobject_dist / tracedist) * tracelen; // real distance ignoring pitch
		atobject_dir.setXYZ( -trace.plane.normal[ 0 ], -trace.plane.normal[ 1 ], -trace.plane.normal[ 2 ] );
		
		if ( sv_showinfo->integer )
			showObjectInfo();
		
		if ( atobject->isSubclassOf( UseObject ) )
		{
			UseObject *uo = (UseObject *)(Entity *)atobject;
			handleUseObject(uo);
		}
		else 
		{
			Entity *ent = (Entity *)atobject;
			handleUseEntity(ent, real_dist); // see if this entity is usable
		}
	}
	else // Didn't hit anything
	{
		if ( sv_showinfo->integer )
		{
			G_EnableWidgetOfPlayer( edict, "InfoHUD", false );
		}
		
		clearActionType();
	}
	
	/*
	//
	// get the distances the player can move left, right, forward, and back
	//
	if ( ( movecontrol == MOVECONTROL_USER ) || ( movecontrol == MOVECONTROL_LEGS ) )
	{
		move_left_dist     = TestMoveDist( yaw_left * 128.0f );
		move_right_dist    = TestMoveDist( yaw_left * -128.0f );
		move_backward_dist = TestMoveDist( yaw_forward * -128.0f );
		move_forward_dist  = TestMoveDist( yaw_forward * 128.0f );
	}
	else
	{
		move_left_dist     = CheckMoveDist( yaw_left * 2.0f );
		move_right_dist    = CheckMoveDist( yaw_left * -2.0f );
		move_backward_dist = CheckMoveDist( yaw_forward * -2.0f );
		move_forward_dist  = CheckMoveDist( yaw_forward * 2.0f );
	}
	*/
}

qboolean Player::CheckMove( const Vector &move, Vector *endpos )
{
	return AnimMove( move, endpos );
}

void Player::ApplyPowerupEffects(int &moveSpeed)
{
	if ( _powerup )
		moveSpeed *= (int)_powerup->getMoveMultiplier();

	if ( _rune )
		moveSpeed *= (int)_rune->getMoveMultiplier();

	/* if ( poweruptype == POWERUP_SPEED )
		moveSpeed *= 2;
		
	if ( poweruptype == POWERUP_STEALTH )
	{
		if ( !(flags & FL_NOTARGET) )
			flags ^= FL_NOTARGET;
	}
		
	if ( poweruptype == POWERUP_PROTECTION )
	{
		if ( !(flags & FL_GODMODE) )
			flags ^= FL_GODMODE;
	}

	if ( poweruptype == POWERUP_FLIGHT )
	{
		client->ps.pm_flags |= PMF_FLIGHT;
	}	
	
	if ( poweruptype == POWERUP_ACCURACY )
	{
		// Tell the weapon we have the accuracy powerup
		Weapon *weap;
		weap = GetActiveWeapon( WEAPON_DUAL );
		if ( weap )
			weap->SetAccuracyPowerup( true );
	} */
}

//----------------------------------------------------------------
// Name:			applyWeaponSpeedModifiers
// Class:			Player
//
// Description:		Applies any weapon speed modifiers
//
// Parameters:		int *moveSpeed					- the move speed to modify
//
// Returns:			none
//----------------------------------------------------------------

void Player::applyWeaponSpeedModifiers( int *moveSpeed )
{
	Weapon *weap;

	weap = GetActiveWeapon( WEAPON_DUAL );

	if ( weap )
	{
		*moveSpeed *= (int) weap->getMoveSpeedModifier();
	}

}

void Player::ClientMoveLadder( usercmd_t *ucmd )
{	
	if ( _onLadder )
	{		
		// Get off the ladder if the player jumps, the player touches the ground while moving down, or the player
		//   is no longer on the ladder physically

		if ( ucmd->upmove > 0 )
		{
			velocity = _ladderNormal * sv_jumpvelocity->value;
			_nextLadderTime = level.time + 0.20;
		}
		else
		{
			Vector climbDir;
			Vector climbAngles;
			Vector playerForward;
			Vector playerLeft;
			Vector forward;
			Vector left;
			Vector climbForward;
			Vector climbLeft;
			Vector climbUp;
			bool goingUp;
			float upAmount;
			float rightAmount;
			float forwardAmount;
			trace_t trace;
			bool pushForward;
			
			// Change the forward velocity to directly up or down depending on how the player is facing and whether
			//   he is trying to go forwards or backwards

			v_angle.AngleVectors( &playerForward, &playerLeft );
			
			if ( playerForward.z > 0.0f )
				goingUp = true;
			else
				goingUp = false;

			if ( ucmd->forwardmove < 0 )
				goingUp = !goingUp;

			// Get the ladder climbing angles

			climbDir = -_ladderNormal;

			climbAngles = climbDir.toAngles();
			climbAngles.AngleVectors( &climbForward, &climbLeft, &climbUp );

			// Determine if we want to push against the ladder
			
			trace = G_Trace( origin, mins, maxs, origin + climbForward * 4, this, edict->clipmask, true, "ClientMoveLadder" );

			if ( trace.fraction < 1.0f )
				pushForward = false;
			else
				pushForward = true;

			// Get the forward/backwards movement of the player

			if ( ucmd->forwardmove < 0 )
				playerForward *= -1;

			// Get the up/down amount from the forward movement 

			upAmount = playerForward * climbUp;

			if ( ( upAmount >= -0.1f ) && ( upAmount <= 0.1f ) )
				upAmount = 0.1f;

			forwardAmount =  abs( (int)(playerForward * climbForward) );

			if ( upAmount >= 0.0f )
				upAmount += forwardAmount;
			else
				upAmount -= forwardAmount;

			// Get the left/right amount from the forward movement 

			rightAmount = playerForward * climbLeft;

			if ( ( rightAmount >= -0.1f ) && ( rightAmount <= 0.1f ) )
				rightAmount = 0.0f;

			// Calculate the forward movement

			forward = ( climbUp * upAmount + climbLeft * rightAmount ) * 0.5f;
			forward.normalize();

			if ( pushForward )
			{
				forward = ( climbForward + forward ) * 0.5f;
			}

			// Get the left/right movement of the player

			if ( ucmd->rightmove > 0 )
				playerLeft *= -1;

			// Get the up/down amount from the strafe movement 

			upAmount = playerLeft * climbUp;

			forwardAmount = playerLeft * climbForward;

			upAmount += forwardAmount;

			// Get the left/right amount from the strafe movement 

			rightAmount = playerLeft * climbLeft;

			if ( ( rightAmount >= -0.1f ) && ( rightAmount <= 0.1f ) )
				rightAmount = 0.0f;

			// Calculate the strafe movement

			left = ( climbUp * upAmount + climbLeft * rightAmount ) * 0.5f;
			left.normalize();

			if ( pushForward )
			{
				left = ( climbForward + left ) * 0.5f;
			}

			// Change our velocity based on the forward/strafe movements calculated

			forward.normalize();

			forward *= abs( ucmd->forwardmove ) / 127.0f * sv_maxspeed->value * 0.75f;

			left *= abs( ucmd->rightmove ) / 127.0f * sv_maxspeed->value * 0.75f;
			
			velocity = forward + left;
			
			ucmd->forwardmove = 0;
			
			client->ps.pm_flags |= PMF_NO_GRAVITY;

			// If we have a groundentity and we are going down get off the ladder

			if ( groundentity && !goingUp )
			{
				_nextLadderTime = level.time + 0.20;
			}
		}

		_onLadder = false;
	}
}

void Player::ClientMoveDuck( usercmd_t *ucmd )
{
	if ( client->ps.pm_flags & PMF_DUCKED )
	{
		// See if we can stand where we are, otherwise we have to stay ducked.
		Vector newmins( mins );
		Vector newmaxs( maxs );
		Vector tmporg( origin );
		trace_t trace;
		tmporg[ 2 ] += 2.0f;
		newmins[ 2 ] = MINS_Z;
		newmaxs[ 2 ] = MAXS_Z;
		trace = G_Trace( tmporg, newmins, newmaxs, tmporg, this, edict->clipmask, true, "checkcanstand" );
		if ( trace.startsolid )
		{
			client->ps.pm_flags |= PMF_DUCKED;
		}
		else
		{
			client->ps.pm_flags &= ~PMF_DUCKED;
		}
	}
	
	if ( ucmd->upmove < 0 && sv_cancrouch->integer )
		client->ps.pm_flags |= PMF_DUCKED;
}

//-----------------------------------------------
//	Name:			ClientMoveLean
//
//	Class:			Player
//
//	Description:	Leans the player
//
//	Parameters:		ucmd - the structure of user commands from the client
//
//	Returns:		None
//-----------------------------------------------
void Player::ClientMoveLean( usercmd_t *ucmd )
{
/*
	client->ps.pm_flags &= ~(PMF_LEAN_RIGHT | PMF_LEAN_LEFT);
	
	if(ucmd->lean > 0)
	{
		client->ps.pm_flags |= PMF_LEAN_RIGHT;
	}
	
	if(ucmd->lean < 0)
	{
		client->ps.pm_flags |= PMF_LEAN_LEFT;
	}
	*/
}

void Player::ClientMoveFlagsAndSpeeds( int moveSpeed, int noclipSpeed, int crouchSpeed, int airSpeed )
{
	if ( level.playerfrozen || ( flags & FL_STUNNED ) )
	{
		client->ps.pm_flags |= PMF_FROZEN;
	}
	
	if ( ( flags & FL_IMMOBILE ) || ( flags & FL_PARTIAL_IMMOBILE ) )
	{
		client->ps.pm_flags |= PMF_NO_MOVE;
		//client->ps.pm_flags |= PMF_NO_PREDICTION;
	}
	
	if ( movecontrol == MOVECONTROL_ANIM )
		client->ps.pm_flags |= PMF_NO_PREDICTION;
	
	if ( !groundentity )
	{
		client->ps.speed = airSpeed;
	}
	else if ( getMoveType() == MOVETYPE_NOCLIP || ( waterlevel > 1 ) )
	{
		// No clip underwater speeds
		if ( last_ucmd.buttons & BUTTON_RUN )
			client->ps.speed = noclipSpeed;
		else
			client->ps.speed = noclipSpeed/2;
	}
	else
	{
		// Duck speed
		if ( client->ps.pm_flags & PMF_DUCKED )
		{
			client->ps.speed = crouchSpeed;	
		}
		else
		{
			// Normal run/walk speed
			if ( sv_useanimmovespeed->integer || movecontrol == MOVECONTROL_ANIM )
			{
				client->ps.speed = (int) animspeed;
			}
			else
			{
				if ( last_ucmd.buttons & BUTTON_RUN )
					client->ps.speed = moveSpeed;
				else
					client->ps.speed = moveSpeed/2;
			}
		}
	}
	
	if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		// Normal noclip speed (run/walk)
		if ( last_ucmd.buttons & BUTTON_RUN )
			client->ps.speed = noclipSpeed;
		else
			client->ps.speed = noclipSpeed/2;
	}
	
	if ( sv_instantjump->integer )
		client->ps.instantJump = true;
	else
		client->ps.instantJump = false;

	if ( sv_strafeJumpingAllowed->integer )
		client->ps.strafeJumpingAllowed = true;
	else
		client->ps.strafeJumpingAllowed = false;
}

void Player::ClientMoveMisc( usercmd_t *ucmd )
{
	// We're falling, can't move around in the air
	if ( client->ps.feetfalling && ( waterlevel < 2 ) && !( client->ps.pm_time ) )
	{
		ucmd->forwardmove = 0;
		ucmd->rightmove = 0;
	}
	
	// Fake player, cancel any movement input
	if ( fakePlayer_active || movecontrol == MOVECONTROL_ANIM )
	{
		ucmd->forwardmove = 0;
		ucmd->rightmove = 0;
		ucmd->upmove = 0;
	}
}

void Player::ClientMove( usercmd_t *ucmd )
{
	pmove_t pm;
	Vector move;
	
	int moveSpeed;
	int noclipSpeed = (int) sv_noclipspeed->value;
	int crouchSpeed;
	int airSpeed;
	
	if ( world->getPhysicsVar( WORLD_PHYSICS_MAXSPEED ) != -1.0f )
		moveSpeed = (int) world->getPhysicsVar( WORLD_PHYSICS_MAXSPEED );
	else
		moveSpeed = (int) sv_maxspeed->value;
	
	if ( sv_crouchspeed->value > 0.0f )
		crouchSpeed = (int) sv_crouchspeed->value;
	else
		crouchSpeed = (int)((float)moveSpeed * 0.5);
	
	if ( sv_airmaxspeed->value > 0.0f )
		airSpeed = (int) sv_airmaxspeed->value;
	else
		airSpeed = moveSpeed;
	
	// Save off current origin
	oldorigin = origin;
	
	client->ps.pm_type = GetMovePlayerMoveType();
	
	// Clear movement flags
	client->ps.pm_flags &= ~( PMF_FLIGHT | PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_HAVETARGET | PMF_NO_GRAVITY );
	
	// Modify speeds 
	
	ApplyPowerupEffects( moveSpeed );
	applyWeaponSpeedModifiers( &moveSpeed );
	
	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.applySpeedModifiers( this, &moveSpeed );
	
	ApplyPowerupEffects( crouchSpeed );
	applyWeaponSpeedModifiers( &crouchSpeed );
	
	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.applySpeedModifiers( this, &crouchSpeed );
	
	ApplyPowerupEffects( airSpeed );
	applyWeaponSpeedModifiers( &airSpeed );
	
	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.applySpeedModifiers( this, &airSpeed );
	
	// Handle ducking
	ClientMoveDuck(ucmd);
	
	//Handle leaning
	ClientMoveLean(ucmd);
	
	// Movement speed and mobility flags
	ClientMoveFlagsAndSpeeds(moveSpeed, noclipSpeed, crouchSpeed, airSpeed);
	
	// Misc movement stuff, like falling, and fake player control
	ClientMoveMisc(ucmd);
	
	// Handle ladder situations
	ClientMoveLadder(ucmd);
	
	// Gravity modifier
	client->ps.gravity = (int)(sv_currentGravity->value * gravity);
	
	// Perform the move
	CheckGround();
	SetMoveInfo( &pm, ucmd );
	Pmove( &pm );
	GetMoveInfo( &pm );
	ProcessPmoveEvents( pm.pmoveEvent );
	
	// Animation driven stuff happens here
	if ( ( getMoveType() == MOVETYPE_NOCLIP ) || !( client->ps.pm_flags & PMF_NO_PREDICTION ) )
	{
		total_delta = vec_zero;
	}
	else
	{
		if ( movecontrol == MOVECONTROL_ABSOLUTE )
		{
			velocity = vec_zero;
		}
		
		if ( total_delta != vec_zero )
		{
			// Animation driven move
			MatrixTransformVector( total_delta, orientation, move );
			CheckMove( move, &origin );
			setOrigin( origin );
			CheckGround();
		}
	}
	
	total_delta = vec_zero;
	
	TouchStuff( &pm );
	
	// Debug output
	if ( ( whereami->integer ) && ( origin != oldorigin ) )
		gi.DPrintf( "x %8.2f y%8.2f z %8.2f area %2d\n", origin[ 0 ], origin[ 1 ], origin[ 2 ], edict->areanum );
}

/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*/
void Player::ClientThink( Event *ev )
{
	// sanity check the command time to prevent speedup cheating
	if ( current_ucmd->serverTime > level.inttime )
	{
		//
		// we don't want any future commands, these could be from the previous game
		//
		return;
	   }
	
	if ( current_ucmd->serverTime < ( level.inttime - 1000 ) )
	{
		current_ucmd->serverTime = level.inttime - 1000;
	   }
	
	if ( ( current_ucmd->serverTime - client->ps.commandTime ) < 1 )
	{
		return;
	}
	
	_started = true;

	last_ucmd   = *current_ucmd;
	new_buttons	= current_ucmd->buttons & ~buttons;
	buttons		= current_ucmd->buttons;
	
	// Handle Heath Regen if it's in the gameplay database
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = "CurrentPlayer.HPRegen";
	if ( gpm->hasObject(scopestr) )
	{
		int value = (int)gpm->getFloatValue(scopestr, "value");
		if ( level.inttime > _nextRegenTime && value > 0 )
		{
			_nextRegenTime = level.inttime + ((6-value) * 1000);
			AddHealth(1.0f);
		}
	}
	
	if ( _useEntityStartTimer != 0.0f )
	{
		if ( level.time > _useEntityStartTimer )
		{
			_usingEntity = false;
			_useEntityStartTimer = 0.0f;
		}
	}
		
	if ( current_ucmd->thirdperson )
		_isThirdPerson = true;
	else
		_isThirdPerson = false;
	
	// Set cvar values
	if ( world->getPhysicsVar( WORLD_PHYSICS_AIRACCELERATE ) != -1.0f )
		client->ps.pm_airaccelerate = (int)  world->getPhysicsVar( WORLD_PHYSICS_AIRACCELERATE );
	else
		client->ps.pm_airaccelerate = (int) sv_airaccelerate->value;
	
	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.applyAirAccelerationModifiers( this, &client->ps.pm_airaccelerate );
	
	client->ps.pm_wateraccelerate = (int) sv_wateraccelerate->value;
	client->ps.pm_stopspeed = (int) sv_stopspeed->value;
	client->ps.pm_friction = (int) sv_friction->value;
	client->ps.pm_waterfriction = (int) sv_waterfriction->value;
	client->ps.jumpvelocity = (int) sv_jumpvelocity->value;
	
	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.applyJumpModifiers( this, &client->ps.jumpvelocity );
	
	client->ps.crouchjumpvelocity = (int) sv_crouchjumpvelocity->value;
	
	client->ps.pm_accelerate = (int) sv_accelerate->value;
	client->ps.pm_defaultviewheight = (int) sv_defaultviewheight->value;
	
	viewheight = client->ps.pm_defaultviewheight;
	
	
	
	if ( level.intermissiontime )
	{
		client->ps.pm_flags |= PMF_FROZEN;
		
		if (g_endintermission->integer > 0 )
		{
			g_endintermission->integer = 0;
			level.exitintermission = true;
		}
		// can exit intermission after 10 seconds (default)
		if ( (( level.time - level.intermissiontime ) > level.intermission_advancetime)
			&& (level.intermission_advancetime != 0))
		{
			if ( multiplayerManager.inMultiplayer() )
			{
				//if ( new_buttons & BUTTON_ANY )
				if ( ( new_buttons & BUTTON_ATTACKRIGHT ) || ( new_buttons & BUTTON_ATTACKLEFT ) )
				{
					level.exitintermission = true;
				}
			}
			else
			{
				level.exitintermission = true;
				
			}
		}
		
		// Save cmd angles so that we can get delta angle movements next frame
		client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
		client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
		client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );
		
		return;
	}
	
	moveresult = MOVERESULT_NONE;
	
	if ( !vehicle || !vehicle->Drive( current_ucmd ) )
	{
		ClientMove( current_ucmd );
	}
	
	if ( vehicle )
	{
		pmove_t pm;
		
		SetMoveInfo( &pm, current_ucmd );
		Pmove( &pm );
	}
	

	if(current_ucmd)
	{
		_crossHairXOffset		= current_ucmd->choffset[0];
		_crossHairYOffset		= current_ucmd->choffset[1];
	}
	

	client->ps.pm_flags &= ~(PMF_RADAR_MODE | PMF_SCANNER );
	
	CheckForTargetedEntity();
	ProcessTargetedEntity();
	
	Weapon *weap;
	weap = GetActiveWeapon( WEAPON_DUAL );
	if ( weap )
	{
		if(weap->GetPutaway())
		{
			//			weap->SetTargetedEntity(0);
		}
		else
		{
			//			weap->SetRealViewOrigin();
			//			weap->SetThirdPerson();
			//			weap->SetCHOffset( current_ucmd->choffset[0],  current_ucmd->choffset[1]);
	
			weap->ProcessTargetedEntity(GetTargetedEntity());
		}

		if ( ( ( weap->GetFireType( FIRE_MODE1 ) == FT_CONTROL_PROJECTILE ) && ( new_buttons & BUTTON_ATTACKLEFT ) ) ||
			 ( ( weap->GetFireType( FIRE_MODE2 ) == FT_CONTROL_PROJECTILE ) && ( new_buttons & BUTTON_ATTACKRIGHT ) ) )
		{
			weap->toggleProjectileControl();
		}

		if ( ( ( weap->GetFireType( FIRE_MODE1 ) == FT_CONTROL_ZOOM ) && ( new_buttons & BUTTON_ATTACKLEFT ) ) ||
			 ( ( weap->GetFireType( FIRE_MODE2 ) == FT_CONTROL_ZOOM ) && ( new_buttons & BUTTON_ATTACKRIGHT ) ) )
		{
			weap->changeZoomStage( 40.0f, 10.0f );
		}
	}
	
	// If we're charging up for a special move, set the current time
	if ( specialMoveCharge > 0.0f )
	{
		specialMoveCharge = level.time;
		//gi.Printf("Charging Up... Time: %.2f\n",specialMoveEndTime - level.time);
	}
	
	
	// only evaluate the state when not noclipping
	if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		// force the stand animation if were in noclip
		SetAnim( "idle", all );
	}
	else
	{
		// set flags for state machine
		CheckMoveFlags();
		EvaluateState();
		
		if ( groundentity && groundentity->entity && groundentity->entity->isSubclassOf( Actor ) )
		{
			Event *event = new Event( EV_Actor_Push );
			event->AddVector( Vector( 0.0f, 0.0f, -10.0f ) );
			groundentity->entity->PostEvent( event, 0.0f );
		}
	}
	
	oldvelocity = velocity;
	old_v_angle  = v_angle;
	
	// If we're dying, check for respawn
	if ( ( deadflag == DEAD_DEAD && ( level.time > respawn_time ) ) )
	{
		// wait for any button just going down
		//if ( new_buttons || ( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FORCE_RESPAWN ) ) )
		if ( ( ( new_buttons & BUTTON_ATTACKRIGHT ) || ( new_buttons & BUTTON_ATTACKLEFT ) ) || 
			   ( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FORCE_RESPAWN ) ) )
		{
			if ( multiplayerManager.inMultiplayer() )
			{
				//respawn_time = level.time ;
				multiplayerManager.respawnPlayer( this, false );
				//				ProcessEvent( EV_Player_Respawn );
			}
			
			else
			{
				G_RestartLevelWithDelay( 1.0f );
			}
		}
	}
	
	// Save cmd angles so that we can get delta angle movements next frame
	client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] );
	client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] );
	client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] );

	if ( client->ps.pm_flags & PMF_CAMERA_VIEW )
	{
		VectorCopy( current_ucmd->realvieworigin, client->ps.camera_origin );
		VectorCopy( current_ucmd->realviewangles, client->ps.camera_angles );
	}
	
	if ( g_logstats->integer )
	{
		if ( !logfile_started )
		{
			ProcessEvent( EV_Player_LogStats );
			logfile_started = true;
		}
	}
	
	if ( ( last_ucmd.buttons & BUTTON_USE ) != 0 )
		ProcessEvent( EV_Player_DoUse );
	
	if ( ( last_ucmd.buttons & BUTTON_DROP_RUNE ) != 0 )
		dropRune();
	
	if ( ( last_ucmd.buttons & BUTTON_TRANSFER_ENERGY ) != 0 )
		transferEnergy();

	if ( multiplayerManager.inMultiplayer() )
		multiplayerManager.playerInput( this, new_buttons );
	
	// Check for incoming melee attacks and set the incomingMeleeAttack flag
	incomingMeleeAttack = false;
	if ( meleeAttackerList.NumObjects() )
	{
		Entity *attacker;
		int i;
		for( i = meleeAttackerList.NumObjects() ; i >= 1 ; i-- )
		{
			attacker = (Entity*)meleeAttackerList.ObjectAt(i);
			if ( !attacker )
				continue;
			
			if ( attacker->isSubclassOf(Actor) )
			{
				Actor *act = (Actor *)attacker;
				if ( act->in_melee_attack )
					incomingMeleeAttack = true;
				else
					meleeAttackerList.RemoveObjectAt( i );
			}
		}
		
		// No one is attacking us, make sure the list is clear
		if ( !incomingMeleeAttack )
			meleeAttackerList.ClearObjectList();
	}
}

// This function returns the endpoint of where the crosshair is located on the
// screen.  Regardless of whether we're in camera, first or 3rd person view.
void Player::GetViewTrace( trace_t& trace,  int contents, float maxDistance )
{
//	trace_t trace;
	Vector f,r,u,p,s;
	Vector pos, forward, endpoint, vorg, dir;
    vec3_t viewAngles;
	

	if (client->ps.pm_flags & PMF_CAMERA_VIEW ) // 3rd person automatic camera
	{
		vorg = client->ps.camera_origin;
		VectorCopy(client->ps.camera_angles, viewAngles);
	}
	else if ( !_isThirdPerson ) // First person
	{
		vorg = origin;
		vorg.z += client->ps.viewheight;
		VectorCopy(GetVAngles(), viewAngles);
	}
	else // Third person
	{
		//vorg = current_ucmd->realviewangles;
		VectorCopy(GetVAngles(), viewAngles);
		
	}
	
	vec3_t left;
	//Adjust the view end point if we are leaning.
	if( client->ps.leanDelta != 0)
	{
		viewAngles[2] -= client->ps.leanDelta / 2.0f;

		AngleVectors( viewAngles, NULL, left, NULL );
		VectorMA( vorg, client->ps.leanDelta, left, vorg );
	}

	// Add the damage angles
	VectorSubtract( viewAngles, client->ps.damage_angles, viewAngles );
	
	AngleVectors(viewAngles, f,r,u);
	
	float xmax,ymax, fov_x, fov_y, x;
	
    fov_x = client->ps.fov;
	x = 640.0f / (float)tan( fov_x / 360.0 * M_PI );
	fov_y = (float)atan2( 480.0, x );
	fov_y *= 360.0f / M_PI;
	
	ymax = 4.0f * (float)tan( fov_y * M_PI / 360.0 );
	xmax = 4.0f * (float)tan( fov_x * M_PI / 360.0 );
	
	p.x = (float) _crossHairXOffset * (-xmax / 320.0f);
	p.y = (float) _crossHairYOffset * (-ymax / 240.0f);
	s = ( 4.0f * f ) + ( p.x * r ) + ( p.y * u );
	s.normalize();
	endpoint = vorg + (s * maxDistance );
	
	if ( !multiplayerManager.inMultiplayer() || multiplayerManager.fullCollision() )
		trace = G_FullTrace( vorg, vec_zero, vec_zero, endpoint, this, contents, true, "Player::GetViewEndPoint" );
	else
		trace = G_Trace( vorg, vec_zero, vec_zero, endpoint, this, contents, true, "Player::GetViewEndPoint" );
	
	//endpoint = trace.endpos;
	
	//G_DebugLine( vorg, endpoint, 1,0,1,1 );
	
	//return endpoint;
}
//-----------------------------------------------------
//
// Name:		CheckForTargetedEntity
// Class:		Player
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::CheckForTargetedEntity( void )
{
	trace_t viewTrace;
		
	memset(&viewTrace,0,sizeof(trace_t));
	GetViewTrace(viewTrace, MASK_SHOT | CONTENTS_TARGETABLE);
	
	if ( viewTrace.ent && ( viewTrace.entityNum != ENTITYNUM_WORLD ))
	{
		if(viewTrace.ent->entity->isSubclassOf(Actor) && viewTrace.ent->entity->getHealth() <= 0)
		{
			SetTargetedEntity(0);
		}
		else
		{
			SetTargetedEntity(viewTrace.ent->entity);
		}
		
		return;
	}
	
	SetTargetedEntity(0);
}


//-----------------------------------------------------
//
// Name:		SetTargetedEntity
// Class:		Player
//
// Description:	Sets the targeted entity.
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::SetTargetedEntity(EntityPtr entity)
{
	//remove the EF_DISPLAY_INFO from the previous entity.
	if(_targetedEntity != 0)
		_targetedEntity ->edict->s.eFlags &= ~(EF_DISPLAY_INFO|EF_DISPLAY_DESC1 | EF_DISPLAY_DESC2 | EF_DISPLAY_DESC3);
	

	_targetedEntity  = entity;
	if(_targetedEntity  != 0)
		_targetedEntity->edict->s.eFlags |= EF_DISPLAY_INFO;
}



//-----------------------------------------------------
//
// Name:		ProcessTargetedEntity
// Class:		Player
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::ProcessTargetedEntity( void )
{
	if(_targetedEntity == 0)
		return;	
	
	_targetedEntity->edict->s.eFlags |= EF_DISPLAY_DESC1;
}


//--------------------------------------------------------------
//
// Name:			SetState
// Class:			Player
//
// Description:		Sets the state machine to the specific legs and torso state specified
//
// Parameters:		const str& legsstate -- Legs state name
//					const str& torsostate -- Torso state name
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::SetState(const str& legsstate, const str& torsostate)
{
	animdone_Legs = false;
	animdone_Torso = false;
	
	movecontrol = MOVECONTROL_USER;
	
	currentState_Legs = statemap_Legs->FindState( legsstate.c_str() );
	currentState_Torso = statemap_Torso->FindState( torsostate.c_str() );
	
	str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) );
	if ( !animate->HasAnim(legsAnim) )
		legsAnim = getGameplayAnim(legsAnim);
	if ( legsAnim == "" )
	{
		partAnim[ legs ] = "";
		animate->ClearLegsAnim();
	}
	else if ( legsAnim != "none" )
	{
		SetAnim( legsAnim, legs );
	}
	
	str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
	if ( !animate->HasAnim(torsoAnim) )
		torsoAnim = getGameplayAnim(torsoAnim);
	if ( torsoAnim == "" )
	{
		partAnim[ torso ] = "";
		animate->ClearTorsoAnim();
	}
	else if ( torsoAnim != "none" )
	{
		SetAnim( torsoAnim.c_str(), torso );
	}
	
	movecontrol = currentState_Legs->getMoveType();
	if ( ( movecontrol < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ movecontrol ] ) )
	{
		( this->*MoveStartFuncs[ movecontrol ] )();
	}
	
	// This seems breaks the secret move mode because it's called at a bad time and causes the client/server angles
	// to get out of sync because delta_angles is not updated correctly.
	// I don't think it's necessary to call it anyway, so I'm removing it.
	//SetViewAngles( v_angle );
}


//--------------------------------------------------------------
//
// Name:			LoadStateTable
// Class:			Player
//
// Description:		Loads the state table for the player.
//
// Parameters:		None
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::LoadStateTable()
{
	statemap_Legs = NULL;
	statemap_Torso = NULL;

	freeConditionals( legs_conditionals );
	freeConditionals( torso_conditionals );

	statemap_Legs = GetStatemap( str( g_statefile->string ) + "_legs.st", ( Condition<Class> * )Conditions, &legs_conditionals, false );
	statemap_Torso = GetStatemap( str( g_statefile->string ) + "_torso.st", ( Condition<Class> * )Conditions, &torso_conditionals, false );

	SetState("STAND", "START");
}

void Player::ResetState( Event *ev )
{
	movecontrol = MOVECONTROL_USER;
	LoadStateTable();
}

void Player::StartPush( void )
{
	trace_t trace;
	Vector  end( origin + ( yaw_forward * 64.0f ) );
	
	trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "StartPush" );
	if ( trace.fraction == 1.0f )
	{
		return;
	}
	v_angle.y = vectoyaw( trace.plane.normal ) - 180.0f;
	SetViewAngles( v_angle );
	
	setOrigin( trace.endpos - ( yaw_forward * 0.4f ) );
}

void Player::StartUseAnim( void )
{
	UseAnim  *ua;
	Vector   neworg;
	Vector   newangles;
	str      newanim;
	str      state;
	str      camera;
	trace_t  trace;
	
	if ( toucheduseanim )
	{
		ua = ( UseAnim * )( Entity * )toucheduseanim;
	}
	else if ( atobject )
	{
		ua = ( UseAnim * )( Entity * )atobject;
	}
	else
	{
		return;
	}
	
	useitem_in_use = ua;
	toucheduseanim = NULL;
	atobject = NULL;
	
	if ( ua->GetInformation( this, &neworg, &newangles, &newanim, &useanim_numloops, &state, &camera ) )
	{
		trace = G_Trace( origin, mins, maxs, neworg, this, edict->clipmask, true, "StartUseAnim" );
		if ( trace.startsolid || ( trace.fraction < 1.0f ) )
		{
			gi.WDPrintf( "Move to UseAnim was blocked.\n" );
		}
		
		if ( !trace.startsolid )
		{
			setOrigin( trace.endpos );
		}
		
		setAngles( newangles );
		v_angle.y = newangles.y;
		SetViewAngles( v_angle );
		
		movecontrol = MOVECONTROL_ABSOLUTE;
		
		if ( state.length() )
		{
			State * newState;
			
			newState = statemap_Torso->FindState( state );
			if ( newState )
            {
				EvaluateState( newState );
            }
			else
            {
				gi.WDPrintf( "Could not find state %s on UseAnim\n", state.c_str() );
            }
		}
		else
		{
			if ( currentState_Torso )
            {
				if ( camera.length() )
				{
					currentState_Torso->setCameraType( camera );
				}
				else
				{
					currentState_Torso->setCameraType( "behind" );
				}
            }
			SetAnim( newanim, legs );
		}
	}
}

void Player::StartLoopUseAnim( void )
{
	useanim_numloops--;
}

void Player::FinishUseAnim( Event *ev )
{
	UseAnim  *ua;
	
	if ( !useitem_in_use )
		return;
	
	ua = ( UseAnim * )( Entity * )useitem_in_use;
	ua->TriggerTargets( this );
	useitem_in_use = NULL;
}

void Player::SetupUseObject()
{
	UseObject  *uo;
	Vector   neworg;
	Vector   newangles;
	str      state;
	trace_t  trace;
	
	if ( atobject )
		uo = ( UseObject * )( Entity * )atobject;
	else
		return;
	
	useitem_in_use = uo;
	
	uo->Setup( this, &neworg, &newangles, &state );
	if ( uo->movetheplayer )
	{
		trace = G_Trace( neworg, mins, maxs, neworg, this, edict->clipmask, true, "SetupUseObject - 1" );
		if ( trace.startsolid || trace.allsolid )
		{
			trace = G_Trace( origin, mins, maxs, neworg, this, edict->clipmask, true, "SetupUseObject - 2" );
			if ( trace.startsolid || ( trace.fraction < 1.0f ) )
			{
				gi.WDPrintf( "Move to UseObject was blocked.\n" );
			}
		}
		
		if ( !trace.startsolid )
		{
			setOrigin( trace.endpos );
		}
		
		setAngles( newangles );
		v_angle.y = newangles.y;
		SetViewAngles( v_angle );
	}
	
	movecontrol = MOVECONTROL_ABSOLUTE;
	if ( state.length() )
	{
		State * newState;
		
		newState = statemap_Torso->FindState( state );
		if ( newState )
			EvaluateState( newState );
		else
			gi.WDPrintf( "Could not find state %s on UseObject\n", state.c_str() );
	}
	else
	{
		uo->Start();
	}
}

void Player::StartUseObject( Event *ev )
{
	UseObject  *uo;
	
	if ( !useitem_in_use )
		return;
	
	uo = ( UseObject * )( Entity * )useitem_in_use;
	uo->Start();
}

void Player::FinishUseObject( Event *ev )
{
	UseObject  *uo;
	
	if ( !useitem_in_use )
		return;
	
	uo = ( UseObject * )( Entity * )useitem_in_use;
	uo->Stop( this );
	useitem_in_use = NULL;
}

void Player::turnTowardsEntity( Event *ev )
{
	Entity *entity;
	Vector dir;
	Vector angles;
	Event *turnEvent;
	float currentYaw;
	float yawDiff;

	entity = ev->GetEntity( 1 );

	if ( !entity )
		return;

	// Get the angles to the entity

	dir = entity->origin - origin;
	dir.normalize();

	angles = dir.toAngles();

	// Get the yaw difference

	currentYaw = anglemod( v_angle[ YAW ] );

	yawDiff = angles[ YAW ] - currentYaw;

	yawDiff = AngleNormalize180( yawDiff );

	// Actually turn the appropriate amount
	
	turnEvent = new Event( EV_Player_Turn );
	turnEvent->AddFloat( yawDiff );
	ProcessEvent( turnEvent );
}

void Player::Turn( Event *ev )
{
	float yaw;
	float time;
	int numFrames;
	
	yaw = ev->GetFloat( 1 );

	if ( ev->NumArgs() > 1 )
		time = ev->GetFloat( 2 );
	else
		time = 0.5;

	numFrames = (int)(time * ( 1 / level.frametime ));
	time = numFrames * level.frametime;
	
	CancelEventsOfType( EV_Player_TurnUpdate );
	
	if ( time > 0 )
	{
		ev = new Event( EV_Player_TurnUpdate );
		ev->AddFloat( yaw / numFrames );
		ev->AddFloat( time );
		ProcessEvent( ev );
	}
	else
	{
		v_angle[ YAW ] += yaw;
		SetViewAngles( v_angle );
	}
}

void Player::TurnUpdate( Event *ev )
{
	float yaw;
	float timeleft;
	
	yaw = ev->GetFloat( 1 );
	timeleft = ev->GetFloat( 2 );

	// Remove some time

	timeleft -= 0.05f;

	// Turn the specified amount

	v_angle[ YAW ] += yaw;
	SetViewAngles( v_angle );

	// Repost the turn event if we have time remaining

	if ( timeleft > 0.0f )
	{
		ev = new Event( EV_Player_TurnUpdate );
		ev->AddFloat( yaw );
		ev->AddFloat( timeleft );
		PostEvent( ev, 0.05f );
	}
}

void Player::TurnLegs( Event *ev )
{
	float yaw;
	
	yaw = ev->GetFloat( 1 );
	
	angles[ YAW ] += yaw;
	setAngles( angles );
}

void Player::DontTurnLegs( Event *ev )
{
	dont_turn_legs = ev->GetBoolean( 1 );
}

void Player::EvaluateState( State *forceTorso, State *forceLegs )
{
	int count;
	State *laststate_Legs;
	State *laststate_Torso;
	State *startstate_Legs;
	State *startstate_Torso;
	movecontrol_t move;
	
	if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		return;
	}
	
	// Evaluate the current state.
	// When the state changes, we reevaluate the state so that if the
	// conditions aren't met in the new state, we don't play one frame of
	// the animation for that state before going to the next state.
	startstate_Torso = laststate_Torso = currentState_Torso;
	count = 0;
	do
	{
		// since we could get into an infinite loop here, do a check
		// to make sure we don't.
		count++;
		if ( count > 10 )
		{
			gi.WDPrintf( "Possible infinite loop in state '%s'\n", currentState_Torso->getName() );
			assert( 0 );
			if ( count > 20 )
            {
				gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" );
				break;
            }
		}
		
		laststate_Torso = currentState_Torso;
		
		if ( forceTorso )
			currentState_Torso = forceTorso;
		else
			currentState_Torso = currentState_Torso->Evaluate( *this, &torso_conditionals );
		
		animdone_Torso = false;
		if ( movecontrol != MOVECONTROL_LEGS )
		{
			animdone_Legs = false;
		}
		if ( laststate_Torso != currentState_Torso )
		{
			// Process exit commands of the last state
			laststate_Torso->ProcessExitCommands( this );
			
			// Process entry commands of the new state
			currentState_Torso->ProcessEntryCommands( this );
			
			if ( waitForState.length() && ( !waitForState.icmpn( currentState_Torso->getName(), waitForState.length() ) ) )
            {
				waitForState = "";
				PlayerDone( NULL );
            }
			
			move = currentState_Torso->getMoveType();
			
			str legsAnim( currentState_Torso->getLegAnim( *this, &torso_conditionals ) );
			if ( !animate->HasAnim(legsAnim) )
				legsAnim = getGameplayAnim(legsAnim);
			str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
			if ( !animate->HasAnim(torsoAnim) )
				torsoAnim = getGameplayAnim(torsoAnim);
			
			if ( legsAnim != "" )
			{
				animdone_Legs = false;
				if ( !vehicle )
					SetAnim( legsAnim, legs );
			}
			else if ( move == MOVECONTROL_LEGS )
			{
				if ( !currentState_Legs )
				{
					animdone_Legs = false;
					currentState_Legs = statemap_Legs->FindState( "STAND" );
					legsAnim = currentState_Legs->getLegAnim( *this, &legs_conditionals );
					if ( !animate->HasAnim(legsAnim) )
						legsAnim = getGameplayAnim(legsAnim);
					if ( legsAnim == "" )
					{
						partAnim[ legs ] = "";
						animate->ClearLegsAnim();
					}
					else if ( legsAnim != "none" )
					{
						if ( !vehicle )
							SetAnim( legsAnim, legs );
					}
				}
			}
			else
			{
				partAnim[ legs ] = "";
				animate->ClearLegsAnim();
			}
			
			if ( torsoAnim == "" )
            {
				partAnim[ torso ] = "";
				animate->ClearTorsoAnim();
            }
			else if ( torsoAnim != "none" )
            {
				SetAnim( torsoAnim.c_str(), torso );
            }
			
			if ( movecontrol != move )
            {
				movecontrol = move;
				if ( ( move < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ move ] ) )
				{
					( this->*MoveStartFuncs[ move ] )();
				}
            }
			
			// This seems breaks the secret move mode because it's called at a bad time and causes the client/server angles
			// to get out of sync because delta_angles is not updated correctly.
			// I don't think it's necessary to call it anyway, so I'm removing it.
			//SetViewAngles( v_angle );
		}
	}
	while( laststate_Torso != currentState_Torso );
	  
	// Evaluate the current state.
	// When the state changes, we reevaluate the state so that if the
	// conditions aren't met in the new state, we don't play one frame of
	// the animation for that state before going to the next state.
	startstate_Legs = laststate_Legs = currentState_Legs;
	if ( movecontrol == MOVECONTROL_LEGS )
	{
		count = 0;
		do
		{
			// since we could get into an infinite loop here, do a check
			// to make sure we don't.
			count++;
			if ( count > 10 )
			{
				gi.WDPrintf( "Possible infinite loop in state '%s'\n", currentState_Legs->getName() );
				assert( 0 );
				if ( count > 20 )
				{
					gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" );
					break;
				}
			}
			
			if ( !currentState_Legs )
			{
				currentState_Legs = statemap_Legs->FindState( "STAND" );
			}
			
			laststate_Legs = currentState_Legs;
			
			if ( forceLegs )
				currentState_Legs = forceLegs;
			else
				currentState_Legs = currentState_Legs->Evaluate( *this, &legs_conditionals );
			
			animdone_Legs = false;
			if ( laststate_Legs != currentState_Legs )
			{
				// Process exit commands of the last state
				laststate_Legs->ProcessExitCommands( this );
				
				// Process entry commands of the new state
				currentState_Legs->ProcessEntryCommands( this );
				
				if ( waitForState.length() && ( !waitForState.icmpn( currentState_Legs->getName(), waitForState.length() ) ) )
				{
					waitForState = "";
					PlayerDone( NULL );
				}
				
				str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) );
				if ( !animate->HasAnim(legsAnim) )
					legsAnim = getGameplayAnim(legsAnim);
				if ( legsAnim == "" )
				{
					partAnim[ legs ] = "";
					animate->ClearLegsAnim();
				}
				else if ( legsAnim != "none" )
				{
					if ( !vehicle )
						SetAnim( legsAnim, legs );
				}
			}
		}
		while( laststate_Legs != currentState_Legs );
	}
	else
	{
		currentState_Legs = NULL;
	}
	
	if ( g_showplayeranim->integer )
	{
		if ( last_leg_anim_name != animate->AnimName( legs ) )
		{
			gi.DPrintf( "Legs change from %s to %s\n", last_leg_anim_name.c_str(), animate->AnimName( legs ) );
			last_leg_anim_name = animate->AnimName( legs );
		}
		
		if ( last_torso_anim_name != animate->AnimName( torso ) )
		{
			gi.DPrintf( "Torso change from %s to %s\n", last_torso_anim_name.c_str(), animate->AnimName( torso ) );
			last_torso_anim_name = animate->AnimName( torso );
		}
	}
	
	if ( g_showplayerstate->integer )
	{
		if ( startstate_Legs != currentState_Legs )
		{
			gi.DPrintf( "Legs change from %s to %s\n",
				startstate_Legs ? startstate_Legs->getName() : "NULL",
				currentState_Legs ? currentState_Legs->getName() : "NULL" );
		}
		
		if ( startstate_Torso != currentState_Torso )
		{
			gi.DPrintf( "Torso change from %s to %s\n",
				startstate_Torso ? startstate_Torso->getName() : "NULL",
				currentState_Torso ? currentState_Torso->getName() : "NULL" );
		}
	}
	
	if ( g_showplayerweapon->integer )
	{
		Weapon *weapon;
		
		weapon = GetActiveWeapon( WEAPON_DUAL );
		
		if ( !weapon )
			weapon = GetActiveWeapon( WEAPON_RIGHT );
		
		if ( !weapon )
			weapon = GetActiveWeapon( WEAPON_LEFT );
		
		if ( weapon )
		{
			gi.DPrintf( "Weapon - anim %s, frame %d\n", weapon->animate->GetName().c_str(), weapon->animate->CurrentFrame() );
		}
	}
	
	// This is so we don't remember pain when we change to a state that has a PAIN condition
	pain = 0;
	// Every second drop accumulated pain by 1
	if ( ( float )( int )( level.time ) == level.time )
	{
		accumulated_pain -= 1.0f;
		if ( accumulated_pain < 0.0f )
			accumulated_pain = 0.0f;
	}
}

void Player::EventUseItem( Event *ev )
{
	const char  *name;
	weaponhand_t hand = WEAPON_DUAL;
	
	if ( deadflag || _disableUseWeapon )
	{
		return;
	}

	if ( multiplayerManager.inMultiplayer() && ( !multiplayerManager.isFightingAllowed() || multiplayerManager.isPlayerSpectator( this ) ) )
	{
		return;
	}
	
	name = ev->GetString( 1 );
	
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	
	str objectName("CurrentPlayer.");
	objectName += name ;
	if ( gpm->hasProperty( objectName, "name" ) )
		name = gpm->getStringValue( objectName, "name" );
	else if ( gpm->hasProperty(name, "consumable" ) )
	{
		str slotname = gpm->getStringValue(name, "invslot");
		if ( !gpm->hasProperty(slotname, "quantity") )
			return;
		
		float quantity = gpm->getFloatValue(slotname, "quantity");
		if ( quantity < 1.0f )
			return;
		
		// Give the model, decrement the quantity
		str model = gpm->getStringValue(name, "model");
		giveItem(model);
		gpm->setFloatValue(slotname, "quantity", quantity-1.0f);
	}
	
	Item *item = ( Item * )FindItem( name );
	
	if ( item && item->isSubclassOf( InventoryItem ) )
	{
		InventoryItem *ii = ( InventoryItem * )item;
		Event *ev1;
		
		ev1 = new Event( EV_InventoryItem_Use );
		ev1->AddEntity( this );
		ii->ProcessEvent( ev1 );
		return;
	}
	else if ( ev->NumArgs() > 1 )
	{
		hand = WeaponHandNameToNum( ev->GetString( 2 ) );
	}
	
	useWeapon( name, hand );	
}

void Player::GiveWeaponCheat( Event *ev )
{
	giveItem( ev->GetString( 1 ) );
}

void Player::GiveCheat( Event *ev )
{
	str name;
	
	if ( deadflag )
	{
		return;
	}
	
	name = ev->GetString( 1 );
	
	if ( !name.icmp( "all" ) )
	{
		GiveAllCheat( ev );
		return;
	}
	EventGiveItem( ev );
}

void Player::GiveAllCheat( Event *ev )
{
	char  *buffer;
	char  *buf;
	char	com_token[MAX_STRING_CHARS];
	int numEvents;
	float postTime;


	if ( deadflag )
	{
		return;
	}

	if ( !gi.isClientActive( this->edict ) )
	{
		PostEvent( *ev, FRAMETIME );
		return;
	}

	numEvents = 0;
	postTime = 0.0f;

	if ( gi.FS_ReadFile( "global/giveall.scr", ( void ** )&buf, true ) != -1 )
	{
		buffer = buf;

		while ( 1 )
		{
			strcpy( com_token, COM_ParseExt( &buffer, true ) );

			if (!com_token[0])
				break;

			// Create the event
			ev = new Event( com_token );

			// get the rest of the line
			while( 1 )
			{
				strcpy( com_token, COM_ParseExt( &buffer, false ) );
				if (!com_token[0])
					break;

				ev->AddToken( com_token );
			}

			if ( numEvents >= 5 )
			{
				numEvents = 0;
				//postTime += level.frametime * 4;
				postTime += 1.0f;
			}

			PostEvent( ev, postTime );

			numEvents++;
		}

		gi.FS_FreeFile( buf );
	}
}

void Player::GodCheat( Event *ev )
{
	const char *msg;
	
	if ( ev->NumArgs() > 0 )
	{
		if ( ev->GetInteger( 1 ) )
		{
			flags |= FL_GODMODE;
		}
		else
		{
			flags &= ~FL_GODMODE;
		}
	}
	else
	{
		flags ^= FL_GODMODE;
	}
	
	if ( ev->GetSource() == EV_FROM_CONSOLE )
	{
		if ( !( flags & FL_GODMODE ) )
		{
			msg = "godmode OFF\n";
		}
		else
		{
			msg = "godmode ON\n";
		}
		
		gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
	}
}

void Player::Kill( Event *ev )
{
	if ( ( level.time - respawn_time ) < 5.0f )
	{
		return;
	}
	
	flags &= ~FL_GODMODE;
	health = 1.0f;
	Damage( this, this, 10.0f, origin, vec_zero, vec_zero, 0, DAMAGE_NO_PROTECTION, MOD_SUICIDE );
}

void Player::NoTargetCheat( Event *ev )
{
	const char *msg;
	
	flags ^= FL_NOTARGET;
	if ( !( flags & FL_NOTARGET ) )
	{
		msg = "notarget OFF\n";
	}
	else
	{
		msg = "notarget ON\n";
	}
	
	gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
}

//--------------------------------------------------------------
//
// Name:			NoclipCheat
// Class:			Player
//
// Description:		This is the event that puts the player in noclip mode
//
// Parameters:		Event *ev - No params
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::NoclipCheat( Event *ev	)
{
	const char *msg;
	
	if ( vehicle )
		msg = "Must exit vehicle first\n";
	else if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		setMoveType( MOVETYPE_WALK );
		msg = "noclip OFF\n";
		
		// reset the state machine so that her animations are correct
		SetState("STAND", "STAND");
	}
	else
	{
		client->ps.feetfalling = false;
		movecontrol = MOVECONTROL_USER;
		
		setMoveType( MOVETYPE_NOCLIP );
		msg = "noclip ON\n";
	}
	
	gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg );
}

void Player::GameVersion( Event *ev )
{
	gi.SendServerCommand( edict-g_entities, "print \"%s : %s\n\"", GAME_NAME, __DATE__ );
}

void Player::SetFov( float newFov, bool forced )
{
	fov = newFov;
	
	if ( !forced && ( fov != sv_defaultFov->value ) && multiplayerManager.checkFlag( MP_FLAG_FIXED_FOV ) )
	{
		fov = sv_defaultFov->value;
		return;
	}

	//if ( !forced )
	//{
	//	_userFovChoice = newFov;
	//}
	
	if ( fov < 1.0f )
	{
		fov = sv_defaultFov->value;
	}
	else if ( fov > 160.0f )
	{
		fov = 160.0f;
	}

	str tempString( fov );
	gi.cvar_set( "r_fov", tempString.c_str() );
}

float Player::getDefaultFov( void )
{
	if ( multiplayerManager.inMultiplayer() && multiplayerManager.checkFlag( MP_FLAG_FIXED_FOV ) )
		return sv_defaultFov->value;
	else
		//return _userFovChoice;
		return userFov;
}

void Player::Fov( Event *ev )
{
	CancelEventsOfType(EV_Player_Fov);
	if ( ev->NumArgs() > 1 )
	{
		Event *event = new Event( EV_Player_Fov );
		event->AddFloat( ev->GetFloat( 1 ) );
		PostEvent ( event, ev->GetFloat( 2 ) );
		return;
	}
	
	if ( ev->NumArgs() < 1 )
	{
		gi.SendServerCommand( edict-g_entities, "print \"Fov = %d\n\"", fov );
		return;
	}
	
	SetFov( ev->GetFloat( 1 ) );
}

/*
===============
CalcRoll

===============
*/
float Player::CalcRoll( void )
{
	float	sign;
	float	side;
	float	value;
	Vector l;
	
	angles.AngleVectors( NULL, &l, NULL );
	side = velocity * l;
	sign = side < 0.0f ? 4.0f : -4.0f;
	side = fabs( side );
	
	value = sv_rollangle->value;
	
	if ( side < sv_rollspeed->value )
	{
		side = side * value / sv_rollspeed->value;
	}
	else
	{
		side = value;
	}
	
	return side * sign;
}

void Player::GravityNodes( void )
{
	Vector grav;
	Vector gravnorm;
	Vector velnorm;
	float  dot;
	qboolean force;
	float max_speed;
	Vector new_velocity;
	
	//
	// Check for gravity pulling points
	//
	
	// no pull during waterjumps
	if ( client->ps.pm_flags & PMF_TIME_WATERJUMP )
	{
		return;
	}
	
	grav = gravPathManager.CalculateGravityPull( *this, origin, &force, &max_speed );
	
	// Check for unfightable gravity.
	if ( force && ( grav != vec_zero ) )
	{
		velnorm = velocity;
		velnorm.normalize();
		
		gravnorm = grav;
		gravnorm.normalize();
		
		dot = ( gravnorm.x * velnorm.x ) + ( gravnorm.y * velnorm.y ) + ( gravnorm.z * velnorm.z );
		
		// This prevents the player from trying to swim upstream
		if ( dot < 0.0f )
		{
			float tempdot;
			Vector tempvec;
			
			tempdot = 0.2f - dot;
			tempvec = velocity * tempdot;
			velocity = velocity - tempvec;
		}
	}
	
	if ( grav != vec_zero )
	{
		new_velocity = velocity + grav;
		
		if ( new_velocity.length() < velocity.length() )
		{
			// Is slowing down, defintely need to apply grav
			velocity = new_velocity;
		}
		else if ( velocity.length() < max_speed )
		{
			// Applay grav
			
			velocity = new_velocity;
			
			// Make sure we aren't making the player go too fast
			
			if ( velocity.length() > max_speed )
			{
				velocity.normalize();
				velocity *= max_speed;
			}
		}
		else
		{
			// Going too fast but still want to pull the player up if any z velocity in grav
			
			grav.x = 0;
			grav.y = 0;
			
			velocity = velocity + grav;
		}
	}
}

//
// PMove Events
//
void Player::ProcessPmoveEvents( int event )
{
	float damage;
	
	switch( event )
	{
	case EV_NONE:
		break;
	case EV_FALL_VERY_SHORT:
	case EV_FALL_SHORT:
	case EV_FALL_MEDIUM:
	case EV_FALL_FAR:
	case EV_FALL_VERY_FAR:
	case EV_FALL_FATAL:
		damage = 0.0f;
		if ( event == EV_FALL_VERY_SHORT )
			damage = 5.0f;
		else if ( event == EV_FALL_SHORT )
			damage = 10.0f;
		else if ( event == EV_FALL_MEDIUM )
			damage = 25.0f;
		else if ( event == EV_FALL_FAR )
			damage = 50.0f;
		else if ( event == EV_FALL_VERY_FAR )
			damage = 100.0f;
		else if ( event == EV_FALL_FATAL )
			damage = 1000.0f;
		
		if ( !multiplayerManager.checkFlag( MP_FLAG_NO_FALLING ) )
		{
            Damage( world, world, damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING );
		}
		break;
	case EV_TERMINAL_VELOCITY:
		Sound( "snd_fall", CHAN_VOICE );
		break;
		
	case EV_WATER_TOUCH:   // foot touches
		if ( watertype & CONTENTS_LAVA )
		{
			Sound( "snd_burn", CHAN_LOCAL );
		}
		else
		{
			Entity *water;
			trace_t trace;
			Vector start;
			float scale;
			
			Sound( "impact_playersplash", CHAN_AUTO );
			
			// Find the correct place to put the splash
			
			start = origin + Vector( 0.0f, 0.0f, 90.0f );
			trace = G_Trace( start, vec_zero, vec_zero, origin, NULL, MASK_WATER, false, "ProcessPmoveEvents" );
			
			// Figure out a good scale for the splash
			
			scale = 1.0f + ( velocity[2] + 400.0f ) / -1500.0f;
			
			if ( scale < 1.0f )
				scale = 1.0f;
			else if ( scale > 1.5f )
				scale = 1.5f;
			
			// Spawn in a water splash
			
			water = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
			
			water->setOrigin( trace.endpos );
			water->setModel( "fx_splashsmall.tik" );
			water->setScale( scale );
			water->animate->RandomAnimate( "idle" );
			water->PostEvent( EV_Remove, 5.0f );
			
		}
		break;
	case EV_WATER_LEAVE:   // foot leaves
		Sound( "impact_playerleavewater", CHAN_AUTO );
		break;
	case EV_WATER_UNDER:   // head touches
		Sound( "impact_playersubmerge", CHAN_AUTO );
		break;
	case EV_WATER_CLEAR:   // head leaves
		Sound( "snd_gasp", CHAN_LOCAL );
		break;
	}
}

/*
=============
WorldEffects
=============
*/
void Player::WorldEffects( void )
{
	if ( deadflag == DEAD_DEAD )
	{
		// if we are dead, no world effects
		return;
	}
	
	if ( movetype == MOVETYPE_NOCLIP )
	{
		// don't need air
		air_finished = level.time + 20.0f;
		return;
	}
	
	//
	// check for on fire
	//
	if ( on_fire )
	{
		if ( next_painsound_time < level.time )
		{
			next_painsound_time = level.time + 4.0f;
			Sound( "snd_onfire", CHAN_LOCAL );
		}
	}
	
	//
	// check for lava
	//
	if ( watertype & CONTENTS_LAVA )
	{
		if ( next_drown_time < level.time )
		{
			next_drown_time = level.time + 0.2f;
			Damage( world, world, 10.0f * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_LAVA );
		}
		if ( next_painsound_time < level.time )
		{
			next_painsound_time = level.time + 3.0f;
			Sound( "snd_burned", CHAN_LOCAL );
		}
	}
	
	//
	// check for slime
	//
	if ( watertype & CONTENTS_SLIME )
	{
		if ( next_drown_time < level.time )
		{
			next_drown_time = level.time + 0.4f;
			Damage( world, world, 7.0f * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_SLIME );
		}
		if ( next_painsound_time < level.time )
		{
			next_painsound_time = level.time + 5.0f;
			Sound( "snd_burned", CHAN_LOCAL );
		}
	}
	
	//
	// check for drowning
	//
	if ( waterlevel == 3 )
	{
		// if out of air, start drowning
		if ( ( air_finished < level.time ) && !( flags & FL_GODMODE ) )
		{
			// drown!
			if ( ( next_drown_time < level.time ) && ( health > 0 ) )
			{
				next_drown_time = level.time + 1.0f;
				
				// take more damage the longer underwater
				drown_damage += 2.0f;
				if ( drown_damage  > 15.0f )
				{
					drown_damage = 15.0f;
				}
				
				// play a gurp sound instead of a normal pain sound
				if ( health <= drown_damage )
				{
					Sound( "snd_drown", CHAN_LOCAL );
					BroadcastSound();
				}
				else if ( rand() & 1 )
				{
					Sound( "snd_choke", CHAN_LOCAL );
					BroadcastSound();
				}
				else
				{
					Sound( "snd_choke", CHAN_LOCAL );
					BroadcastSound();
				}
				
				Damage( world, world, drown_damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_DROWN );
			}
		}
	}
	else
	{
		air_finished = level.time + 20.0f;
		drown_damage = 2.0f;
	}
	
	GravityNodes();
	
	old_waterlevel = waterlevel;
}

/*
=============
AddBlend
=============
*/
void Player::AddBlend( float r, float g, float b, float a )
{
	float	a2;
	float a3;
	
	if ( a <= 0.0f )
	{
		return;
	}
	
	// new total alpha
	a2 = blend[ 3 ] + ( 1.0f - blend[ 3 ] ) * a;
	
	// fraction of color from old
	a3 = blend[ 3 ] / a2;
	
	blend[ 0 ] = ( blend[ 0 ] * a3 ) + ( r * ( 1.0f - a3 ) );
	blend[ 1 ] = ( blend[ 1 ] * a3 ) + ( g * ( 1.0f - a3 ) );
	blend[ 2 ] = ( blend[ 2 ] * a3 ) + ( b * ( 1.0f - a3 ) );
	blend[ 3 ] = a2;
}

/*
=============
SetBlend
=============
*/
void Player::SetBlend( float r, float g, float b, float a, int additive )
{
	client->ps.blend[ 0 ] = r;
	client->ps.blend[ 1 ] = g;
	client->ps.blend[ 2 ] = b;
	client->ps.blend[ 3 ] = a;
	
	client->ps.stats[ STAT_ADDFADE ] = additive;
}

void Player::SetBlend( int additive )
{
	SetBlend( blend[ 0 ], blend[ 1 ], blend[ 2 ], blend[ 3], additive );
}

/*
=============
CalcBlend
=============
*/
void Player::CalcBlend( void )
{
	int		contents;
	Vector	vieworg;
	Vector	viewModeColor;
	float		viewModeAlpha;
	qboolean	viewModeAdditive;
	
	client->ps.stats[STAT_ADDFADE] = 0;
	blend[ 0 ] = blend[ 1 ] = blend[ 2 ] = blend[ 3 ] = 0;
	SetBlend( false );
	
	// Set to view mode blend if necessary
	
	if ( gi.GetViewModeScreenBlend( getViewMode(), viewModeColor, &viewModeAlpha, &viewModeAdditive ) )
	{
		AddBlend( viewModeColor[ 0 ], viewModeColor[ 1 ], viewModeColor[ 2 ], viewModeAlpha );
		SetBlend( viewModeAdditive );
		
		return;
	}
	
	// add for contents
	vieworg = origin;
	vieworg[ 2 ] += viewheight;	
	
	contents = gi.pointcontents( vieworg, 0 );
	
	if ( flags & FL_STUNNED )
	{
		AddBlend( 0.0f, 0.0f, 0.5f, 0.1f );
		SetBlend( true );
	}
	else if ( contents & CONTENTS_SOLID )
	{
		// Outside of world
		//AddBlend( 0.8, 0.5, 0.0, 0.2 );
	}
	else if ( contents & CONTENTS_LAVA )
	{
		AddBlend( level.lava_color[0], level.lava_color[1], level.lava_color[2], level.lava_alpha );
		SetBlend( true );
	}
	else if ( contents & CONTENTS_WATER )
	{
		AddBlend( level.water_color[0], level.water_color[1], level.water_color[2], level.water_alpha );
		SetBlend( true );
	}
	else if ( contents & CONTENTS_SLIME )
	{
		AddBlend( level.slime_color[0], level.slime_color[1], level.slime_color[2], level.slime_alpha );
		SetBlend( true );
	}
	
	// add for damage
	if ( _doDamageScreenFlash && ( damage_alpha > 0 ) )
	{
		AddBlend( damage_blend[ 0 ], damage_blend[ 1 ], damage_blend[ 2 ], damage_alpha );
		SetBlend( false );
		
		// drop the damage value
		/* damage_alpha -= 0.06;
		
		if ( damage_alpha < 0 )
		{
			damage_alpha = 0;
		} */
	}
	
	// Add screen flash
	
	if ( level.time < _flashMaxTime )
	{
		float currentFlashAlpha;
		
		currentFlashAlpha = _flashAlpha;
		
		if ( level.time > _flashMinTime )
		{
			currentFlashAlpha = _flashAlpha * ( _flashMaxTime - level.time ) / ( _flashMaxTime - _flashMinTime );
		}
		
		AddBlend( _flashBlend[ 0 ], _flashBlend[ 1 ], _flashBlend[ 2 ], currentFlashAlpha );
		SetBlend( false );
	}
	
	
	// Do the cinematic fading
	float alpha=1;
	
	level.m_fade_time -= level.frametime;
	
	// Return if we are completely faded in
	if ( ( level.m_fade_time <= 0.0f ) && ( level.m_fade_type == fadein ) )
	{
		//client->ps.blend[3] = 0 + damage_alpha;
		return;
	}
	
	// If we are faded out, and another fade out is coming in, then don't bother
	/* if ( ( level.m_fade_time_start > 0 ) && ( level.m_fade_type == fadeout ) )
	{
	if ( client->ps.blend[3] >= 1 )
	return;
} */
	
	if ( level.m_fade_time_start > 0.0f )
		alpha = level.m_fade_time / level.m_fade_time_start;
	
	if ( level.m_fade_type == fadeout )
		alpha = 1.0f - alpha;
	
	if ( alpha < 0.0f )
		alpha = 0.0f;
	
	if ( alpha > 1.0f )
		alpha = 1.0f;
	
	if ( level.m_fade_style == additive )
	{
		if ( client->ps.stats[STAT_ADDFADE] == 1 )
		{
			AddBlend( level.m_fade_color[0] * level.m_fade_alpha * alpha, level.m_fade_color[1] * level.m_fade_alpha * alpha, 
				level.m_fade_color[2] * level.m_fade_alpha * alpha, level.m_fade_alpha * alpha );
			SetBlend( true );
		}
		else
		{
			SetBlend( level.m_fade_color[0] * level.m_fade_alpha * alpha, level.m_fade_color[1] * level.m_fade_alpha * alpha, 
				level.m_fade_color[2] * level.m_fade_alpha * alpha, level.m_fade_alpha * alpha, true );
		}
	}
	else
	{
		SetBlend( level.m_fade_color[0], level.m_fade_color[1], level.m_fade_color[2], level.m_fade_alpha * alpha, false );
	}
}

void Player::setFlash( const Vector &color, float alpha, float minTime, float maxTime )
{
	_flashBlend = color;
	_flashAlpha = alpha;
	_flashMinTime = level.time + minTime;
	_flashMaxTime = level.time + maxTime;
}

/*
===============
P_DamageFeedback

Handles color blends and view kicks
===============
*/

#define DAMAGE_MAX_PITCH_SCALE 0.3f
#define DAMAGE_MAX_YAW_SCALE 0.3f

void Player::DamageFeedback( void )
{
	if ( _lastDamagedTimeFront + 0.25f >= level.time )
		client->ps.pm_flags |= PMF_DAMAGE_FRONT;
	else
		client->ps.pm_flags &= ~PMF_DAMAGE_FRONT;

	if ( _lastDamagedTimeBack + 0.25f >= level.time )
		client->ps.pm_flags |= PMF_DAMAGE_BACK;
	else
		client->ps.pm_flags &= ~PMF_DAMAGE_BACK;

	if ( _lastDamagedTimeLeft + 0.25f >= level.time )
		client->ps.pm_flags |= PMF_DAMAGE_LEFT;
	else
		client->ps.pm_flags &= ~PMF_DAMAGE_LEFT;

	if ( _lastDamagedTimeRight + 0.25f >= level.time )
		client->ps.pm_flags |= PMF_DAMAGE_RIGHT;
	else
		client->ps.pm_flags &= ~PMF_DAMAGE_RIGHT;

	// if we are dead, don't setup any feedback

	if ( health <= 0.0f )
	{
		damage_count = 0;
		damage_blood = 0;
		damage_alpha = 0;
		VectorClear( damage_angles );
		return;
	}
	
	if ( damage_blood > damage_count )
	{
		Vector delta;
		Vector damageDir;
		
		//damageDir = damage_from * -1.0f;
		damageDir = damage_from;

		delta = damageDir.toAngles();

		delta[ PITCH ] = AngleDelta( delta[ PITCH ], v_angle[ PITCH ] );
		delta[ YAW ]   = AngleDelta( delta[ YAW ], v_angle[ YAW ] );
		delta[ ROLL ]  = AngleDelta( delta[ ROLL ], v_angle[ ROLL ] );

		// Dim it down by a factor of a hundred so we can multiple it by our built up damage later

		delta *= 0.01f;
		
		damage_angles = delta;
	}
	
	if ( damage_count > 0 )
	{
		// decay damage_count over time

		if ( damage_count * 0.1f < 0.25f )
		{
			damage_count -= 0.25f;
		}
		else
		{
			damage_count *= 0.9f;
		}

		if ( damage_count < 0.1f )
		{
			damage_count = 0;
		}
	}

	damage_count += damage_blood;

	if ( damage_count <= 0.0f )
	{
		damage_alpha = 0.0f;
		return;
	}

	// the total alpha of the blend is always proportional to count
	
	damage_alpha = damage_count / 25.0f;

	// Make sure the alpha is within a reasonable range

	if ( damage_alpha < 0.1f )
	{
		damage_alpha = 0.1f;
	}
	else if ( damage_alpha > 0.6f )
	{
		damage_alpha = 0.6f;
	}

	//damage_blend = bcolor;
	
	// clear totals

	damage_blood = 0;
}

void Player::GetPlayerView( Vector *pos, Vector *angle )
{
	if ( pos )
	{
		*pos = origin;
		pos->z += viewheight;
	}
	
	if ( angle )
	{
		*angle = Vector( client->ps.viewangles );
	}
}

#define EARTHQUAKE_SCREENSHAKE_PITCH 2
#define EARTHQUAKE_SCREENSHAKE_YAW 2
#define EARTHQUAKE_SCREENSHAKE_ROLL 3

void Player::SetClientViewAngles( const Vector &position, const float cameraoffset, const Vector &ang, const Vector &vel, const float camerafov ) const
{
	if ( client->ps.useCameraFocalPoint )
	{
		client->ps.cameraFocalPoint[ 0 ] = position[ 0 ];
		client->ps.cameraFocalPoint[ 1 ] = position[ 1 ];
		client->ps.cameraFocalPoint[ 2 ] = position[ 2 ] + cameraoffset + 18.0f;
	}

	client->ps.origin[ 0 ] = position[ 0 ];
	client->ps.origin[ 1 ] = position[ 1 ];
	client->ps.origin[ 2 ] = position[ 2 ];
	
	client->ps.viewheight = (int) cameraoffset;

	client->ps.viewangles[ 0 ] = ang[ 0 ];
	client->ps.viewangles[ 1 ] = ang[ 1 ];
	client->ps.viewangles[ 2 ] = ang[ 2 ];
	
	client->ps.velocity[ 0 ] = vel[ 0 ];
	client->ps.velocity[ 1 ] = vel[ 1 ];
	client->ps.velocity[ 2 ] = vel[ 2 ];
	
	client->ps.fov = camerafov;
}

void Player::ShakeCamera( void )
{
	// Shake the player's view
	
	VectorClear( client->ps.damage_angles );

	// Don't shake camera if in cinematic and not allowed to

	if ( ( playerCameraMode == PLAYER_CAMERA_MODE_CINEMATIC ) && !world->canShakeCamera() )
		return;
	
	// Add earthquake shaking
	
	float earthquakeMagnitude = level.getEarthquakeMagnitudeAtPosition( origin );

	if ( earthquakeMagnitude > 0.0f )
	{
		client->ps.damage_angles[ PITCH ] += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_PITCH;
		client->ps.damage_angles[ YAW ]   += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_YAW;
		client->ps.damage_angles[ ROLL ]  += G_CRandom() * earthquakeMagnitude * EARTHQUAKE_SCREENSHAKE_ROLL;
	}

	// Don't do anything else to the camera if in a cinematic

	if ( playerCameraMode == PLAYER_CAMERA_MODE_CINEMATIC )
		return;

	VectorAdd( client->ps.damage_angles, getWeaponViewShake(), client->ps.damage_angles );
	
	// Add damage shaking
	
	if ( damage_count && sv_showdamageshake->integer )
	{
		if ( health <= 0.0f )
		{
			damage_angles = vec_zero;
		}
		else if ( multiplayerManager.inMultiplayer() )
		{
			damage_angles[ YAW ]   = G_CRandom( 0.05f );
			damage_angles[ PITCH ] = G_CRandom( 0.05f );
			damage_angles[ ROLL ]  = G_CRandom( 0.05f );
		}
		else
		{
			damage_angles[ YAW ]   = G_CRandom( 0.2f );
			damage_angles[ PITCH ] = G_CRandom( 0.2f );
			damage_angles[ ROLL ]  = G_CRandom( 0.2f );
		}

		client->ps.damage_angles[ YAW ]   += damage_angles[ YAW ]   * damage_count;
		client->ps.damage_angles[ PITCH ] += damage_angles[ PITCH ] * damage_count;
		client->ps.damage_angles[ ROLL ]  += damage_angles[ ROLL ]  * damage_count;
	}

	if ( client->pers.mp_lowBandwidth )
	{
		client->ps.damage_angles[ YAW ]   = 0.0f;
		client->ps.damage_angles[ PITCH ] = 0.0f;
		client->ps.damage_angles[ ROLL ]  = 0.0f;
	}
}


void Player::SetPlayerViewUsingNoClipController( void )
{
	client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
	
	// Force camera to behind in NOCLIP
	client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
}

void Player::SetPlayerViewUsingCinematicController( Camera *camera )
{
	client->ps.camera_angles[ 0 ] = camera->angles[ 0 ];
	client->ps.camera_angles[ 1 ] = camera->angles[ 1 ];
	client->ps.camera_angles[ 2 ] = camera->angles[ 2 ];
	
	client->ps.camera_origin[ 0 ] = camera->origin[ 0 ];
	client->ps.camera_origin[ 1 ] = camera->origin[ 1 ];
	client->ps.camera_origin[ 2 ] = camera->origin[ 2 ];
	client->ps.pm_flags |= PMF_CAMERA_VIEW;
	
	//
	// clear out the flags, but preserve the CF_CAMERA_CUT_BIT
	//
	client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;

	ShakeCamera();
}


void Player::SetPlayerViewUsingActorController( Camera *camera )
{
	if ( actor_camera )
	{
		// Find the focal point ( either the actor's watch offset or top of the bounding box)
		
		// Go a little above the view height
		
		actor_camera->origin = origin;
		actor_camera->origin[2] += client->ps.pm_defaultviewheight + 10.f;
		
		// Shift the camera back just a little
		
		Vector forward;
		Vector left;
		angles.AngleVectors( &forward, &left );
		actor_camera->origin -= forward * 15.0f;
		
		// Shift the camera a little to the left or right
		actor_camera->origin -= left * 15.0f;
		
		// Set the camera's position
		
		actor_camera->setOrigin( actor_camera->origin );
		
		// Set the camera's angles
		
		actor_camera->setAngles( angles );
		
		// Set this as our camera
		
		SetCamera( actor_camera, 0.5f );

	}
	else if ( ( level.automatic_cameras.NumObjects() > 0 ) && ( !camera || camera->IsAutomatic() ) )
	{
		// if we currently are not in a camera or the camera we are looking through is automatic, evaluate our camera choices
		AutomaticallySelectedNewCamera();
	}

	client->ps.camera_angles[ 0 ] = camera->angles[ 0 ];
	client->ps.camera_angles[ 1 ] = camera->angles[ 1 ];
	client->ps.camera_angles[ 2 ] = camera->angles[ 2 ];
	
	client->ps.camera_origin[ 0 ] = camera->origin[ 0 ];
	client->ps.camera_origin[ 1 ] = camera->origin[ 1 ];
	client->ps.camera_origin[ 2 ] = camera->origin[ 2 ];
	client->ps.pm_flags |= PMF_CAMERA_VIEW;
	
	//
	// clear out the flags, but preserve the CF_CAMERA_CUT_BIT
	//
	client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
}

void Player::SetPlayerViewUsingEntityWatchingController( void )
{

	SetPlayerViewNormal();

	// Find the focal point ( either the actor's watch offset or top of the bounding box)
	
	Vector focal_point;
	if ( entity_to_watch->watch_offset != vec_zero )
	{
		MatrixTransformVector( entity_to_watch->watch_offset, entity_to_watch->orientation, focal_point );
		focal_point += entity_to_watch->origin;
		focal_point[2] += client->ps.pm_defaultviewheight + 18.0f;
	}
	else
	{
		focal_point = entity_to_watch->origin;
		focal_point[2] += client->ps.pm_defaultviewheight + 18.0f;
	}

	if ( client->ps.useCameraFocalPoint )
	{
		client->ps.cameraFocalPoint[ 0 ] = focal_point[ 0 ];
		client->ps.cameraFocalPoint[ 1 ] = focal_point[ 1 ];
		client->ps.cameraFocalPoint[ 2 ] = focal_point[ 2 ];
	}
	
}

void Player::SetPlayerViewNormal( void )
{
	client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
	
	//
	// make sure the third person camera is setup correctly.
	//
	
	int camera_type = currentState_Torso->getCameraType();
	if ( last_camera_type != camera_type )
    {
		//
		// clear out the flags, but preserve the CF_CAMERA_CUT_BIT
		//
		client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT;
		bool do_cut = false;
		switch( camera_type )
		{
		case CAMERA_TOPDOWN:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_offset[ PITCH ] = -75;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			break;
		case CAMERA_FRONT:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			client->ps.camera_offset[ YAW ] = 180;
			client->ps.camera_offset[ PITCH ] = 0;
			do_cut = true;
			break;
		case CAMERA_SIDE:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			// randomly invert the YAW
			if ( G_Random( 1.0f ) > 0.5f )
			{
				client->ps.camera_offset[ YAW ] = -90;
			}
			else
			{
				client->ps.camera_offset[ YAW ] = 90;
			}
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		case CAMERA_SIDE_LEFT:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			client->ps.camera_offset[ YAW ] = 90;
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		case CAMERA_SIDE_RIGHT:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			client->ps.camera_offset[ YAW ] = -90;
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		case CAMERA_BEHIND_FIXED:
			client->ps.camera_offset[ YAW ] = 0;
			client->ps.camera_offset[ PITCH ] = 0;
			client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET;
			break;
		case CAMERA_BEHIND_NOPITCH:
			client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH;
			client->ps.camera_offset[ YAW ] = 0;
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		case CAMERA_BEHIND:
			client->ps.camera_offset[ YAW ] = 0;
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		default:
			client->ps.camera_offset[ YAW ] = 0;
			client->ps.camera_offset[ PITCH ] = 0;
			break;
		}
		last_camera_type = camera_type;
		if ( do_cut )
			CameraCut();
	}
	
	// Add weapon shaking
	ShakeCamera();

}



void Player::SetupView(	void )
{
	// Check for change of state
	// These switch statements are indicative that we need a polymorphic set of classes based off a base class called PlayerCameraController
	switch( playerCameraMode )
	{
	case PLAYER_CAMERA_MODE_NORMAL:
	case PLAYER_CAMERA_MODE_CINEMATIC:
		break;

	case PLAYER_CAMERA_MODE_ACTOR:
		{
			if ( !entity_to_watch  || entity_to_watch->deadflag )
			{
				DestroyActorCamera();
			}
			else
			{
				trace_t trace = G_Trace( actor_camera->origin, Vector(-5, -5, -5), Vector(5, 5, 5), actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView" );
				if ( trace.startsolid )
				{
					DestroyActorCamera();
				}
			}
		}
		break;
	
	case PLAYER_CAMERA_MODE_ENTITY_WATCHING:
		// See if we still want to watch this actor
		{
			if ( entity_to_watch )
			{
				Vector cameraPosition;
				Vector cameraAngles;
				GetPlayerView( &cameraPosition, &cameraAngles );
				Vector directionToWatchedEntity( entity_to_watch->origin - cameraPosition );
				Vector cameraForward;
				cameraAngles.AngleVectors( &cameraForward );
				const float angleToWatchedEntity = RAD2DEG( Vector::AngleBetween( directionToWatchedEntity, cameraForward ) );
				if ( angleToWatchedEntity > maximumAngleToWatchedEntity )
				{
					if ( watchEntityForEntireDuration )
					{
						client->ps.useCameraFocalPoint = false;
					}
					else
					{
						StopWatchingEntity();
					}
				}
				else
				{
					client->ps.useCameraFocalPoint = true;
				}

			}
		}
		break;
	
	case PLAYER_CAMERA_MODE_NO_CLIP:
		break;
	
	default:
		assert( false ); // default case is not valid
	}

	
	
	// Select the camera mode for the player (btw I hate that the player knows anything about cameras) -BillS
	if ( actor_camera)
	{
		playerCameraMode = PLAYER_CAMERA_MODE_ACTOR;
		if ( !camera )
		{
			AutomaticallySelectedNewCamera();
		}
	}
	else if ( entity_to_watch )
	{
		playerCameraMode = PLAYER_CAMERA_MODE_ENTITY_WATCHING;
	}
	else if ( camera )
	{
		playerCameraMode = PLAYER_CAMERA_MODE_CINEMATIC;
	}
	else if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		playerCameraMode = PLAYER_CAMERA_MODE_NO_CLIP;
	}
	else
	{
		playerCameraMode = PLAYER_CAMERA_MODE_NORMAL;
	}

	
	// Update the camera position using the appropriate controller 
	switch( playerCameraMode )
	{
	case PLAYER_CAMERA_MODE_NORMAL:
		{
			SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov );
			SetPlayerViewNormal();		
		}
		break;

	case PLAYER_CAMERA_MODE_ACTOR:
		{
			// Create the camera if we don't have one yet
			if ( !actor_camera )
			{
				actor_camera = new Camera();
			}
			if ( !camera )
			{
				SetCamera( actor_camera, 0.5f );
			}
			SetClientViewAngles( origin, viewheight, v_angle, velocity, camera->Fov() );
			SetPlayerViewUsingActorController( camera );
		}
		break;
	
	case PLAYER_CAMERA_MODE_ENTITY_WATCHING:
		{
			SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov);
			SetPlayerViewUsingEntityWatchingController();
		}
		break;
	
	case PLAYER_CAMERA_MODE_NO_CLIP:
		{
			SetClientViewAngles( origin, client->ps.viewheight, v_angle, velocity, fov );
			SetPlayerViewUsingNoClipController();
		}
		break;

	case PLAYER_CAMERA_MODE_CINEMATIC:
		{
			SetClientViewAngles( origin, viewheight, v_angle, velocity, camera->Fov() );
			SetPlayerViewUsingCinematicController( camera );
		}
		break;
	
	default:
		assert( false ); // default case is not valid
	}
}


void Player::AutomaticallySelectedNewCamera( void )
{
	float bestScore = 999;
	Camera *bestCamera = NULL;

	for( int i = 1; i <= level.automatic_cameras.NumObjects(); i++ )
	{
		Camera *cam = level.automatic_cameras.ObjectAt( i );
		float score = cam->CalculateScore( this, currentState_Torso->getName() );
		
		// if this is our current camera, scale down the score a bit to favor it.
		if ( cam == camera )
		{
			score *= 0.9f;
		}
		
		if ( score < bestScore )
		{
			bestScore = score;
			bestCamera = cam;
		}
	}
	if ( bestScore <= 1.0f )
	{
		// we have a camera to switch to
		if ( bestCamera != camera )
		{
			if ( camera )
			{
				camera->AutomaticStop( this );
			}
			SetCamera( bestCamera, bestCamera->AutomaticStart( this ) );
		}
	}
	else
	{
		// we don't have a camera to switch to
		if ( camera )
		{
			SetCamera( NULL, camera->AutomaticStop( this ) );
		}
	}
}

//----------------------------------------------------------------
// Name:			getWeaponViewShake
// Class:			Player
//
// Description:		Gets the view shake from the current weapon(s)
//
// Parameters:		none
//
// Returns:			Vector					- angles to shake the view by
//----------------------------------------------------------------

Vector Player::getWeaponViewShake( void )
{
	Vector viewShake;
	Weapon *weapon;

	// Try dual hand 

	weapon = GetActiveWeapon( WEAPON_DUAL );

	if ( weapon )
	{
		viewShake = weapon->getViewShake();
	}
	else
	{
		// Try left hand 

		weapon = GetActiveWeapon( WEAPON_LEFT );

		if ( weapon )
		{
			viewShake = weapon->getViewShake();
		}

		// Try right hand 

		weapon = GetActiveWeapon( WEAPON_RIGHT );

		if ( weapon )
		{
			viewShake += weapon->getViewShake();
		}
	}

	return viewShake;
}

void Player::StopWatchingEntity( void )
{
	entity_to_watch = NULL;
	maximumAngleToWatchedEntity = 0.0f;
	client->ps.useCameraFocalPoint = false;
	client->ps.pm_flags &= ~PMF_CAMERA_VIEW;
}

void Player::DestroyActorCamera( void )
{
	if ( actor_camera )
	{
		delete actor_camera;
		actor_camera = NULL;
		SetCamera( NULL, .5f );
	}
}
/*
==================
SwingAngles
==================
*/
void Player::SwingAngles( float destination, float swingTolerance, float clampTolerance, float speed, float *angle,
		qboolean *swinging )
{
	float	swing;
	float	move;
	float	scale;
	
	if ( !*swinging )
	{
		// see if a swing should be started
		swing = AngleSubtract( *angle, destination );
		if ( ( swing > swingTolerance ) || ( swing < -swingTolerance ) )
		{
			*swinging = true;
			// we intentionally return so that we can start the animation before turning
			return;
		}
	}
	
	if ( !*swinging )
	{
		return;
	}
	
	// modify the speed depending on the delta
	// so it doesn't seem so linear
	swing = AngleSubtract( destination, *angle );
	scale = fabs( swing );
	
/****************************************************************************
Squirrel : #if 0 / 1 block demoted to comment
	
#if 0
	if ( scale < swingTolerance * 0.5 )
	{
		scale = 0.5;
	}
	else if ( scale < swingTolerance )
	{
		scale = 1.0;
	}
	else
	{
		scale = 2.0;
	}
#else
	  
****************************************************************************/
	
	scale = 1.0f;
/****************************************************************************
Squirrel : #if 0 / 1 block demoted to comment
	
  #endif
	  
****************************************************************************/
	
	
	// swing towards the destination angle
	if ( swing >= 0.0f )
	{
		move = level.frametime * scale * speed;
		if ( move >= swing )
		{
			move = swing;
			*swinging = false;
		}
		
		*angle = AngleMod( *angle + move );
	}
	else if ( swing < 0.0f )
	{
		move = level.frametime * scale * -speed;
		if ( move <= swing )
		{
			move = swing;
			*swinging = false;
		}
		*angle = AngleMod( *angle + move );
	}
	
	// clamp to no more than tolerance
	swing = AngleSubtract( destination, *angle );
	if ( swing > clampTolerance )
	{
		*angle = AngleMod( destination - ( clampTolerance - 1.0f ) );
	}
	else if ( swing < -clampTolerance )
	{
		*angle = AngleMod( destination + ( clampTolerance - 1.0f ) );
	}
}

void Player::SetHeadTarget
   (
   Event *ev
   )

   {
   str ht = ev->GetString( 1 );

   head_target = G_FindTarget( 0, ht );
   }

qboolean Player::GetTagPositionAndOrientation( int tagnum, orientation_t *new_or )
{
	int            i;
	orientation_t  tag_or;
	vec3_t         axis[3];
	
	tag_or = gi.Tag_OrientationEx( edict->s.modelindex,
			CurrentAnim( legs ),
			CurrentFrame( legs ),
			tagnum & TAG_MASK,
			edict->s.scale,
			edict->s.bone_tag,
			edict->s.bone_quat,
			0,
			0,
			1.0f,
			( edict->s.anim & ANIM_BLEND ) != 0,
			( edict->s.torso_anim & ANIM_BLEND ) != 0,
			CurrentAnim( torso ),
			CurrentFrame( torso ),
			0,
			0,
			1.0f
			);
	
	AnglesToAxis( angles, axis );
	VectorCopy( origin, new_or->origin );
	
	for ( i=0;  i<3; i++ )
		VectorMA( new_or->origin, tag_or.origin[i], axis[i], new_or->origin );
	
	MatrixMultiply( tag_or.axis, axis, new_or->axis );
	return true;
}

qboolean Player::GetTagPositionAndOrientation( const str &tagname, orientation_t *new_or )
{
	int            tagnum;
	
	tagnum = gi.Tag_NumForName( edict->s.modelindex, tagname );
	
	if ( tagnum < 0 )
	{
		warning( "Player::GetTagPositionAndOrientation", "Could not find tag \"%s\"", tagname.c_str() );
		return false;
	}
	
	return GetTagPositionAndOrientation( tagnum, new_or );
}

Vector Player::GetAngleToTarget( const Entity *ent, const str &tag, float yawclamp, float pitchclamp, 
		const Vector &baseangles )
{
	assert( ent );
	
	if ( ent )
	{
		Vector         delta,angs;
		orientation_t  tag_or;
		
		int tagnum = gi.Tag_NumForName( edict->s.modelindex, tag.c_str() );
		
		if ( tagnum < 0 )
			return Vector( 0.0f, 0.0f, 0.0f );
		
		GetTagPositionAndOrientation( tagnum, &tag_or );
		
		delta = ent->centroid - tag_or.origin;
		delta.normalize();
		
		angs = delta.toAngles();
		
		//AnglesSubtract( angs, baseangles, angs );
		angs -= baseangles;
		
		angs[PITCH] = AngleNormalize180( angs[PITCH] );
		angs[YAW]   = AngleNormalize180( angs[YAW] );
		
		if ( angs[PITCH] > pitchclamp )
			angs[PITCH] = pitchclamp;
		else if ( angs[PITCH] < -pitchclamp )
			angs[PITCH] = -pitchclamp;
		
		if ( angs[YAW] > yawclamp )
			angs[YAW] = yawclamp;
		else if ( angs[YAW] < -yawclamp )
			angs[YAW] = -yawclamp;
		
		return angs;
	}
	else
	{
		return Vector( 0.0f, 0.0f, 0.0f );
	}
}

void Player::DebugWeaponTags( int controller_tag, Weapon *weapon, const str &weapon_tagname )
{
	int i;
	orientation_t  bone_or, tag_weapon_or, barrel_or, final_barrel_or;
	
	GetTagPositionAndOrientation( edict->s.bone_tag[controller_tag], &bone_or );
	//G_DrawCoordSystem( Vector( bone_or.origin ), Vector( bone_or.axis[0] ), Vector( bone_or.axis[1] ), Vector( bone_or.axis[2] ), 20 );
	
	GetTagPositionAndOrientation( gi.Tag_NumForName( edict->s.modelindex, weapon_tagname ), &tag_weapon_or );
	//G_DrawCoordSystem( Vector( tag_weapon_or.origin ), Vector( tag_weapon_or.axis[0] ), Vector( tag_weapon_or.axis[1] ), Vector( tag_weapon_or.axis[2] ), 40 );
	
	weapon->GetRawTag( "tag_barrel", &barrel_or );
	VectorCopy( tag_weapon_or.origin, final_barrel_or.origin );
	
	for ( i = 0 ; i < 3 ; i++ )
		VectorMA( final_barrel_or.origin, barrel_or.origin[i], tag_weapon_or.axis[i], final_barrel_or.origin );
	
	MatrixMultiply( barrel_or.axis, tag_weapon_or.axis, final_barrel_or.axis );
	//G_DrawCoordSystem( Vector( final_barrel_or.origin ), Vector( final_barrel_or.axis[0] ), Vector( final_barrel_or.axis[1] ), Vector( final_barrel_or.axis[2] ), 80 );
}

Entity const * Player::GetTarget( void ) const
{
	return targetEnemy;
}

bool Player::GetProjectileLaunchAngles( Vector &launchAngles, const Vector &launchPoint, const float initialSpeed, const float gravity ) const
{
	Entity const *target = GetTarget();
	if ( target && targetEnemyLocked)
	{
		const Vector targetPoint( target->centroid );
		
		Trajectory projectileTrajectory( launchPoint, targetPoint, initialSpeed, gravity * -sv_currentGravity->value );
		if ( projectileTrajectory.GetTravelTime() > 0.0f )
		{
			launchAngles.setPitch( projectileTrajectory.GetLaunchAngle() );

			Vector direction( targetPoint - launchPoint );
			direction.z = 0.0f;
			direction.normalize();

			launchAngles.setYaw( direction.toYaw() );
			launchAngles.setRoll( 0.0f );
			return true;
		}

	}
	return false;
}

void Player::AcquireTarget( void )
{
	targetEnemyLocked = false;
	
	if ( GetTarget() )
	{
		GetTarget()->edict->s.eFlags &= ~PMF_ENEMY_TARGETED;
	}
	
	// Find a right hand target ( might be the same one )
	
	Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
	if ( ! (weapon && weapon->autoAimTargetSelectionAngle) )
	{
		weapon = GetActiveWeapon( WEAPON_LEFT );
	}
	if ( weapon && weapon->autoAimTargetSelectionAngle )
	{
		Entity *newTarget = FindClosestEntityInRadius( weapon->autoAimTargetSelectionAngle, 170.0f, weapon->GetMaxRange() );
		targetEnemy = newTarget;
		if ( newTarget )
		{
			
			if ( FindClosestEntityInRadius( weapon->autoAimLockonAngle, 170.0f, weapon->GetMaxRange() ) )
			{
				targetEnemyLocked = true;
				targetEnemy->edict->s.eFlags |= PMF_ENEMY_TARGETED;
			}
			return;
		}
	}

}

void Player::AutoAim( void )
{
	if ( deadflag )
		return;
	
	// Check for targets in the FOV
	AcquireTarget();

	// Update Crosshair
	if ( _targetSelectedHighlight )
	{
		_targetSelectedHighlight->hideModel();
	}

	if ( _targetLockedHighlight )
	{
		_targetLockedHighlight->hideModel();
	}

	EntityPtr currentHighlight = _targetSelectedHighlight;
	if ( targetEnemyLocked )
	{
		currentHighlight = _targetLockedHighlight;
	}

	if ( currentHighlight && !level.cinematic)
	{
		if ( !GetTarget() )
		{
			return;
		}
		Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT );
		if ( !(weapon && weapon->crosshair) )
		{
			weapon = GetActiveWeapon( WEAPON_LEFT );
		}
		if ( weapon && weapon->crosshair )
        {
			Vector newCrosshairLocation( GetTarget()->origin );
			currentHighlight->setOrigin( newCrosshairLocation );
			currentHighlight->showModel();
		}

	}
}

   
/*
===============
PlayerAngles
===============
*/
void Player::PlayerAngles( void )
{
	float    deltayaw;
	Vector   moveangles;
	float		speed;
	float    yawAngle;
	float    speedscale;
	vec3_t   temp;
	Vector   dir;
	Vector   newAimAngles;
	
	if ( gi.Anim_Flags( edict->s.modelindex, CurrentAnim( legs ) ) & MDL_ANIM_DEFAULT_ANGLES )
	{
		//SetControllerAngles( HEAD_TAG, vec_zero );
		SetControllerAngles( TORSO_TAG, vec_zero );
		setAngles( Vector( 0.0f, v_angle.y, 0.0f ) );
		return;
	}
	
	// set the head and torso directly
	headAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z );
	torsoAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z );
	
	dir = Vector( velocity.x, velocity.y, 0.0f );
	speed = VectorNormalize( dir );
	
	// If moving, angle the legs toward the direction we are moving
	if ( ( speed > 32.0f ) && groundentity && ( last_ucmd.forwardmove || last_ucmd.rightmove ) )
	{
		speedscale = 3;
		yawing   = true; // always center
		deltayaw = AngleSubtract( dir.toYaw(), headAngles[ YAW ] );
	}
	else
	{
		speedscale = 1;
		deltayaw = 0;
	}
	
	// --------- yaw -------------
	// Clamp to g_legclampangle
	if ( fabs( deltayaw ) > 90.0f )
		deltayaw = AngleSubtract( deltayaw, 180.0f );
	
	if ( deltayaw > g_legclampangle->value )
		deltayaw = g_legclampangle->value;
	else if ( deltayaw < -g_legclampangle->value )
		deltayaw = -g_legclampangle->value;
	
	yawAngle = headAngles[ YAW ] + deltayaw;
	
	yawing_left = false;
	yawing_right = false;
	
	if ( client->ps.walking && client->ps.groundPlane && ( movecontrol == MOVECONTROL_LEGS ) &&
		!last_ucmd.forwardmove && !last_ucmd.rightmove && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) )
	{
		float groundyaw;
		float yawdelta;
		
		groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal );
		yawdelta = anglemod( v_angle.y - groundyaw );
		yawdelta = (float)( ( ( ( int )yawdelta + 45 ) / 90 ) * 90.0f );
		angles.y = groundyaw + yawdelta;
	}
	else
	{
		// if purely strafing, don't swing the legs
		if ( dont_turn_legs )
		{
			setAngles( Vector( 0, v_angle.y, 0 ) );
		}
		else
		{
			SwingAngles( yawAngle, g_legtolerance->value, g_legclamptolerance->value, g_legswingspeed->value * speedscale, &angles[ YAW ], &yawing );
			/*if ( yawing )
            {
            float swing;
			swing = AngleSubtract( yawAngle, angles[ YAW ] );
			if ( swing > 0.0f )
			{
			yawing_left = true;
			}
            else
			{
			yawing_right = true;
			}
		}*/
			
			if(last_ucmd.deltaAngles[ YAW ] > 0.0f)
				yawing_left = true;
			if(last_ucmd.deltaAngles[ YAW] < 0.0f)
				yawing_right = true;
		}
	}
	
	if ( ( deadflag == DEAD_DYING ) || ( deadflag == DEAD_DEAD ) )
		headAngles[PITCH] = 0.0f;
	
	// --------- pitch -------------
	headAngles[PITCH] *= 0.65f; // Nerf head angles alittle... head pitch 90 degrees is not reasonable.
	
	// only show a fraction of the pitch angle in the torso
	if ( headAngles[ PITCH ] > 180.0f )
	{
		torsoAngles[PITCH] = ( -360.0f + headAngles[ PITCH ] ) * bendTorsoMult;
	}
	else
	{
		torsoAngles[PITCH] = headAngles[ PITCH ] * bendTorsoMult;
	}
	
	if ( _headWatchAllowed )
		AcquireHeadTarget();
	else
		head_target = NULL;
	
	// Adjust head and torso angles for the target if needed
	if ( head_target )
	{
		//newAimAngles   = GetAngleToTarget( head_target, "Bip01 Head", 60, 45, torsoAngles );
		newAimAngles   = GetAngleToTarget( head_target, "Bip01 Head", 40.0f, 30.0f, torsoAngles );
		
		headAimAngles[PITCH]  = LerpAngle( headAimAngles[PITCH], newAimAngles[PITCH], 0.25f );
		headAimAngles[YAW]    = LerpAngle( headAimAngles[YAW],   newAimAngles[YAW],   0.25f );
		
		torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0.0f, 0.5f );
		torsoAimAngles[YAW]   = LerpAngle( torsoAimAngles[YAW],   0.0f, 0.5f );
	}
	else // Otherwise return to them to 0
	{
		headAimAngles[PITCH]  = LerpAngle( headAimAngles[PITCH],  0.0f, 0.5f );
		headAimAngles[YAW]    = LerpAngle( headAimAngles[YAW],    0.0f, 0.1f );
		
		torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0.0f, 0.5f );
		torsoAimAngles[YAW]   = LerpAngle( torsoAimAngles[YAW],   0.0f, 0.5f );
	}

	//if ( !multiplayerManager.inMultiplayer() )
	{
		// pull the head angles back out of the hierarchial chain
		AnglesSubtract( headAngles, torsoAngles, temp );
		
		// Add in the aim angles for the head
		VectorAdd( temp, headAimAngles, temp );
		
		// Update the head controller
		SetControllerAngles( HEAD_TAG, temp );
		
		// pull the torso angles back out of the hierarchial chain
		AnglesSubtract( torsoAngles, angles, temp );
		
		// Add in the aim angles for the torso
		VectorAdd( temp, torsoAimAngles, temp );
		
		// Update the torso controller
		SetControllerAngles( TORSO_TAG, temp );
	}
	
	// Set the rest (legs)
	setAngles( angles );
}

void Player::FinishMove( void )
{
	//
	// If the origin or velocity have changed since ClientThink(),
	// update the pmove values.  This will happen when the client
	// is pushed by a bmodel or kicked by an explosion.
	//
	// If it wasn't updated here, the view position would lag a frame
	// behind the body position when pushed -- "sinking into plats"
	//
	if ( !( client->ps.pm_flags & PMF_FROZEN ) && !( client->ps.pm_flags & PMF_NO_MOVE ))
	{
		origin.copyTo( client->ps.origin );
		velocity.copyTo( client->ps.velocity );
	}
	
	if ( !( client->ps.pm_flags & PMF_FROZEN ) )
	{
		PlayerAngles();
	}
	
	// burn from lava, etc
	WorldEffects();
	
	// determine the view offsets
	DamageFeedback();
	CalcBlend();
}

void Player::UpdateStats( void )
{
	int i,count;
	float healthToDisplay;
	float armorToDisplay;
	
	// Deathmatch stats for arena mode
	if ( multiplayerManager.inMultiplayer() )
	{
		/*
		// Arena name configstring index
		if ( current_arena )
		{
			client->ps.stats[STAT_ARENA] = CS_ARENA_INFO + current_arena->getID();
		}
		else
		{
			// CS_ARENA_INFO index holds the "No Arena" string
			client->ps.stats[STAT_ARENA] = CS_ARENA_INFO;
		}
		
		if ( current_team )
		{
			client->ps.stats[STAT_TEAM] = current_team->getIndex();
		}
		else
		{
			// CS_TEAM_INFO index holds the "No Team" string
			client->ps.stats[STAT_TEAM] = CS_TEAM_INFO;
		}
		*/

		//client->ps.stats[STAT_KILLS]		= multiplayerManager.getPoints( this );
		//client->ps.stats[STAT_DEATHS]		= multiplayerManager.getDeaths( this );
		//client->ps.stats[STAT_ARENA]		= multiplayerManager.getTeamPoints( this );

		client->ps.stats[STAT_RED_TEAM_SCORE]  = multiplayerManager.getTeamPoints( "Red" );
		client->ps.stats[STAT_BLUE_TEAM_SCORE] = multiplayerManager.getTeamPoints( "Blue" );

		client->ps.stats[STAT_SCORE]  = multiplayerManager.getPoints( this );
		client->ps.stats[STAT_KILLS]  = multiplayerManager.getKills( this );
		client->ps.stats[STAT_DEATHS] = multiplayerManager.getDeaths( this );
		
		client->ps.stats[STAT_MP_GENERIC1] = multiplayerManager.getStat( this, STAT_MP_GENERIC1 );
		client->ps.stats[STAT_MP_GENERIC2] = multiplayerManager.getStat( this, STAT_MP_GENERIC2 );
		client->ps.stats[STAT_MP_GENERIC3] = multiplayerManager.getStat( this, STAT_MP_GENERIC3 );
		client->ps.stats[STAT_MP_GENERIC4] = multiplayerManager.getStat( this, STAT_MP_GENERIC4 );
		client->ps.stats[STAT_MP_GENERIC5] = multiplayerManager.getStat( this, STAT_MP_GENERIC5 );
		client->ps.stats[STAT_MP_GENERIC6] = multiplayerManager.getStat( this, STAT_MP_GENERIC6 );
		client->ps.stats[STAT_MP_GENERIC7] = multiplayerManager.getStat( this, STAT_MP_GENERIC7 );
		client->ps.stats[STAT_MP_GENERIC8] = multiplayerManager.getStat( this, STAT_MP_GENERIC8 );

		client->ps.stats[STAT_MP_SPECTATING_ENTNUM] = multiplayerManager.getStat( this, STAT_MP_SPECTATING_ENTNUM );
		
		client->ps.stats[STAT_MP_MODE_ICON]			= multiplayerManager.getIcon( this, STAT_MP_MODE_ICON );
		client->ps.stats[STAT_MP_TEAM_ICON]			= multiplayerManager.getIcon( this, STAT_MP_TEAM_ICON );
		client->ps.stats[STAT_MP_TEAMHUD_ICON]		= multiplayerManager.getIcon( this, STAT_MP_TEAMHUD_ICON );
		client->ps.stats[STAT_MP_SPECIALTY_ICON]	= multiplayerManager.getIcon( this, STAT_MP_SPECIALTY_ICON );

		client->ps.stats[STAT_MP_OTHERTEAM_ICON]	= multiplayerManager.getIcon( this, STAT_MP_OTHERTEAM_ICON );

		if ( multiplayerManager.inMultiplayer() )
			edict->s.infoIcon = multiplayerManager.getInfoIcon( this, last_ucmd.buttons );
		else
			edict->s.infoIcon = 0;

		client->ps.stats[STAT_MP_AWARD_ICON]  = multiplayerManager.getIcon( this, STAT_MP_AWARD_ICON );
		client->ps.stats[STAT_MP_AWARD_COUNT] = multiplayerManager.getStat( this, STAT_MP_AWARD_COUNT );

		client->ps.stats[STAT_MP_STATE] = multiplayerManager.getStat( this, STAT_MP_STATE );
		
		if ( _holdableItem )
			client->ps.stats[STAT_MP_HOLDABLEITEM_ICON]	= _holdableItem->getIcon();
		else
			client->ps.stats[STAT_MP_HOLDABLEITEM_ICON]	= -1;
		
		if ( _rune )
			client->ps.stats[STAT_MP_RUNE_ICON]			= _rune->getIcon();
		else
			client->ps.stats[STAT_MP_RUNE_ICON]			= -1;
		
		if ( _powerup )
			client->ps.stats[STAT_MP_POWERUP_ICON]		= _powerup->getIcon();
		else
			client->ps.stats[STAT_MP_POWERUP_ICON]		= -1;
		
		/* client->ps.stats[STAT_WON_MATCHES]     = num_won_matches;
		client->ps.stats[STAT_LOST_MATCHES]    = num_lost_matches; */
		
		// Get queue position
		//client->ps.stats[STAT_QUEUE_PLACE] = 0;
		/*
		if ( current_arena )
		{
			client->ps.stats[STAT_QUEUE_PLACE] = current_arena->GetLinePosition( this );
		}
		*/
//		multiplayerManager.getStat( this, STAT_TIMELEFT_MINUTES );
		client->ps.stats[STAT_TIMELEFT_SECONDS] = multiplayerManager.getStat( this, STAT_TIMELEFT_SECONDS );
	}
	
	//
	// Health
	//

	// Use my health/armor as the default to display

	healthToDisplay = health;
	armorToDisplay = GetArmorValue();

	if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) )
	{
		Player *playerSpectating;

		playerSpectating = multiplayerManager.getPlayerSpectating( this );

		if ( playerSpectating )
		{
			// Display the health/armor of the player we are spectating instead of ours

			healthToDisplay = playerSpectating->getHealth();
			armorToDisplay = playerSpectating->GetArmorValue();
		}
	}

	// Round health a little so that it doesn't mislead the player when it gets changed to an int

	if ( ( healthToDisplay < 1.0f ) && ( healthToDisplay > 0.0f ) )
	{
		client->ps.stats[ STAT_HEALTH ] = 1;
	}
	else
	{
		client->ps.stats[ STAT_HEALTH ] = (int)healthToDisplay;
	}


	if ( health <= 0.0f )
	{
		Vector damageAngles = damage_from * -1;
		damageAngles = damageAngles.toAngles();
		client->ps.stats[ STAT_DEAD_YAW ] = (int)  damageAngles[ YAW ];
	}
	else
	{
		client->ps.stats[ STAT_DEAD_YAW ] = 0;
	}
	
	//ArmorValue Stat Update
	client->ps.stats[ STAT_ARMOR_LEVEL ] = (int) armorToDisplay;
	
	Weapon *leftweapon  = GetActiveWeapon( WEAPON_LEFT );
	Weapon *rightweapon = GetActiveWeapon( WEAPON_RIGHT );
	Weapon *dualweapon  = GetActiveWeapon( WEAPON_DUAL );
	
	client->ps.stats[STAT_AMMO_LEFT]                 = 0;
	client->ps.stats[STAT_AMMO_RIGHT]                = 0;
	client->ps.stats[STAT_CLIPAMMO_LEFT]             = 0;
	client->ps.stats[STAT_CLIPAMMO_RIGHT]            = 0;
	client->ps.stats[STAT_NUM_SHOTS_LEFT]			 = 0;
	client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT]		 = 0;
	client->ps.stats[STAT_NUM_SHOTS_RIGHT]			 = 0;
	client->ps.stats[STAT_MAXAMMO_LEFT]              = 0;
	client->ps.stats[STAT_MAXAMMO_RIGHT]             = 0;
	client->ps.stats[STAT_MAXCLIPAMMO_LEFT]          = 0;
	client->ps.stats[STAT_MAXCLIPAMMO_RIGHT]         = 0;

	client->ps.stats[STAT_AMMO_TYPE1]				 = 0;
	client->ps.stats[STAT_AMMO_TYPE2]				 = 0;
	client->ps.stats[STAT_AMMO_TYPE3]				 = 0;
	client->ps.stats[STAT_AMMO_TYPE4]				 = 0;

	if ( _powerup )
		client->ps.stats[ STAT_POWERUPTIME ] = static_cast<int>( _powerup->getTimeLeft() );
	else
		client->ps.stats[ STAT_POWERUPTIME ] = 0;
	
	client->ps.stats[ STAT_ACCUMULATED_PAIN]         = (int) accumulated_pain;
	
	client->ps.activeItems[ ITEM_NAME_AMMO_LEFT		]		= -1;
	client->ps.activeItems[ ITEM_NAME_AMMO_RIGHT	]		= -1;
	client->ps.activeItems[ ITEM_NAME_WEAPON_LEFT	]		= -1;
	client->ps.activeItems[ ITEM_NAME_WEAPON_RIGHT	]		= -1;
	client->ps.activeItems[ ITEM_NAME_WEAPON_DUAL	]		= -1;
#ifndef DEDICATED	
	//
	// mission objectives
	//
	client->ps.stats[STAT_NUM_OBJECTIVES]			= gi.MObjective_GetNumActiveObjectives();
	client->ps.stats[STAT_COMPLETE_OBJECTIVES]		= gi.MObjective_GetNumCompleteObjectives();
	client->ps.stats[STAT_FAILED_OBJECTIVES]		= gi.MObjective_GetNumFailedObjectives();
	client->ps.stats[STAT_INCOMPLETE_OBJECTIVES]	= gi.MObjective_GetNumIncompleteObjectives();
#endif

	// misc stats
	if ( client->ps.stats[ STAT_SHOTS_FIRED ] > 0 )
		client->ps.stats[STAT_ACCURACY] = (int)((float)( (float)client->ps.stats[ STAT_SHOTS_HIT ] / (float)client->ps.stats[ STAT_SHOTS_FIRED ] ) * 100.0f);
	else
		client->ps.stats[STAT_ACCURACY] = 100;
		
	client->ps.stats[STAT_MISSION_DURATION] = (int) level.timeInLevel;
	
	client->ps.stats[ STAT_WEAPON_GENERIC1 ] = 0;
	client->ps.stats[ STAT_WEAPON_GENERIC2 ] = 0;
	
	if ( dualweapon )
	{
		// Left is PRIMARY
		if ( dualweapon->GetClipSize( FIRE_MODE1 ) > 0 )
		{
			//set the max ammo to contain the number of clips and the max number of clips.
			client->ps.stats[STAT_AMMO_LEFT]        = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->GetClipSize( FIRE_MODE1 );
			client->ps.stats[STAT_MAXAMMO_LEFT]     = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->GetClipSize( FIRE_MODE1 );

			client->ps.stats[STAT_CLIPAMMO_LEFT]    = dualweapon->ClipAmmo( FIRE_MODE1 );
			client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = dualweapon->GetClipSize( FIRE_MODE1 );

			if( dualweapon->ammorequired[FIRE_MODE1] != 0)
			{
				client->ps.stats[STAT_NUM_SHOTS_LEFT]		= dualweapon->ClipAmmo( FIRE_MODE1 ) / dualweapon->ammorequired[FIRE_MODE1]; 
				client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT]	= dualweapon->GetClipSize( FIRE_MODE1 ) / dualweapon->ammorequired[FIRE_MODE1];
			}
		}
		else
		{
			client->ps.stats[STAT_AMMO_LEFT]        = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_MAXAMMO_LEFT]     = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );

			client->ps.stats[STAT_CLIPAMMO_LEFT]    = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) );

			if( dualweapon->ammorequired[FIRE_MODE1] != 0)
			{
				client->ps.stats[STAT_NUM_SHOTS_LEFT]		= AmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->ammorequired[FIRE_MODE1]; 
				client->ps.stats[STAT_MAX_NUM_SHOTS_LEFT]	= MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE1 ) ) / dualweapon->ammorequired[FIRE_MODE1];
			}
			

		}


		
		client->ps.activeItems[ITEM_NAME_AMMO_LEFT]     = AmmoIndex( dualweapon->GetAmmoType( FIRE_MODE1 ) );
		
		// Right is AlTERNATE
		client->ps.stats[STAT_AMMO_RIGHT]               = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
		client->ps.stats[STAT_MAXAMMO_RIGHT]            = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
		
		if ( dualweapon->GetClipSize( FIRE_MODE2 ) > 0 )
		{
			client->ps.stats[STAT_CLIPAMMO_RIGHT]    = dualweapon->ClipAmmo( FIRE_MODE2 );
			client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = dualweapon->GetClipSize( FIRE_MODE2 );

			if(dualweapon->ammorequired[FIRE_MODE2] != 0)
				client->ps.stats[STAT_NUM_SHOTS_RIGHT]	 = dualweapon->ClipAmmo( FIRE_MODE2 ) / dualweapon->ammorequired[FIRE_MODE2]; 
		}
		else
		{
			client->ps.stats[STAT_CLIPAMMO_RIGHT]    = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );
			client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) );

			if(dualweapon->ammorequired[FIRE_MODE2] != 0)
				client->ps.stats[STAT_NUM_SHOTS_RIGHT]	 = AmmoCount( dualweapon->GetAmmoType( FIRE_MODE2 ) ) / dualweapon->ammorequired[FIRE_MODE2]; 

		}
		


		
		client->ps.activeItems[ITEM_NAME_AMMO_RIGHT]    = AmmoIndex( dualweapon->GetAmmoType( FIRE_MODE2 ) );
		
		client->ps.activeItems[ITEM_NAME_WEAPON_DUAL] = dualweapon->getIndex();

		//Send the # for all ammo groups
		//This should be fixed since its a poor implementation.

		for( int i = 1; i <= ammo_inventory.NumObjects(); i++ )
		{
			if(ammo_inventory.ObjectAt(i)->getName() == "Plasma")
			{
				client->ps.stats[STAT_AMMO_TYPE1] = ammo_inventory.ObjectAt(i)->getAmount();
			}
			else if(ammo_inventory.ObjectAt(i)->getName() == "Fed")
			{
				client->ps.stats[STAT_AMMO_TYPE2] = ammo_inventory.ObjectAt(i)->getAmount();
			}
			else if(ammo_inventory.ObjectAt(i)->getName() == "Idryll")
			{
				client->ps.stats[STAT_AMMO_TYPE3] = ammo_inventory.ObjectAt(i)->getAmount();
			}
			else if( ammo_inventory.ObjectAt(i)->getName() == "Phaser" )
			{
				client->ps.stats[STAT_AMMO_TYPE4] = ammo_inventory.ObjectAt(i)->getAmount();
			}
		}

		client->ps.stats[ STAT_WEAPON_GENERIC1 ] = dualweapon->getStat( STAT_WEAPON_GENERIC1 );
		client->ps.stats[ STAT_WEAPON_GENERIC2 ] = dualweapon->getStat( STAT_WEAPON_GENERIC2 );
	}
	else
	{
		if ( leftweapon )
		{
			client->ps.stats[STAT_AMMO_LEFT]                = AmmoCount( leftweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_MAXAMMO_LEFT]             = MaxAmmoCount( leftweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_CLIPAMMO_LEFT]            = leftweapon->ClipAmmo( FIRE_MODE1 );
			client->ps.stats[STAT_MAXCLIPAMMO_LEFT]         = leftweapon->GetClipSize( FIRE_MODE1 );
			client->ps.activeItems[ITEM_NAME_AMMO_LEFT]     = AmmoIndex( leftweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.activeItems[ITEM_NAME_WEAPON_LEFT]   = leftweapon->getIndex();
			
		}
		
		if ( rightweapon )
		{
			client->ps.stats[STAT_AMMO_RIGHT]               = AmmoCount( rightweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_MAXAMMO_RIGHT]            = MaxAmmoCount( rightweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.stats[STAT_CLIPAMMO_RIGHT]           = rightweapon->ClipAmmo( FIRE_MODE1 );
			client->ps.stats[STAT_MAXCLIPAMMO_RIGHT]        = rightweapon->GetClipSize( FIRE_MODE1 );
			client->ps.activeItems[ITEM_NAME_AMMO_RIGHT]    = AmmoIndex( rightweapon->GetAmmoType( FIRE_MODE1 ) );
			client->ps.activeItems[ITEM_NAME_WEAPON_RIGHT]  = rightweapon->getIndex();
			
		}
	}
	
	
	//
	// set boss health and name
	//
	
	if ( bosshealth->value > 0.0f )
	{
		client->ps.stats[ STAT_BOSSHEALTH ] = (int)(bosshealth->value * 100.0f);
		
		if ( ( ( bosshealth->value * 100.0f ) > 0 ) && ( client->ps.stats[ STAT_BOSSHEALTH ] == 0 ) )
		{
			client->ps.stats[ STAT_BOSSHEALTH ] = 1;
		}
		
		client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = G_FindConfigstringIndex( bossname->string, CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
		//client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = gi.soundindex( bossname->string ) + CS_SOUNDS;
	}
	else
	{
		client->ps.stats[ STAT_BOSSHEALTH ] = 0;
	}

	if ( _itemText.length() > 0  )
	{
		client->ps.stats[ STAT_ITEMICON ] = _itemIcon;
		
		client->ps.stats[ STAT_ITEMTEXT ] = G_FindConfigstringIndex( _itemText.c_str(), CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
		//client->ps.stats[ STAT_BOSSNAME_CONFIGINDEX ] = gi.soundindex( bossname->string ) + CS_SOUNDS;
	}
	else
	{
		client->ps.stats[ STAT_ITEMTEXT ] = -1;
	}

	if ( _voteText.length() > 0  )
	{	
		client->ps.stats[ STAT_VOTETEXT ] = G_FindConfigstringIndex( _voteText.c_str(), CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;
	}
	else
	{
		client->ps.stats[ STAT_VOTETEXT ] = -1;
	}
	
	if ( specialMoveEndTime > 0.0f )
	{
		float beginTime = specialMoveEndTime - specialMoveChargeTime;
		float timeElapsed = specialMoveCharge - beginTime;
		float percentElapsed = timeElapsed / specialMoveChargeTime;
		float finalValue = percentElapsed * 100.0f;
		if ( finalValue > 100.0f )
			finalValue = 100.0f;
		client->ps.stats[ STAT_SPECIALMOVETIMER ] = (int) finalValue;
	}	
	else
		client->ps.stats[ STAT_SPECIALMOVETIMER ] = 0;
	
	client->ps.stats[ STAT_POINTS ] = points;

	client->ps.stats[ STAT_SECRETS_TOTAL ] = level.total_secrets;
	client->ps.stats[ STAT_SECRETS_FOUND ] = level.found_secrets;
	client->ps.stats[ STAT_ITEMS_TOTAL ] = level.total_specialItems;
	client->ps.stats[ STAT_ITEMS_FOUND ] = level.found_specialItems;
	
	
	// Set cinematic stuff
	
	client->ps.stats[ STAT_CINEMATIC ] = 0;
	
	if ( level.cinematic )
		client->ps.stats[ STAT_CINEMATIC ] = (1<<0);
	
	if ( actor_camera )
		client->ps.stats[ STAT_CINEMATIC ] += (1<<1);
	
	// Go through all the player's weapons and send over the indexes of the names
	memset( client->ps.inventory_name_index, 0, sizeof( client->ps.inventory_name_index ) );
	memset( client->ps.ammo_in_clip, 0, sizeof(client->ps.ammo_in_clip));
	
	count = inventory.NumObjects();
	
	if ( count > MAX_INVENTORY )
	{
		count = MAX_INVENTORY;
		warning( "Player::UpdateStats", "Max inventory exceeded\n" );
	}
	
	Weapon* weapon;
	Ammo*	ammo;
	int		ammoRequired;
	for ( i=1; i<=count; i++ )
	{
		int entnum = inventory.ObjectAt( i );
		Item *item = ( Item * )G_GetEntity( entnum );

		if ( item )
		{
			client->ps.inventory_name_index[i-1] = item->getIndex();
			if( item->isSubclassOf(Weapon) )
			{
				weapon = (Weapon*) item;
				ammo = FindAmmoByName(weapon->GetAmmoType(FIRE_MODE1));
				if( ammo == 0)
					continue;
				client->ps.inventory_weapon_ammo_index[ i - 1 ]		= ammo->getIndex();
				
				ammoRequired = weapon->GetRequiredAmmo(FIRE_MODE1);
				client->ps.inventory_weapon_required_ammo[i - 1]	= ammoRequired;
				
				client->ps.ammo_in_clip[ i - 1 ] = weapon->getAmmoInClip(FIRE_MODE1);
			}
		}
	}
	
	// Go through all the player's ammo and send over the names/amounts
	memset( client->ps.ammo_amount, 0, sizeof( client->ps.ammo_amount ) );
	count = ammo_inventory.NumObjects();
	
	assert( count < MAX_AMMO );
	if ( count > MAX_AMMO )
	{
		gi.Error( ERR_DROP, "Player::UpdateStats : Exceeded MAX_AMMO\n" );
	}
	
	for ( i=1; i<=count; i++ )
	{
		Ammo *ammo = ammo_inventory.ObjectAt( i );
		
		if ( ammo )
		{
			client->ps.ammo_amount[i-1]     = ammo->getAmount();
			client->ps.max_ammo_amount[i-1] = ammo->getMaxAmount();
			client->ps.ammo_name_index[i-1] = ammo->getIndex();
		}
	}
	
	// Do letterbox
	
	// Check for letterbox fully out
	if ( ( level.m_letterbox_time <= 0.0f ) && ( level.m_letterbox_dir == letterbox_in ) )
	{
		client->ps.stats[STAT_LETTERBOX] = (int)(level.m_letterbox_fraction * MAX_LETTERBOX_SIZE);
		return;
	}
	else if ( ( level.m_letterbox_time <= 0.0f ) && ( level.m_letterbox_dir == letterbox_out ) )
	{
		client->ps.stats[STAT_LETTERBOX] = 0;
		return;
	}
	
	float frac;
	
	level.m_letterbox_time -= level.frametime;
	
	frac = level.m_letterbox_time / level.m_letterbox_time_start;
	
	if ( frac > 1.0f )
		frac = 1.0f;
	if ( frac < 0.0f )
		frac = 0.0f;
	
	if ( level.m_letterbox_dir == letterbox_in )
		frac = 1.0f - frac;
	
	client->ps.stats[STAT_LETTERBOX] = (int)((float)( frac * level.m_letterbox_fraction ) * MAX_LETTERBOX_SIZE);
	
	// Stats for Mission Status
}

//-----------------------------------------------------
//
// Name:		UpdateObjectiveStatus	
// Class:		Player	
//
// Description:	Updates the player state of the mission objectives.
//
// Parameters:	None
//
// Returns:		None
//-----------------------------------------------------
void Player::UpdateObjectiveStatus( void )
{
	client->ps.objectiveStates = _objectiveStates;
	client->ps.informationStates = _informationStates;
	client->ps.objectiveNameIndex = _objectiveNameIndex;
}

void Player::UpdateMusic( void )
{
	
	if ( !g_allowActionMusic->integer || !_allowActionMusic )
	{
		action_level = 0.0f;
	}
	
	if ( music_forced )
	{
		client->ps.current_music_mood = music_current_mood;
		client->ps.fallback_music_mood = music_fallback_mood;
	}
	else if ( action_level > 30.0f )
	{
		client->ps.current_music_mood = mood_action;
		client->ps.fallback_music_mood = mood_normal;
	}
	else if ( action_level < 15.0f )
	{
		client->ps.current_music_mood = music_current_mood;
		client->ps.fallback_music_mood = music_fallback_mood;
	}
	
	if ( action_level > 0.0f )
	{
		if ( multiplayerManager.inMultiplayer() )
		{
			action_level -= level.fixedframetime * 2.0f;
		}
		else
		{
			action_level -= level.fixedframetime * 15.0f;
		}

		if ( action_level > 80.0f )
		{
			action_level = 80.0f;
		}
	}
	else
	{
		action_level = 0.0f;
	}
	
	//
	// set the music
	// naturally decay the action level
	//
	if ( s_debugmusic->integer )
	{
		gi.DPrintf( "%s's action_level = %4.2f\n", client->pers.netname, action_level );
	}
	
	// Copy music volume and fade time to player state
	client->ps.music_volume				= music_current_volume;
	client->ps.music_volume_fade_time	= music_volume_fade_time;
	client->ps.allowMusicDucking		= _allowMusicDucking;
}

void Player::SetReverb( int type, float level )
{
	reverb_type  = type;
	reverb_level = level;
}

void Player::SetReverb( const str &type, float level )
{
	reverb_type  = EAXMode_NameToNum( type );
	reverb_level = level;
}

void Player::SetReverb( Event *ev )
{
	if ( ev->NumArgs() < 2 )
		return;
	
	SetReverb( ev->GetInteger( 1 ), ev->GetFloat( 2 ) );
}

void Player::UpdateReverb( void )
{
	client->ps.reverb_type  = reverb_type;
	client->ps.reverb_level = reverb_level;
}

void Player::EndAnim_Legs( Event *ev )
{
	if ( vehicle )
		return;
	
	animdone_Legs = true;
	animate->SetAnimDoneEvent( EV_Player_AnimLoop_Legs, legs );
	EvaluateState();
}

void Player::EndAnim_Torso( Event *ev )
{
	if ( vehicle )
		return;
	
	animdone_Torso = true;
	animate->SetAnimDoneEvent( EV_Player_AnimLoop_Torso, torso );
	EvaluateState();
}

void Player::SetAnim( const char *anim, bodypart_t part, bool force )
{
	assert( anim );
	
	if ( !force && ( part != all ) && ( partAnim[ part ] == anim ) )
	{
		return;
	}
	
	if ( !force && ( part == all ) && ( partAnim[ legs ] == anim ) && ( partAnim[ torso ] == anim ) )
	{
		return;
	}
	
	if ( getMoveType() == MOVETYPE_NOCLIP )
	{
		anim = "idle";
	}
	
	if ( part != all )
	{
		partAnim[ part ] = anim;
	}
	else
	{
		partAnim[ legs ] = anim;
		partAnim[ torso ] = anim;
	}
	
	switch( part )
	{
	default :
	case all :
		animate->RandomAnimate( anim, EV_Player_AnimLoop_Legs, part );
		break;
		
	case legs :
		animate->RandomAnimate( anim, EV_Player_AnimLoop_Legs, part );
		break;
		
	case torso :
		animate->RandomAnimate( anim, EV_Player_AnimLoop_Torso, part );
		break;
	}
	
	if ( ( part == legs ) || ( part == all ) )
	{
		Vector animmove;
		float time;
		float len;
		
		time = gi.Anim_Time( edict->s.modelindex, CurrentAnim() );
		gi.Anim_Delta( edict->s.modelindex, CurrentAnim(), animmove );
		len = animmove.length();
		if ( ( len == 0.0f ) || ( time == 0.0f ) )
		{
			animspeed = 0;
		}
		else
		{
			animspeed = len / time;
		}
	}
}

void Player::CheckReloadWeapons( void )
{
	Weapon *weap;
	
	weap = GetActiveWeapon( WEAPON_DUAL );

	if ( weap )
	{
		weap->CheckReload();
	}
	else
	{
		weap = GetActiveWeapon( WEAPON_LEFT );
		if ( weap )
		{
			weap->CheckReload();
		}
		
		weap = GetActiveWeapon( WEAPON_RIGHT );
		if ( weap )
		{
			weap->CheckReload();
		}
	}
}

void Player::UpdateMisc( void )
{
	//
	// clear out the level exit flag
	//
	client->ps.pm_flags &= ~PMF_LEVELEXIT;
	
	//
	// see if our camera is the level exit camera
	//
	if ( camera && camera->IsLevelExit() )
	{
		client->ps.pm_flags |= PMF_LEVELEXIT;
	}
	else if ( level.near_exit )
	{
		client->ps.pm_flags |= PMF_LEVELEXIT;
	}
	//
	// do anything special for level exits
	//
	if ( client->ps.pm_flags & PMF_LEVELEXIT )
	{
		//
		// change music
		//
		if ( music_current_mood != mood_success )
		{
			ChangeMusic( "success", "normal", false );
		}
	}

	if(_updateGameFrames == true)
		_totalGameFrames++;

	//Update the dialog information.
	client->ps.dialogEntnum			= _dialogEntnum;
	client->ps.dialogSoundIndex		= _dialogSoundIndex;
	client->ps.dialogTextSoundIndex = _dialogTextSoundIndex;
}

/*
=================
EndFrame

Called for each player at the end of the server frame
and right after spawning
=================
*/
void Player::EndFrame( Event *ev )
{
	AutoAim();
	
	if ( meleeAttackFlags & MELEE_ATTACK_LEFT )
		AdvancedMeleeAttack(WEAPON_LEFT);
	
	if ( meleeAttackFlags & MELEE_ATTACK_RIGHT )
		AdvancedMeleeAttack(WEAPON_RIGHT);
	
	if ( finishableList.NumObjects() > 0 )
		HandleFinishableList();
	else
	{
		//G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", false ); // Temporary
		_doingFinishingMove = false;
		_finishActor = NULL;
		_finishState = "";
	}
	
	FinishMove();
	CheckReloadWeapons();
	UpdateStats();
	UpdateMusic();
	UpdateReverb();
	UpdateMisc();
	SetupView();
	UpdateObjectiveStatus();
	
	if ( _powerup )
		_powerup->update( level.frametime );
	
	if ( _rune )
		_rune->update( level.frametime );
	
	if ( _holdableItem )
		_holdableItem->update( level.frametime );

	if ( multiplayerManager.inMultiplayer() && ( _lastPainShaderMod != MOD_NONE ) && ( _nextPainShaderTime < level.time ) )
	{
		str painShader = getPainShader( _lastPainShaderMod, false );

		clearCustomShader( "ArmorDeflection" );

		if ( painShader.length() > 0 )
		{
			clearCustomShader( painShader );

			_lastPainShaderMod = MOD_NONE;
		}
	}

	if ( needToSendAllHudsToClient() )
	{
		sendAllHudsToClient();
	}

	if( _needToSendBranchDialog == true && _started )
	{
		_needToSendBranchDialog = false;
		if(_branchDialogActor)
			_branchDialogActor->setBranchDialog();
	}

	_cameraCutThisFrame = false;
}


void Player::GibEvent( Event *ev )
{
	qboolean hidemodel;
	
	hidemodel = !ev->GetInteger( 1 );
	
	if ( com_blood->integer )
	{
		if ( hidemodel )
		{
			gibbed = true;
			takedamage = DAMAGE_NO;
			setSolidType( SOLID_NOT );
			hideModel();
		}
		
		CreateGibs( this, health, 0.75f, 3 );
	}
}

void Player::GotKill( Event *ev )
{
}

/* void Player::SetPowerupTimer
   (
   Event *ev
   )

   {
   Event *event;

   poweruptimer = ev->GetInteger( 1 );
   poweruptype  = (powerup_t)ev->GetInteger( 2 );
   event = new Event( EV_Player_UpdatePowerupTimer );
   PostEvent ( event, 1.0f );

	if ( p_heuristics )
		p_heuristics->IncrementItemsPickedUp();	
   } */

/* void Player::UpdatePowerupTimer
   (
   Event *ev
   )

   {
   poweruptimer -= 1;
   if ( poweruptimer > 0 )
      {
      Event *event = new Event( EV_Player_UpdatePowerupTimer );
		PostEvent ( event, 1.0f );
      }
   else
      {
		// Reset any flags as necessary, powerup is done
		if ( poweruptype == POWERUP_STEALTH && (flags & FL_NOTARGET) )
			flags ^= FL_NOTARGET;
		if ( poweruptype == POWERUP_PROTECTION && (flags & FL_GODMODE) )
			flags ^= FL_GODMODE;

		if ( poweruptype == POWERUP_ACCURACY )
			{
			Weapon *weap;
			weap = GetActiveWeapon( WEAPON_DUAL );
			// Tell the weapon we lost the accuracy powerup
			if ( weap )
				weap->SetAccuracyPowerup( false );
			}

      poweruptype = POWERUP_NONE;
      }
   } */

void Player::ChangeMusic( const char * current, const char * fallback, qboolean force )
{
	int current_mood_num;
	int fallback_mood_num;
	
	music_forced = force;
	if ( str( current ) == "normal" )
	{
		music_forced = false;
	}

	// We no longer let any music be forced
	//music_forced = false;
	
	// zero out action_level so that we do get a change
	//
	action_level = 0;
	
	if ( current )
	{
		current_mood_num = MusicMood_NameToNum( current );
		if ( current_mood_num < 0 )
		{
			gi.DPrintf( "current music mood %s not found", current );
		}
		else
		{
			music_current_mood = current_mood_num;
		}
	}
	
	if ( fallback )
	{
		fallback_mood_num = MusicMood_NameToNum( fallback );
		if ( fallback_mood_num < 0 )
		{
			gi.DPrintf( "fallback music mood %s not found", fallback );
			fallback = NULL;
		}
		else
		{
			music_fallback_mood = fallback_mood_num;
		}
	}
}

void Player::ChangeMusicVolume( float volume, float fade_time )
{
	music_volume_fade_time = fade_time;
	music_saved_volume     = music_current_volume;
	music_current_volume   = volume;
}

void Player::RestoreMusicVolume( float fade_time )
{
	music_volume_fade_time = fade_time;
	music_current_volume   = music_saved_volume;
	music_saved_volume     = -1.0f;
}

//----------------------------------------------------------------
// Name:			allowMusicDucking
// Class:			Player
//
// Description:		Specifies whether or not music ducking is allowed
//
// Parameters:		bool allowMusicDucking					- whether or not music ducking is allowed
//
// Returns:			none
//----------------------------------------------------------------

void Player::allowMusicDucking( bool allowMusicDucking )
{
	_allowMusicDucking = allowMusicDucking;
}

//----------------------------------------------------------------
// Name:			allowActionMusic
// Class:			Player
//
// Description:		Specifies whether or not action music is allowed
//
// Parameters:		bool allowActionMusic					- whether or not action music is allowed
//
// Returns:			none
//----------------------------------------------------------------

void Player::allowActionMusic( bool allowActionMusic )
{
	_allowActionMusic = allowActionMusic;
}

void Player::GiveOxygen( float time )
{
	air_finished = level.time + time;
}

void Player::Jump( Event *ev )
{
	float maxheight;
	
	maxheight = ev->GetFloat( 1 );
	
	if ( maxheight > 16.0f )
	{
		// v^2 = 2ad
		velocity[ 2 ] += sqrt( 2.0f * sv_currentGravity->integer * maxheight );
		
		// make sure the player leaves the ground
		client->ps.walking = false;
	}
}

void Player::JumpXY( Event *ev )
{
	float forwardmove;
	float sidemove;
	float distance;
	float time;
	float speed;
	
	forwardmove = ev->GetFloat( 1 );
	sidemove    = ev->GetFloat( 2 );
	speed       = ev->GetFloat( 3 );
	
	velocity = ( yaw_forward * forwardmove ) - ( yaw_left * sidemove );
	distance = velocity.length();
	velocity *= speed / distance;
	time = distance / speed;
	velocity[ 2 ] = sv_currentGravity->integer * time * 0.5f;
	
	airspeed = distance;
	
	// make sure the player leaves the ground
	client->ps.walking = false;
}

void Player::StartFakePlayer( void )
{
	Actor * fake;
	
	//
	// if we don't have a fakePlayer active, no need to check
	//
	if ( !fakePlayer_active )
	{
		return;
	}
	
	fakePlayer_active = false;
	
	fakePlayer = new Actor;
	
	if ( !fakePlayer )
		return;
	
	fake = fakePlayer;
	
	CloneEntity( fake, this );
	
	fake->SetTargetName( "fakeplayer" );
	fake->ProcessEvent( EV_Actor_AIOff );
	
	// make sure it thinks so that it can fall when necessary
	fake->turnThinkOn();
	
	// Make the fake player a stepsize shorter to prevent some collision issues
	
	fake->maxs[2] -= STEPSIZE;
	fake->setSize( mins, maxs );
	
	fake->takedamage = DAMAGE_NO;
	
	// hide the player
	this->hideModel();
	this->ProcessEvent( EV_Sentient_TurnOffShadow );
	//
	// immobolize the player
	//
	this->flags |= FL_IMMOBILE;
	// make the player not solid
	setSolidType( SOLID_NOT );
	
	// let the scripts now we are ready
	PostEvent( EV_Player_Done, 0.0f );
}

void Player::FakePlayer( qboolean holster )
{
	//
	// make sure we don't have one already
	//
	if ( fakePlayer )
	{
		return;
	}
	
	fakePlayer_active = true;
	
	// if we are in the holster state, wait until next frame
	// if we aren't process immediately
	if ( !holster )
	{
		StartFakePlayer();
	}
	else
	{
		if ( WeaponsOut() )
		{
			SafeHolster( true );
		}
	}
}

void Player::RemoveFakePlayer( void )
{
	Actor * fake;
	
	//
	// make sure we have one
	//
	if ( !fakePlayer )
	{
		return;
	}
	fake = fakePlayer;
	
	//
	// warp the real player to the fakeplayer location
	//
	this->setOrigin( fake->origin );
	this->setAngles( fake->angles );
	this->SetViewAngles( fake->angles );
	// show the player
	this->showModel();
	this->ProcessEvent( EV_Sentient_TurnOnShadow );
	// allow the player to move
	this->flags &= ~FL_IMMOBILE;
	// make the player solid
	setSolidType( SOLID_BBOX );
	// remove the fake
	fake->PostEvent ( EV_Remove, 0.f );
	// null out the fake player
	fakePlayer = NULL;
	SafeHolster( false );
}

void Player::SetViewAngles( Vector newViewangles )
{
	// set the delta angle
	client->ps.delta_angles[0] = ANGLE2SHORT( newViewangles.x - client->cmd_angles[0] );
	client->ps.delta_angles[1] = ANGLE2SHORT( newViewangles.y - client->cmd_angles[1] );
	client->ps.delta_angles[2] = ANGLE2SHORT( newViewangles.z - client->cmd_angles[2] );
	
	v_angle = newViewangles;
	
	// get the pitch and roll from our leg angles
	newViewangles.x = angles.x;
	newViewangles.z = angles.z;
	AnglesToMat( newViewangles, orientation );
	yaw_forward = orientation[ 0 ];
	yaw_left = orientation[ 1 ];
	
	//MatrixTransformVector( base_righthand_pos, orientation, righthand_pos );
	//MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos );
	MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos );
	MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos );
	//righthand_pos += origin;
	//lefthand_pos += origin;
	rightfoot_pos += origin;
	leftfoot_pos += origin;
}

void Player::DumpState( Event *ev )
{
	gi.DPrintf( "Legs: %s Torso: %s\n", currentState_Legs ? currentState_Legs->getName() : "NULL", currentState_Torso->getName() );
}

void Player::ForceTorsoState( Event *ev )
{
	State *ts = statemap_Torso->FindState( ev->GetString( 1 ) );
	EvaluateState( ts );
}

void Player::TouchedUseAnim( Entity * ent )
{
	toucheduseanim = ent;
}

void Player::ClearTarget( Event *ev )
{
	targetEnemy = NULL;
}

void Player::AdjustTorso( Event *ev )
{
	adjust_torso = ev->GetBoolean( 1 );
}

void Player::UseDualWield( Event *ev )
{
	// This is triggered by the state machine.
	// If there is a weapon in the dual wield list, use it, then remove it from the list.
	if ( dual_wield_weaponlist.NumObjects() )
	{
		WeaponSetItem *dw;
		
		dw = dual_wield_weaponlist.ObjectAt( 1 );
		
		useWeapon( dw->name, dw->hand );
		dual_wield_weaponlist.RemoveObjectAt( 1 );
		delete dw;
	}
	else
	{
		dual_wield_active = false;  // We are done wielding all the weapons
	}
}

void Player::DualWield( Event *ev )
{
	str      leftweap, rightweap;
	Weapon   *leftactweap, *rightactweap, *dualactweap;
	
	leftweap  = ev->GetString( 1 );
	rightweap = ev->GetString( 2 );
	
	// Set the putaway flags on any active weapons
	leftactweap  = GetActiveWeapon( WEAPON_LEFT );
	rightactweap = GetActiveWeapon( WEAPON_RIGHT );
	dualactweap  = GetActiveWeapon( WEAPON_DUAL );
	
	// Check for any dual handed weapon being out, and mark it for putaway
	if ( dualactweap )
	{
		dualactweap->SetPutAway( true );
	}
	
	// if the left and right weapons are already out, then holster them both
	if (
        ( leftactweap && !leftweap.icmp( leftactweap->getName() ) ) &&
        ( rightactweap && !rightweap.icmp( rightactweap->getName() ) )
		)
	{
		leftactweap->SetPutAway( true );
		rightactweap->SetPutAway( true );
		return;
	}
	
	WeaponSetItem *dualweap;
	
	// Putaway the old weapons, and add the new ones to the dual_wield list
	if ( !leftactweap )
	{
		dualweap = new WeaponSetItem;
		dualweap->name = leftweap;
		dualweap->hand = WEAPON_LEFT;
		dual_wield_weaponlist.AddObject( dualweap );
	}
	else if ( leftweap.icmp( leftactweap->getName() ) )
	{
		leftactweap->SetPutAway( true );
		
		dualweap = new WeaponSetItem;
		dualweap->name = leftweap;
		dualweap->hand = WEAPON_LEFT;
		dual_wield_weaponlist.AddObject( dualweap );
	}
	
	if ( !rightactweap )
	{
		dualweap = new WeaponSetItem;
		dualweap->name = rightweap;
		dualweap->hand = WEAPON_RIGHT;
		dual_wield_weaponlist.AddObject( dualweap );
	}
	else if ( rightweap.icmp( rightactweap->getName() ) )
	{
		rightactweap->SetPutAway( true );
		
		dualweap = new WeaponSetItem;
		dualweap->name = rightweap;
		dualweap->hand = WEAPON_RIGHT;
		dual_wield_weaponlist.AddObject( dualweap );
	}
	
	dual_wield_active = true;
}

void Player::EvaluateTorsoAnim( Event *ev )
{
	str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) );
	if ( !animate->HasAnim(torsoAnim) )
		torsoAnim = getGameplayAnim(torsoAnim);
	
	if ( torsoAnim == "" )
	{
		partAnim[ torso ] = "";
		animate->ClearTorsoAnim();
	}
	else if ( torsoAnim != "none" )
	{
		SetAnim( torsoAnim.c_str(), torso );
	}
}

void Player::NextPainTime( Event *ev )
{
	nextpaintime = level.time + ev->GetFloat( 1 );
	pain_type    = MOD_NONE;
	pain         = 0;
}

void Player::SetMouthAngle( Event *ev )
{
	int tag_num;
	float angle_percent;
	Vector mouth_angles;
	
	
	angle_percent = ev->GetFloat( 1 );
	
	if ( angle_percent < 0.0f )
		angle_percent = 0.0f;
	
	if ( angle_percent > 1.0f )
		angle_percent = 1.0f;
	
	tag_num = gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" );
	
	if ( tag_num != -1 )
	{
		SetControllerTag( MOUTH_TAG, tag_num );
		
		mouth_angles = vec_zero;
		mouth_angles[PITCH] = max_mouth_angle * angle_percent;
		
		SetControllerAngles( MOUTH_TAG, mouth_angles );
	}
}

void Player::EnterVehicle( Event *ev )
{
	Entity *ent;
	
	ent = ev->GetEntity( 1 );
	if ( ent && ent->isSubclassOf( Vehicle ) )
	{
		flags |= FL_PARTIAL_IMMOBILE;
		viewheight = STAND_EYE_HEIGHT;
		velocity = vec_zero;
		vehicle = ( Vehicle * )ent;
		if ( vehicle->IsDrivable() )
			setMoveType( MOVETYPE_VEHICLE );
		else
			setMoveType( MOVETYPE_NOCLIP );
	}
}

void Player::ExitVehicle( Event *ev )
{
	flags &= ~FL_PARTIAL_IMMOBILE;
	setMoveType( MOVETYPE_WALK );
	vehicle = NULL;
}

qboolean Player::WeaponsOut( void )
{
	return ( GetActiveWeapon( WEAPON_LEFT ) || GetActiveWeapon( WEAPON_RIGHT ) || GetActiveWeapon( WEAPON_DUAL ) );
}

qboolean Player::IsDualWeaponActive( void )
{
	if(GetActiveWeapon( WEAPON_LEFT ) || GetActiveWeapon( WEAPON_RIGHT ))
	{
		return qfalse;
	}
	
	return qtrue;
}


void Player::Holster( qboolean putaway )
{
//	if(client->ps.pm_flags & PMF_DISABLE_INVENTORY)
//		return;

	Weapon   *leftWeap, *rightWeap, *dualWeap;
	
	leftWeap  = GetActiveWeapon( WEAPON_LEFT );
	rightWeap = GetActiveWeapon( WEAPON_RIGHT );
	dualWeap  = GetActiveWeapon( WEAPON_DUAL );
	
	// Holster
	if ( leftWeap || rightWeap || dualWeap )
	{
		if ( putaway )
		{
			if ( leftWeap )
            {
				leftWeap->SetPutAway( true );
				holsteredWeapons[WEAPON_LEFT] = leftWeap;
            }
			if ( rightWeap )
            {
				rightWeap->SetPutAway( true );
				holsteredWeapons[WEAPON_RIGHT] = rightWeap;
            }
			if ( dualWeap )
            {
				dualWeap->SetPutAway( true );
				holsteredWeapons[WEAPON_DUAL] = dualWeap;
            }
			
			// Set a level var so the script can know if the player is going to holster
			levelVars.SetVariable( "holster_active", 1 );
		}
	}
	else
	{
		if ( !putaway )
		{
			// Unholster
			if ( holsteredWeapons[WEAPON_DUAL] )
            {
				useWeapon( holsteredWeapons[WEAPON_DUAL], WEAPON_DUAL );
            }
			else if ( holsteredWeapons[WEAPON_LEFT] && holsteredWeapons[WEAPON_RIGHT] )
            {
				Event *ev1;
				
				ev1 = new Event( EV_Player_DualWield );
				ev1->AddString( holsteredWeapons[WEAPON_LEFT]->getName() );
				ev1->AddString( holsteredWeapons[WEAPON_RIGHT]->getName() );
				ProcessEvent( ev1 );
            }
			else if ( holsteredWeapons[WEAPON_RIGHT] )
            {
				useWeapon( holsteredWeapons[WEAPON_RIGHT], WEAPON_RIGHT );
            }
			else if ( holsteredWeapons[WEAPON_LEFT] )
            {
				useWeapon( holsteredWeapons[WEAPON_LEFT], WEAPON_LEFT );
            }
			
			holsteredWeapons[WEAPON_LEFT]  = NULL;
			holsteredWeapons[WEAPON_RIGHT] = NULL;
			holsteredWeapons[WEAPON_DUAL]  = NULL;
			// Set a level var to let the script know there is no holstering
			levelVars.SetVariable( "holster_active", 0 );
		}
	}
}

void Player::SafeHolster( qboolean putaway )
{
	if ( WeaponsOut() )
	{
		if ( putaway )
		{
			weapons_holstered_by_code = true;
			Holster( true );
		}
	}
	else
	{
		if ( putaway )
		{
			if ( !fakePlayer_active )
            {
				WeaponsHolstered();
            }
		}
		else
		{
			if ( weapons_holstered_by_code )
            {
				weapons_holstered_by_code = false;
				Holster( false );
            }
		}
	}
}

void Player::WeaponsNotHolstered( void )
{
}

void Player::WeaponsHolstered( void )
{
}

void Player::setTargeted( bool targeted )
{
	if ( targeted )
		{
		gi.SendServerCommand( entnum, "stufftext \"ui_addhud targetedhud\"\n");
		}
	else
		{
		gi.SendServerCommand( entnum, "stufftext \"ui_removehud targetedhud\"\n");
		}
}

void Player::NightvisionToggle( Event *ev )
{
	if ( level.cinematic )
		return;

	if ( ( multiplayerManager.isPlayerSpectator( this ) ) && ( client->ps.pm_flags ^ PMF_NIGHTVISION ) )
		return;

	client->ps.pm_flags ^= PMF_NIGHTVISION;

	Event *newEvent;
	newEvent = new Event( EV_Sentient_SetViewMode );
	if (client->ps.pm_flags & PMF_NIGHTVISION) 
		newEvent->AddString("nightvision");
	else
		newEvent->AddString("normal");
	ProcessEvent( newEvent );
}

void Player::HolsterToggle( Event *ev )
{
	if ( WeaponsOut() )
	{
		Holster( true );
	}
	else
	{
		Holster( false );
	}
}

void Player::Holster( Event *ev )
{

	SafeHolster( ev->GetBoolean( 1 ) );
}

void Player::IncreaseActionLevel( float action_level_increase )
{
	action_level += action_level_increase;
}

void Player::WatchEntity( Event *ev )
{
	if ( camera || ( currentState_Torso->getCameraType() != CAMERA_BEHIND ) )
		return;

	watchEntityForEntireDuration = false;

	if ( ev->NumArgs() > 1 )
	{
		Event *stopWatchingEvent = new Event( EV_Player_StopWatchingEntity );
		stopWatchingEvent->AddEntity( ev->GetEntity( 1 ) );
		const float timeToWatch = ev->GetFloat( 2 );
		PostEvent( stopWatchingEvent, timeToWatch );

		maximumAngleToWatchedEntity = ev->GetFloat( 3 );

		if ( ev->NumArgs() > 3 )
		{
			watchEntityForEntireDuration = ev->GetBoolean( 4 );
		}

	}

	entity_to_watch = ev->GetEntity( 1 );
}

void Player::StopWatchingEntity( Event *ev )
{
	StopWatchingEntity();
}

void Player::setAngles( const Vector &ang )
{
	Vector new_ang;
	
	new_ang = ang;
	
	// set the angles normally
	Entity::setAngles( new_ang );
	
	// set the orientation based off of the current view, also update our yaw_forward and yaw_left
	new_ang[ YAW ] = v_angle[ YAW ];
	AnglesToMat( new_ang, orientation );
	yaw_forward = orientation[ 0 ];
	yaw_left = orientation[ 1 ];
}

void Player::WeaponCommand( Event *ev )
{
	weaponhand_t   hand;
	Weapon         *weap;
	int            i;
	
	if ( ev->NumArgs() < 2 )
		return;
	
	hand = WeaponHandNameToNum( ev->GetString( 1 ) );
	weap = GetActiveWeapon( hand );
	
	if ( !weap )
		return;
	
	Event *e;
	e = new Event( ev->GetToken( 2 ) );
	
	for( i=3; i<=ev->NumArgs(); i++ )
		e->AddToken( ev->GetToken( i ) );
	
	weap->ProcessEvent( e );
}

qboolean TryPush( int entnum, vec3_t move_origin, vec3_t move_end )
{
	Actor *act;
	Vector dir;
	Vector dir2;
	Entity *ent;
	
	if ( entnum == ENTITYNUM_NONE )
		return false;
	
	ent = G_GetEntity( entnum );
	
	if ( ent->isSubclassOf( Actor ) )
	{
		act = (Actor *) ent;
		
		dir = act->origin - move_origin;
		dir.z = 0.0f;
		dir.normalize();
		
		dir2 = move_end;
		dir2 -= move_origin;
		
		if ( act->flags & FL_FLY )
		{
			dir *= dir2.length() / 2.0f;
			
			if ( act->movementSubsystem->Push( dir ) )
				return true;
		}
		else
		{
			dir *= dir2.length();
			
			Event *event = new Event( EV_Actor_Push );
			event->AddVector( dir );
			act->PostEvent( event, 0.0f );
		}
	}
	
	return false;
}

void Player::PlayerDone( Event *ev )
{
	// This is used to let scripts know that the player is done doing something
	
	// let any threads waiting on us know they can go ahead
	Director.PlayerSpawned();
}

painDirection_t Player::Pain_string_to_int( const str &pain )
{
	if ( !pain.icmp( pain, "Front" ) )
		return PAIN_FRONT;
	else if ( !pain.icmp( pain, "Left" ) )
		return PAIN_LEFT;
	else if ( !pain.icmp( pain, "Right" ) )
		return PAIN_RIGHT;
	else if ( !pain.icmp( pain, "Rear" ) )
		return PAIN_REAR;
	else
		return PAIN_NONE;
}

void Player::ArchivePersistantData( Archiver &arc, qboolean sublevelTransition )
{
	int i;
	str model_name;
	bool anglesArchived;
	
	Sentient::ArchivePersistantData( arc, sublevelTransition );
	
	model_name = g_playermodel->string;
	
	arc.ArchiveString( &model_name );
	
	if ( arc.Loading() )
	{
		// set the cvar
		gi.cvar_set( "g_playermodel", model_name.c_str() );
		
		model_name += ".tik";
		setModel( model_name.c_str() );
	}
	
	for( i = 0; i < MAX_ACTIVE_WEAPONS; i++ )
	{
		str name;
		if ( arc.Saving() )
		{
			if ( holsteredWeapons[ i ] )
            {
				name = holsteredWeapons[ i ]->getName();
            }
			else
            {
				name = "none";
            }
		}
		arc.ArchiveString( &name );
		if ( arc.Loading() )
		{
			if ( name != "none" )
            {
				holsteredWeapons[ i ] = ( Weapon * )FindItem( name );
            }
		}
	}
	
	if ( arc.Saving() )
	{
		if ( sublevelTransition && level._saveOrientation )
		{
			anglesArchived = true;
			arc.ArchiveBool( &anglesArchived );
			arc.ArchiveVector( &angles );
			arc.ArchiveVector( &v_angle );
		}
		else
		{
			anglesArchived = false;
			arc.ArchiveBool( &anglesArchived );
		}
	}
	else
	{
		arc.ArchiveBool( &anglesArchived );
		
		if ( anglesArchived )
		{
			arc.ArchiveVector( &angles );
			arc.ArchiveVector( &v_angle );
			
			setAngles( angles );
			SetViewAngles( v_angle );
		}
	}
	
	
	// Force a re-evaluation of the player's state
	LoadStateTable();
	
	arc.ArchiveInteger(&_totalGameFrames);
	_updateGameFrames = true;

	arc.ArchiveInteger( &_secretsFound );

	arc.ArchiveInteger( &_skillLevel );

	arc.ArchiveRaw( client->ps.stats, sizeof( client->ps.stats ) );
}

const str Player::getPainShader( meansOfDeath_t mod, bool takeArmorIntoAccount )
{
	if ( ( takeArmorIntoAccount ) && ( GetArmorValue() >= 100 ) )
		return "ArmorDeflection";
	else
		return getPainShader( MOD_NumToName( mod )  );
}

const str Player::getPainShader( const char *MODName )
{
	GameplayManager *gpm;
	str modName;
	const char *defaultName = "default";

	gpm = GameplayManager::getTheGameplayManager();

	if ( !gpm )
		return str("");

	modName = "MOD";
	modName += MODName;

	if ( !gpm->hasObject( modName ) )
	{
		if ( stricmp( MODName, defaultName ) == 0 )
			return "";
		else
			return getPainShader( defaultName );
	}

	return gpm->getStringValue( modName, "PainShaderName" );

	/* switch ( mod )
	{
	case MOD_NONE:
		return "none";
		break;
	default:
		return "electriclines";
		break;
	} */
}

void Player::SpawnDamageEffect( meansOfDeath_t mod )
{
	/* switch ( mod )
	{
	case MOD_ELECTRIC:
		// lint -fallthrough
	case MOD_ELECTRICWATER:
		//SpawnEffect( "fx_elecstrike.tik", origin );
		//Sound( "sound/weapons/sword/electric/hitmix2.wav", 0 );
		
		break;
		
	default:
		break;
	} */

	if ( multiplayerManager.inMultiplayer() )
	{
		if ( ( mod != MOD_NONE ) && ( mod != MOD_DEATH_QUAD ) && ( _nextPainShaderTime < level.time ) && !hasCustomShader() )
		{
			str painShader = getPainShader( mod, true );

			if ( painShader.length() > 0 )
			{
				setCustomShader( painShader );

				_lastPainShaderMod  = mod;
				_nextPainShaderTime = level.time + 0.25f;
			}
		}
	}
}

void Player::ActivateDualWeapons( Event *ev )
{
	int i;
	
	Weapon *weapon = 0;
	for ( i=dual_wield_weaponlist.NumObjects(); i>=1; i-- )
	{
		WeaponSetItem   *dw;
		
		dw = dual_wield_weaponlist.ObjectAt( i );
		
		weapon = ( Weapon * )FindItem( dw->name, weapon );
		
		// Check to see if player has the weapon
		if ( !weapon )
		{
			warning( "Player::ActivateDualWeapons", "Player does not have weapon %s", dw->name.c_str() );
			return;
		}
		
		ChangeWeapon( weapon, dw->hand );
		dual_wield_weaponlist.RemoveObjectAt( i );
		delete dw;
	}
	
	// Clear out the newActiveWeapon
	ClearNewActiveWeapon();
	
	// Clear out the holstered weapons
	holsteredWeapons[WEAPON_LEFT]  = NULL;
	holsteredWeapons[WEAPON_RIGHT] = NULL;
	holsteredWeapons[WEAPON_DUAL]  = NULL;
	
	// let the player know that our weapons are not holstered
	WeaponsNotHolstered();
}

void Player::VelocityModified( void )
{
	if ( velocity.z > 32.0f )
	{
		do_rise = true;
	}
}

int Player::GetKnockback( int original_knockback, qboolean blocked )
{
	int new_knockback;
	
	new_knockback = original_knockback;
	
	// If blocked, absorb some of the knockback
	
	if ( blocked )
	{
		if ( LargeShieldActive() )
			new_knockback -= 150;
		else
			new_knockback -= 50;
	}
	
	// See if we still have enough knockback to knock the player down
	
	if ( ( new_knockback >= 200.0f ) && take_pain )
	{
		knockdown = true;
		
		if ( blocked )
		{
			float damage;
			
			damage = new_knockback / 50;
			
			if ( damage > 10.0f )
				damage = 10.0f;
			
			Damage( world, world, damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_CRUSH );
		}
	}
	
	// Make sure knockback is still at least 0
	
	if ( new_knockback < 0 )
		new_knockback = 0;
	
	return new_knockback;
}

void Player::ResetHaveItem( Event *ev )
{
	str fullname;
	ScriptVariable * var;
	
	fullname = str( "playeritem_" ) + ev->GetString( 1 );
	
	var = gameVars.GetVariable( fullname.c_str() );
	
	if ( var )
		var->setIntValue( 0 );
}

void Player::ReceivedItem( Item * item )
{
	qboolean forced;
	qboolean first;
	str fullname;
	str dialog;
	str anim;
	ScriptVariable * var;
	
	//
	// set our global game variables
	//
	
	if ( item->isSubclassOf( Weapon ) )
	{
		setItemText( item->getIcon(), va( "$$PickedUpThe$$ $$Weapon-%s$$\n", item->getName().c_str() ) );
		//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUpThe$$ $$%s$$\n", item->getName() );
	}
	else if ( item->getAmount() > 1 )
	{
		if ( item->getName() == "health" )  // I know this is horrible :(
			setItemText( item->getIcon(), va( "$$PickedUp$$ %d $$Item-%s$$\n", (int)item->getAmount(), item->getName().c_str() ) );
			//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUp$$ %d %s\n", (int)item->getAmount(), item->getName() );
		else
			setItemText( item->getIcon(), va( "$$PickedUp$$ %d $$Item-%s$$s\n", (int)item->getAmount(), item->getName().c_str() ) );
			//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUp$$ %d %ss\n", (int)item->getAmount(), item->getName() );
	}
	else
	{
		setItemText( item->getIcon(), va( "$$PickedUpThe$$ $$Item-%s$$\n", item->getName().c_str() ) );
		//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$PickedUpThe$$ %s\n", item->getName() );
	}
	
	fullname = str( "playeritem_" ) + item->getName();
	
	first = true;
	
	var = gameVars.GetVariable( fullname.c_str() );
	if ( !var )
	{
		gameVars.SetVariable( fullname.c_str(), 1 );
	}
	else
	{
		int amount;
		
		amount = var->intValue() + 1;
		var->setIntValue( amount );
		//
		// if we just received it, let the player know
		//
		if ( amount > 1 )
		{
			first = false;
		}
	}
	
	var = levelVars.GetVariable( fullname.c_str() );
	if ( !var )
	{
		levelVars.SetVariable( fullname.c_str(), 1 );
	}
	else
	{
		int amount;
		
		amount = var->intValue() + 1;
		var->setIntValue( amount );
	}
	
	if ( item->IsItemCool( &dialog, &anim, &forced ) )
	{
		if ( first || forced )
		{
			cool_item = item;
			cool_dialog = dialog;
			cool_anim = anim;
		}
	}
}

void Player::RemovedItem( Item * item )
{
	str fullname;
	ScriptVariable * var;
	
	//
	// set our global game variables if client
	//
	
	fullname = str( "playeritem_" ) + item->getName();
	
	var = levelVars.GetVariable( fullname.c_str() );
	if ( var )
	{
		int amount;
		
		amount = var->intValue() - 1;
		if ( amount < 0 )
			amount = 0;
		var->setIntValue( amount );
	}
	
	var = gameVars.GetVariable( fullname.c_str() );
	if ( var )
	{
		int amount;
		
		amount = var->intValue() - 1;
		if ( amount < 0 )
			amount = 0;
		var->setIntValue( amount );
	}
}

void Player::AmmoAmountChanged( Ammo * ammo, int ammo_in_clip )
{
	str fullname;
	ScriptVariable * var;
	
	//
	// set our level variables
	//
	fullname = str( "playerammo_" ) + ammo->getName();
	
	var = levelVars.GetVariable( fullname.c_str() );
	if ( !var )
	{
		levelVars.SetVariable( fullname.c_str(), ammo->getAmount() + ammo_in_clip );
	}
	else
	{
		var->setIntValue( ammo->getAmount() + ammo_in_clip );
	}
}

void Player::StartCoolItem( Event *ev )
{
	// turn off ai off during the cinematic
	level.ai_on = false;
	// make sure we don't take damage during this time
	takedamage = DAMAGE_NO;
	// freeze the player
	level.playerfrozen = true;
	// turn on cinematic mode
	G_StartCinematic();
	
	assert( ( Camera * )cool_camera == NULL );
	// start playing the success music
	if ( music_current_mood != mood_success )
	{
		ChangeMusic( "success", MusicMood_NumToName( music_current_mood ), false );
	}
	
	// create an orbit cam
	cool_camera = new Camera();
	cool_camera->SetOrbitHeight( 150.0f );
	cool_camera->Orbit( this, 200.0f, this, -90.0f );
	cool_camera->Cut( NULL );
	SetCamera( cool_camera, 1.0f );
}

void Player::ShowCoolItem( Event *ev )
{
	Entity *fx;
	Vector org;
	
	org = origin;
	org.z += 128.0f;
	
	fx = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
	
	fx->setOrigin( org );
	fx->setModel( "fx_coolitem.tik" );
	fx->animate->RandomAnimate( "idle" );
	fx->PostEvent( EV_Remove, 1.0f );
	
	if ( cool_item )
	{
		cool_item->setOrigin( org );
		cool_item->PostEvent( EV_Show, 0.1f );
		// place a lens flare on the object
		cool_item->edict->s.renderfx |= RF_VIEWLENSFLARE;
		
		if ( cool_dialog.length() )
		{
			Sound( cool_dialog, CHAN_DIALOG );
		}
	}
}

void Player::HideCoolItem( Event *ev )
{
	Entity *fx;
	Vector org;
	
	org = origin;
	org.z += 128.0f;
	
	fx = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
	
	fx->setOrigin( org );
	fx->setModel( "fx_coolitem_reverse.tik" );
	fx->animate->RandomAnimate( "idle" );
	fx->PostEvent( EV_Remove, 1.0f );
	
	if ( cool_item )
	{
		Event * event;
		
		cool_item->PostEvent( EV_Hide, 1.0f );
		
		event = new Event( EV_SetOrigin );
		event->AddVector( vec_zero );
		cool_item->PostEvent( event, 1.0f );
		// remove the lens flare on the object
		cool_item->edict->s.renderfx &= ~RF_VIEWLENSFLARE;
	}
}

void Player::StartCoolItemAnim( void )
{
	movecontrol = MOVECONTROL_ABSOLUTE;
	
	if ( cool_item && cool_anim.length() )
	{
		SetAnim( cool_anim, legs );
		// clear out anim till next time
		cool_anim = "";
	}
}

void Player::StopCoolItem( Event *ev )
{
	if ( cool_item && cool_anim.length() )
	{
		State * newState;
		
		newState = statemap_Torso->FindState( "DO_COOL_ITEM_ANIM" );
		if ( newState )
		{
			currentState_Torso = newState;
			return;
		}
	}
	
	// turn ai back on
	level.ai_on = true;
	
	// turn damage back on
	takedamage = DAMAGE_AIM;
	
	// unfreeze the player
	level.playerfrozen = false;
	
	// turn off cinematic mode
	G_StopCinematic();
	
	cool_item = NULL;
	
	// delete our camera
	if ( cool_camera )
	{
		SetCamera( NULL, 1.0f );
		delete cool_camera;
		cool_camera = NULL;
	}
}

void Player::WaitForState( Event *ev )
{
	waitForState = ev->GetString( 1 );
}


void Player::SetDamageMultiplier( Event *ev )
{
	damage_multiplier = ev->GetFloat( 1 );
}

void Player::SetTakePain( Event *ev )
{
	take_pain = ev->GetBoolean( 1 );
}

void Player::Loaded( void )
{
}

void Player::PlayerShowModel( Event *ev )
{
	Entity::showModel();
}

void Player::showModel( void )
{
	Entity::showModel();
}

void Player::WarpToPoint( const Entity *spawnpoint )
{
	if ( !spawnpoint )
		return;
	
	NoLerpThisFrame();
	setOrigin( spawnpoint->origin + Vector( "0 0 1" ) );
	origin.copyTo( edict->s.origin2 );
	setAngles( spawnpoint->angles );
	SetViewAngles( angles );
	CameraCut();

	oldvelocity = vec_zero;
	velocity    = vec_zero;
}

void Player::Gib( void )
{
	/* str gib_name;
	int number_of_gibs;
	float scale;
	Entity *ent;
	str real_gib_name;
	
	if ( !com_blood->integer )
		return;
	
	gib_name       = "fx_rgib";
	number_of_gibs = 5;
	scale          = 1.3;
	
	// Spawn the gibs
	real_gib_name = gib_name;
	real_gib_name += number_of_gibs;
	real_gib_name += ".tik";
	
	ent = new Entity( ENTITY_CREATE_FLAG_ANIMATE );
	ent->setModel( real_gib_name.c_str() );
	ent->setScale( scale );
	ent->setOrigin( centroid );
	ent->animate->RandomAnimate( "idle" );
	ent->PostEvent( EV_Remove, 1.0f );
	
	this->hideModel();
	Sound( "snd_decap", CHAN_BODY, 1.0f, 300.0f );
	gibbed = true; */
}

void Player::ArmorDamage( Event *ev )
{
	float oldHealth;

	::Damage damage(ev);
	
	// Protect the player from errant damage before fighting
	if ( multiplayerManager.inMultiplayer() && !multiplayerManager.isFightingAllowed() )
		return;

	if ( multiplayerManager.inMultiplayer() && multiplayerManager.isPlayerSpectator( this ) )
		return;
	
	// Quick dirty hack to do no damage when you have the shield up.
	if ( shield_active )
	{
		// Code to be implemented soon.
		Weapon *weapon = GetActiveWeapon(WEAPON_RIGHT);
		if ( !weapon )
			return;
		
		Vector attack_angle;
		float yaw_diff;
		attack_angle = damage.attacker->angles;
		yaw_diff = angles[YAW] - attack_angle[YAW] + 180.0f;
		yaw_diff = AngleNormalize180( yaw_diff );
		if ( ( yaw_diff > -45.0f ) && ( yaw_diff < 45.0f ) )
		{
			int tagnum = 0;
			tagnum = gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe1" );
			if ( tagnum >= 0)
			{
				Vector pos, pos2, sparkpos;
				weapon->GetActorMuzzlePosition(&pos, NULL, NULL, NULL, "tag_swipe1");
				weapon->GetActorMuzzlePosition(&pos2, NULL, NULL, NULL, "tag_swipe2");
				sparkpos = (pos + pos2) / 2.0f; // Spark is halfway between the two points
				WeaponEffectsAndSound( weapon, "Parry", sparkpos );
			}
			
			if ( damage.attacker->isSubclassOf( Sentient ) )
			{
				Sentient *sent = ( Sentient * )damage.attacker;
				sent->SetAttackBlocked( true );
			}
			
			//attack_blocked = true;
			return;
		}
	}
	
	if ( _powerup )
		damage.damage = _powerup->getDamageTaken( damage.attacker, damage.damage, damage.meansofdeath );
	
	if ( _rune )
		damage.damage = _rune->getDamageTaken( damage.attacker, damage.damage, damage.meansofdeath );
	
	if ( multiplayerManager.inMultiplayer() && damage.attacker->isSubclassOf( Player ) )
	{
		damage.damage = multiplayerManager.playerDamaged( this, (Player *)damage.attacker, damage.damage, damage.meansofdeath );
		
		damage.knockback = (int)multiplayerManager.getModifiedKnockback( this, (Player *)damage.attacker, damage.knockback );
	}
	
	if ( !multiplayerManager.inMultiplayer() && ( damage.meansofdeath != MOD_FALLING ) )
	{
		GameplayManager *gpm;
		float damageMultiplier;
		int skillLevel;
		
		skillLevel = getSkill();

		gpm = GameplayManager::getTheGameplayManager();
		
		if ( gpm->hasObject( "SkillLevel-PlayerDamage" ) )
		{
			if ( skillLevel == 0 )
				damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Easy" );
			else if ( skillLevel == 1 )
				damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Normal" );
			else if ( skillLevel == 2 )
				damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "Hard" );
			else
				damageMultiplier = gpm->getFloatValue( "SkillLevel-PlayerDamage", "VeryHard" );
			
			
			damage.damage *= damageMultiplier;
		}
	}

	oldHealth = health;
	
	Sentient::ArmorDamage(damage);

	if ( multiplayerManager.inMultiplayer() )
	{
		float damageTaken;

		damageTaken = oldHealth - health;

		if ( damageTaken > 0.0f )
		{
			// Increase victim's action level

			if ( damage.meansofdeath > MOD_LAST_SELF_INFLICTED )
			{
				IncreaseActionLevel( damageTaken );
			}

			if ( damage.attacker->isSubclassOf( Player ) )
			{
				Player *attackingPlayer = (Player *)damage.attacker;

				// Tell the multiplayer system that the player took damage

				multiplayerManager.playerTookDamage( this, attackingPlayer, damageTaken, damage.meansofdeath );

				// Increase attacker's action level

				if ( attackingPlayer != this )
				{
					attackingPlayer->IncreaseActionLevel( damageTaken );
				}
			}
		}
	}
	
	// If we're dead, go ahead and gib completely on Projectiles
	if ( ( multiplayerManager.inMultiplayer() ) && ( health <= 0.0f ) && damage.inflictor->isSubclassOf( Projectile ) )
	{
		Gib();
	}
}

void Player::DeadBody( Event *ev )
{
	// Spawn a dead body at the spot
	Body *body;
	int surfaceNum;
	
	if ( ( pain_type == MOD_VAPORIZE ) || ( pain_type == MOD_VAPORIZE_COMP ) || 
		( pain_type == MOD_VAPORIZE_DISRUPTOR ) || ( pain_type == MOD_VAPORIZE_PHOTON ) || ( pain_type == MOD_SNIPER ))
		return;
	
	body = new Body;
	
	if ( gibbed )
		return;
	
	body->setModel( this->model );
	body->ProcessInitCommands( body->edict->s.modelindex );
	body->edict->s.anim        = this->edict->s.anim;
	body->edict->s.frame       = this->edict->s.frame;
	
	//body->edict->s.torso_anim  = this->edict->s.anim;
	//body->edict->s.torso_frame = this->edict->s.frame;
	
	body->edict->s.torso_anim  = this->edict->s.torso_anim;
	body->edict->s.torso_frame = this->edict->s.torso_frame;
	body->edict->s.scale       = this->edict->s.scale;
	
	body->setOrigin( this->origin );
	body->setAngles( this->angles );

	// Copy over all of the surface data from the player to the body

	for( surfaceNum = 0 ; surfaceNum < numsurfaces ; surfaceNum++ )
	{
		body->edict->s.surfaces[ surfaceNum ] = edict->s.surfaces[ surfaceNum ];
	}
}

void Player::ShowHeuristics( Event *ev )
{
	
	if ( p_heuristics )
		p_heuristics->ShowHeuristics( this );
}

void Player::FireWeapon( Event *ev )
{	
	Sentient::FireWeapon(ev);
}

void Player::ReleaseFireWeapon( Event *ev )
{
	Sentient::ReleaseFireWeapon(ev);
}

void Player::SetAimType( Event *ev )
{
	Weapon* weapon = 0;
	weapon = GetActiveWeapon( WEAPON_DUAL );
	if (!weapon )
		return;
	
	// Forward the event to the weapon itself
	weapon->SetAimType( ev );
}

void Player::ReloadWeapon( Event *ev )
{
	Weapon* weapon = 0;
	weapon = GetActiveWeapon( WEAPON_DUAL );
	if (!weapon )
		return;
	
	// Reload
	weapon->ForceReload();
}

void Player::AnimateWeapon( Event *ev )
{
	Weapon* weapon = 0;
	weaponhand_t hand = WEAPON_DUAL;
	bool animatingFlag = true;
	
	if ( ev->NumArgs() > 1 )
		hand = WeaponHandNameToNum(ev->GetString( 2 ));
	
	if ( ev->NumArgs() > 2 )
		animatingFlag = ev->GetBoolean( 3 );
	
	weapon = GetActiveWeapon( hand );
	if ( !weapon )
		return;
	
	weapon->playAnim( ev->GetString( 1 ), animatingFlag );
}

void Player::SwitchWeaponMode( Event *ev )
{
	Weapon* weapon = 0;
	weapon = GetActiveWeapon( WEAPON_DUAL );
	if (!weapon )
		return;
	
	// Switch Modes
	weapon->SwitchMode();
}

qboolean Player::GetCrouch( void )
{
	if ( last_ucmd.upmove < 0 ) // check for downward movement
		return true;
	return false;
}
	
void Player::ReloadTiki( Event *ev )
{
	if ( ev->NumArgs() < 1 )
		return;
	
	int frame, anim, animstate;
	Viewthing *viewthing;
	
	viewthing = ( Viewthing * )( ( Entity * )Viewmodel.current_viewthing );
	if ( !viewthing )
		return;
	
	// Save off info about the current viewspawn
	frame = viewthing->frame;
	anim = viewthing->CurrentAnim();
	Vector vieworigin(viewthing->origin.x, viewthing->origin.y, viewthing->origin.z);
	Vector viewangles(viewthing->angles.x, viewthing->angles.y, viewthing->angles.z);
	
	// We're actually going to call ToggleAnimationState, so we
	// set the animstate here one less than the real state
	animstate = viewthing->animstate-1;
	if ( animstate < 0 ) 
		animstate = -1;
	
	// Process the event that deletes the old viewmodel and spawns the new one
	Event *ev2 = new Event(EV_ViewThing_SpawnFromTS);
	ev2->AddString(ev->GetString(1));
	ev2->AddString(viewthing->model);
	Viewmodel.ProcessEvent(ev2);
	
	// Re-get the new viewthing pointer
	viewthing = ( Viewthing * )( ( Entity * )Viewmodel.current_viewthing );
	
	// Update all its info to be the same to the one we deleted
	ev2 = new Event;
	ev2->AddFloat(vieworigin.x);
	ev2->AddFloat(vieworigin.y);
	ev2->AddFloat(vieworigin.z);		
	viewthing->ChangeOrigin(ev2);
	if ( ev2 ) delete ev2;
	
	ev2 = new Event;
	ev2->AddFloat(viewangles.x);
	ev2->AddFloat(viewangles.y);
	ev2->AddFloat(viewangles.z);		
	viewthing->SetAnglesEvent(ev2);
	
	viewthing->frame = frame;
	viewthing->SetAnim(anim);
	viewthing->animstate = animstate;
	if ( ev2 ) delete ev2;
	ev2 = new Event;
	viewthing->ToggleAnimateEvent(ev2);
}

void Player::SetViewAnglesEvent( Event *ev )
{
	if ( ev->NumArgs() > 0 )
		SetViewAngles(ev->GetVector(1));
}

void Player::ProjDetonate(Event *ev)
{
	if ( ev->NumArgs() > 0 )
		projdetonate = ev->GetBoolean(1);
}

void Player::SetProjDetonate(qboolean value)
{
	projdetonate = value;
}

qboolean Player::GetProjDetonate()
{
	Weapon *weapon;

	if ( projdetonate )
		return true;

	weapon = GetActiveWeapon( WEAPON_DUAL );

	if ( !weapon )
		return false;

	if ( ( weapon->GetFireType( FIRE_MODE1 ) == FT_TRIGGER_PROJECTILE ) && ( isButtonDown( BUTTON_ATTACKLEFT ) ) )
		return true;

	if ( ( weapon->GetFireType( FIRE_MODE2 ) == FT_TRIGGER_PROJECTILE ) && ( isButtonDown( BUTTON_ATTACKRIGHT ) ) )
		return true;

	return false;
}

void Player::PassEventToVehicle( Event *ev )
{
	if ( vehicle )
		vehicle->HandleEvent( ev );
}

void Player::UseSpecifiedEntity( Event *ev )
{
	Event  *event = NULL;
	Entity *ent = NULL;
	
	// Event with a param is old functionality
	if ( ev->NumArgs() > 0 )
	{
		ent = ev->GetEntity( 1 );
		if ( ent == 0 )
		{
			Com_Error ( ERR_DROP , "UseSpecifiedEntity(): NULL entity referenced\n" );
			return;
		}

		event = new Event( EV_Use );
		event->AddEntity( this );
		ent->ProcessEvent( event );
		return;
	}
	else // No params, new functionality
	{
		if ( !atobject )
			return;
		ent = (Entity *)atobject;
		if ( !ent->hasUseData() )
			return;
		
		ent->useData->useMe();
		
		if ( ent->useData->getUseAnim().length() > 0 && animate->HasAnim(ent->useData->getUseAnim()) )
		{
			// We are assuming we have a valid anim that
			// will manually trigger the use on a specific frame
			// using the "douseentity" call	
			
			SetAnim( ent->useData->getUseAnim(), legs );
			movecontrol = MOVECONTROL_ABSOLUTE;
			_usingEntity = true;
			_useEntityStartTimer = level.time + 2.5f;
		}
		else
		{
			// No animation, just call the thread and notify the entity
			// he's been used.
			if ( ent->useData->getUseThread().length() > 0 )
				ExecuteThread(ent->useData->getUseThread().c_str(), true, ent);
			
			_usingEntity = false; // No anim, so we can just leave the state immediately.
			
			// If it's an item, we're going to pick it up, so no need to call
			// it's use event.  Check the gameplay manager to make sure this item
			// cannot be auto-picked up.
			GameplayManager *gpm = GameplayManager::getTheGameplayManager();
			if ( ent->isSubclassOf(Item) && gpm->hasProperty(ent->getArchetype(), "noautopickup"))
			{
				Item *item = (Item *)ent;
				handlePickupItem(item);
				return;
			}
			
			event = new Event( EV_Use );
			event->AddEntity( this );
			ent->ProcessEvent( event );
		}
	}
}

//--------------------------------------------------------------
//
// Name:			handlePickupItem
// Class:			Player
//
// Description:		Called when the user has clicked on a useentity that
//					happens to be an item. The default behavior of this
//					action is to put the item in the inventory and remove
//					it from the world.
//
// Parameters:		Item *item -- The item to pick up
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::handlePickupItem( Item *item )
{
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str type = item->getArchetype();
	str invslot = gpm->getStringValue(type, "invslot");
	if ( invslot.length() )
	{
		float quantity = gpm->getFloatValue(invslot, "quantity");
		quantity += 1.0f;
		gpm->setFloatValue(invslot, "quantity", quantity);
		gpm->setStringValue(invslot, "name", type);
	}
	else
	{
		str slotName = getFreeInventorySlot();
		if ( !slotName.length() )
			return;
		
		gpm->setStringValue(slotName, "name", type);
	}
	
	str snd = gpm->getStringValue(type + ".Pickup", "wav");
	if ( snd.length() )
	{
		int channel = CHAN_BODY;
		float volume = -1.0f;
		float mindist = -1.0f;
		if ( gpm->hasProperty(type + ".Pickup","channel") )
			channel = (int)gpm->getFloatValue(type + ".Pickup", "channel");
		if ( gpm->hasProperty(getArchetype() + ".Pickup","volume") )
			volume = (int)gpm->getFloatValue(getArchetype() + ".Pickup", "volume");
		if ( gpm->hasProperty(getArchetype() + ".Pickup","mindist") )
			mindist = (int)gpm->getFloatValue(getArchetype() + ".Pickup", "mindist");
		item->Sound(snd, channel, volume, mindist);
	}
	
	// Remove the item from the world
	item->ProcessEvent(EV_Remove);
}

//--------------------------------------------------------------
//
// Name:			doUseEntity
// Class:			Player
//
// Description:		Called from the tiki to do the actual useentity
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::doUseEntity( Event *ev )
{
	Entity *ent = NULL;
	Event *event = NULL;
	
	if ( !atobject )
		return;
	
	ent = (Entity *)atobject;
	if ( !ent->hasUseData() )
		return;
	
	if ( ent->useData->getUseThread().length() > 0 )
		ExecuteThread(ent->useData->getUseThread().c_str(), true, ent);
	
	// If it's an item, we're going to pick it up, so no need to call
	// it's use event.  Check the gameplay manager to make sure this item
	// cannot be auto-picked up.
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	if ( ent->isSubclassOf(Item) && gpm->hasProperty(ent->getArchetype(), "noautopickup"))
	{
		Item *item = (Item *)ent;
		handlePickupItem(item);
		return;
	}
	
	event = new Event( EV_Use );
	event->AddEntity( this );
	ent->ProcessEvent( event );
}

//--------------------------------------------------------------
//
// Name:			doneUseEntity
// Class:			Player
//
// Description:		Called when the useentity animation is done
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::doneUseEntity( Event *ev )
{
	_usingEntity = false;
	level.playerfrozen = false;
	_useEntityStartTimer = 0.0f;
	SetState("STAND", "STAND");
}

void Player::SetupDialog( Event *ev )
{
	Entity *entity;
	str soundName;
	
	entity = ev->GetEntity( 1 );
	soundName = ev->GetString( 2 );
	
	SetupDialog( entity, soundName );
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::SetupDialog( Entity *entity, const str &soundName )
{
	if( gi.SoundLength( soundName.c_str() ) <= 0 )
		return;
	
	//If we have an entity, then we are dealing with Dialog events.
	if ( entity )
	{
		handleDialogSetup(entity, soundName);
	}
	else
	{
		handleTextDialogSetup( soundName );
	}
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::handleDialogSetup( Entity* entity, const str& soundName )
{
	// Set the correct info and post the clear event when done
	// Make sure all current clears are canceled
	CancelEventsOfType( EV_Player_ClearDialog );
	
	// Make sure current stuff is cleared properly
	
	ClearDialog();

	if ( gi.SoundLength( soundName.c_str() ) >= 0 )
	{
		_dialogEntnum = entity->entnum;
		_dialogSoundIndex = gi.soundindex( soundName.c_str() );

		PostEvent( EV_Player_ClearDialog, gi.SoundLength( soundName.c_str() ) );
	}
	else
	{
		ProcessEvent( EV_Player_ClearDialog );
	}
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::handleTextDialogSetup( const str& soundName )
{
	// Set the correct info and post the clear event when done
	// Make sure all current clears are canceled
	CancelEventsOfType( EV_Player_ClearTextDialog );
	
	// Make sure current stuff is cleared properly
	ClearTextDialog();
	
	if ( gi.SoundLength( soundName.c_str() ) >= 0 )
	{
		_dialogTextSoundIndex = gi.soundindex( soundName.c_str() );
		PostEvent( EV_Player_ClearTextDialog, gi.SoundLength( soundName.c_str() ) );
	}
	else
	{
		ProcessEvent( EV_Player_ClearTextDialog );
	}
}


void Player::ClearDialog( Event *ev )
{
	ClearDialog();
}

void Player::ClearDialog( void )
{
	// Clear the dialog info
	_dialogEntnum = ENTITYNUM_NONE;
	_dialogSoundIndex = -1;
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::ClearTextDialog( Event* ev )
{
	ClearTextDialog();
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::ClearTextDialog( void )
{
	_dialogTextSoundIndex = -1;
}


//
// Objective Functions
//
void Player::SetObjectiveComplete( Event* ev )
{
	int ObjIndex;
	str ObjName;
	qboolean Complete;
	
	ObjName = ev->GetString( 1 );
	Complete = ev->GetBoolean( 2 );
	
	ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );   
	if ( ObjIndex == 0 )
		return;
	
	switch ( ObjIndex )
	{
	case OBJECTIVE1:
		if ( Complete )
            _objectiveStates |= OBJECTIVE1_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE1_COMPLETE);
		break;
		
	case OBJECTIVE2:
		if ( Complete )
            _objectiveStates |= OBJECTIVE2_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE2_COMPLETE);
		break;
		
	case OBJECTIVE3:
		if ( Complete )
            _objectiveStates |= OBJECTIVE3_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE3_COMPLETE);
		
		break;
		
	case OBJECTIVE4:
		if ( Complete )
            _objectiveStates |= OBJECTIVE4_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE4_COMPLETE);
		
		break;
		
	case OBJECTIVE5:
		if ( Complete )
            _objectiveStates |= OBJECTIVE5_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE5_COMPLETE);
		
		break;
		
	case OBJECTIVE6:
		if ( Complete )
            _objectiveStates |= OBJECTIVE6_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE6_COMPLETE);
		
		break;
		
	case OBJECTIVE7:
		if ( Complete )
            _objectiveStates |= OBJECTIVE7_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE7_COMPLETE);
		
		break;
		
	case OBJECTIVE8:
		if ( Complete )
            _objectiveStates |= OBJECTIVE8_COMPLETE;
		else
            _objectiveStates &= ~(OBJECTIVE8_COMPLETE);
		
		break;
		
	default:
		break;
	}
	
	
	//   gi.MObjective_SetObjectiveComplete( ObjName.c_str() , Complete );         
}



void Player::SetObjectiveFailed( Event *ev )
{
	int ObjIndex;
	str ObjName;
	qboolean Failed;
	
	ObjName = ev->GetString( 1 );
	Failed = ev->GetBoolean( 2 );
	
	ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );   
	if ( ObjIndex == 0 )
		return;
	
	switch ( ObjIndex )
	{
	case OBJECTIVE1:
		if ( Failed )
            _objectiveStates |= OBJECTIVE1_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE1_FAILED);
		break;
		
	case OBJECTIVE2:
		if ( Failed )
            _objectiveStates |= OBJECTIVE2_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE2_FAILED);
		
		break;
		
	case OBJECTIVE3:
		if ( Failed )
            _objectiveStates |= OBJECTIVE3_FAILED;
		else
			_objectiveStates &= ~(OBJECTIVE3_FAILED);
		
		break;
		
	case OBJECTIVE4:
		if ( Failed )
            _objectiveStates |= OBJECTIVE4_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE4_FAILED);
		
		break;
		
	case OBJECTIVE5:
		if ( Failed )
            _objectiveStates |= OBJECTIVE5_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE5_FAILED);
		
		break;
		
	case OBJECTIVE6:
		if ( Failed )
            _objectiveStates |= OBJECTIVE6_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE6_FAILED);
		
		break;
		
	case OBJECTIVE7:
		if ( Failed )
            _objectiveStates |= OBJECTIVE7_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE7_FAILED);
		
		
	case OBJECTIVE8:
		if ( Failed )
            _objectiveStates |= OBJECTIVE8_FAILED;
		else
            _objectiveStates &= ~(OBJECTIVE8_FAILED);
		
		break;
		
	default:
		break;
	}
	
	// gi.MObjective_SetObjectiveFailed( ObjName.c_str() , Failed );   
}


//-----------------------------------------------------
//
// Name:		LoadObjectives
// Class:		Player
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::LoadObjectives(Event* ev)
{
	loadObjectives(ev->GetString(1));
}


//-----------------------------------------------------
//
// Name:		loadObjectives
// Class:		Player
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::loadObjectives( const str& objectiveName )
{
	_objectiveStates   = 0;
	_informationStates = 0;
	gi.MObjective_Update(objectiveName);

	_objectiveNameIndex = gi.objectivenameindex(objectiveName);
}


//-----------------------------------------------------
//
// Name:		SetObjectiveShow
// Class:		Player
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::SetObjectiveShow( Event* ev )
{
	int ObjIndex;
	str ObjName;
	qboolean Show;
	bool playSound;

	playSound = false;
	
	ObjName = ev->GetString( 1 );
	Show = ev->GetBoolean( 2 );
	
	
	ObjIndex = gi.MObjective_GetIndexFromName( ObjName.c_str() );
	if ( ObjIndex == 0 )
		return;

	//Update the objective show flag.
	gi.MObjective_SetShowObjective(ObjName.c_str(), Show);


	//Set the appropriate bit on the flag passed to the client.
	unsigned int bitToChange;

	switch ( ObjIndex )
	{
	case OBJECTIVE1:
		bitToChange = OBJECTIVE1_SHOW;
		break;
	case OBJECTIVE2:
		bitToChange = OBJECTIVE2_SHOW;
		break;
	case OBJECTIVE3:
		bitToChange = OBJECTIVE3_SHOW;
		break;
	case OBJECTIVE4:
		bitToChange = OBJECTIVE4_SHOW;
		break;
	case OBJECTIVE5:
		bitToChange = OBJECTIVE5_SHOW;
		break;
	case OBJECTIVE6:
		bitToChange = OBJECTIVE6_SHOW;
		break;
	case OBJECTIVE7:
		bitToChange = OBJECTIVE7_SHOW;
		break;
	case OBJECTIVE8:
		bitToChange = OBJECTIVE8_SHOW;
		break;
	default:
		bitToChange = 0;
		break;
	}

	if ( Show && !(_objectiveStates & bitToChange) )
	{			
		_objectiveStates |= bitToChange;		
		playSound = true;
	}

	// Else is removed because if we call setobjectiveshow on the same objective twice, we will
	// actually hide it
	//else
	//{
    //    _objectiveStates &= ~bitToChange;
	//}

	if ( playSound )
		Sound( "snd_objectivechanged", CHAN_LOCAL );
}

void Player::SpecialMoveChargeStart( Event* ev )
{
	specialMoveCharge = level.time;
	specialMoveEndTime = level.time + specialMoveChargeTime;
}

void Player::SpecialMoveChargeEnd( Event* ev )
{
	specialMoveCharge = 0.0f;
	specialMoveChargeTime = 0.0f;
	specialMoveEndTime = 0.0f;
}

void Player::SpecialMoveChargeTime( Event* ev )
{
	if ( ev->NumArgs() > 0 )
		specialMoveChargeTime = ev->GetFloat( 1 );
}

void Player::SetInformationShow( Event* ev )
{
	int InfoIndex;
	str InfoName;
	qboolean Show;
	
	InfoName = ev->GetString( 1 );
	Show = ev->GetBoolean( 2 );
	
	InfoIndex = gi.MI_GetIndexFromName( InfoName.c_str() );
	if ( InfoIndex == 0 )
		return;
	
	
	switch ( InfoIndex )
	{
	case INFORMATION1:
		if ( Show )
            _informationStates |= INFORMATION1_SHOW;
		else
            _informationStates &= ~(INFORMATION1_SHOW);
		break;
		
	case INFORMATION2:
		if ( Show )
            _informationStates |= INFORMATION2_SHOW;
		else
            _informationStates &= ~(INFORMATION2_SHOW);
		
		break;
		
	case INFORMATION3:
		if ( Show )
            _informationStates |= INFORMATION3_SHOW;
		else
            _informationStates &= ~(INFORMATION3_SHOW);
		
		break;
		
	case INFORMATION4:
		if ( Show )
            _informationStates |= INFORMATION4_SHOW;
		else
            _informationStates &= ~(INFORMATION4_SHOW);
		
		break;
		
	case INFORMATION5:
		if ( Show )
            _informationStates |= INFORMATION5_SHOW;
		else
            _informationStates &= ~(INFORMATION5_SHOW);
		
		break;
		
	case INFORMATION6:
		if ( Show )
            _informationStates |= INFORMATION6_SHOW;
		else
            _informationStates &= ~(INFORMATION6_SHOW);
		
		break;
		
	case INFORMATION7:
		if ( Show )
            _informationStates |= INFORMATION7_SHOW;
		else
            _informationStates &= ~(INFORMATION7_SHOW);
		
		
	case INFORMATION8:
		if ( Show )
            _informationStates |= INFORMATION8_SHOW;
		else
            _informationStates &= ~(INFORMATION8_SHOW);
		
		break;
		
	default:
		break;
	}
}

void Player::MissionFailed( Event* ev )
{
	str reason = "DefaultFailure";
	if ( ev->NumArgs() > 0 )
		reason = ev->GetString( 1 );

	G_MissionFailed(reason);
}

void Player::setMissionFailed( void )
{
	client->ps.missionStatus |= MISSION_FAILED;
}

void Player::SetStat( Event *ev )
{
	int stat_index;
	int stat_value;
	
	stat_index = PlayerStat_NameToNum( ev->GetString( 1 ) );
	
	if ( stat_index < 0 )
	{
		gi.Printf( "Couldn't find player stat %s\n", ev->GetString( 1 ) );
		return;
	}
	
	stat_value = ev->GetInteger( 2 );
	
	client->ps.stats[ stat_index ] = stat_value;
}

void Player::SetStateFile( Event *ev )
{
	str stateFileName(ev->GetString(1));
	gi.cvar_set( "g_statefile", stateFileName );
	LoadStateTable();
}

//----------------------------------------------------------------
// Name:			ShouldSendToClient
// Class:			Player
//
// Description:		Decides whether or not we should send this entity to the client
//
// Parameters:		Entity *entityToSend						- entity that we deciding about
//
// Returns:			qboolean										- whether or not we should send this entity
//----------------------------------------------------------------

qboolean Player::ShouldSendToClient( Entity *entityToSend )
{
	// For now, early out if we don't have care about any view modes

	if ( multiplayerManager.inMultiplayer() && client->pers.mp_lowBandwidth && entityToSend->isNetworkDetail() )
		return false;

	if ( !entityToSend->_affectingViewModes )
		return true;


	// Check to see if we should send this entity based on the player's current view mode
	
	if ( entityToSend->_affectingViewModes & _viewMode )
		return gi.GetViewModeSendInMode( entityToSend->_affectingViewModes & _viewMode );
	else
		return gi.GetViewModeSendNotInMode( entityToSend->_affectingViewModes & (~_viewMode) );
}

void Player::UpdateEntityStateForClient( entityState_t *state )
{
	int i;

	if ( !state )
		return;

	// Only update entity in multiplayer

	if ( !multiplayerManager.inMultiplayer() )
		return;

	// Only update entity in low bandwidth mode

	if ( !client->pers.mp_lowBandwidth )
		return;

	// Clear net angles if a client

	if ( state->clientNum != ENTITYNUM_NONE )
	{
		VectorClear( state->netangles );
	}

	// Clear bone angles

	for ( i = 0 ; i < NUM_BONE_CONTROLLERS ; i++ )
	{
		VectorClear( state->bone_angles[ i ] );
	}
}

void Player::UpdatePlayerStateForClient( playerState_t *state )
{
	if ( !state )
		return;

	// Only update playerstate in multiplayer

	if ( !multiplayerManager.inMultiplayer() )
		return;

	if ( !multiplayerManager.isPlayerSpectator( this, SPECTATOR_TYPE_FOLLOW ) && !mp_savingDemo )
	{
		VectorClear( state->viewangles );
	}
}

//----------------------------------------------------------------
// Name:			ExtraEntitiesToSendToClient
// Class:			Player
//
// Description:		Adds extra entities to send over to the client
//
// Parameters:		int *numExtraEntities					- the number of extra entities we added
//					int *extraEntities						- the list of entity numbers that we added
//
// Returns:			None
//----------------------------------------------------------------

void Player::ExtraEntitiesToSendToClient( int *numExtraEntities, int *extraEntities )
{
	*numExtraEntities = 0;
	
	// Add in our current dialog person (if any)
	if ( _dialogEntnum != ENTITYNUM_NONE )
	{
		extraEntities[ *numExtraEntities ] = _dialogEntnum;
		(*numExtraEntities)++;
		
		// Make sure we haven't added too many entities to the list
		
		if ( *numExtraEntities == MAX_EXTRA_ENTITIES_FROM_GAME )
			return;
	}
}

//----------------------------------------------------------------
// Name:			setViewMode
// Class:			Player
//
// Description:		Sets the players current view mode
//
// Parameters:		const str &viewModeName					- the name of the view mode to go to
//
// Returns:			None
//----------------------------------------------------------------

void Player::setViewMode( const str &viewModeName )
{
	Sentient::setViewMode( viewModeName );
	client->ps.viewMode = getViewMode();
}

//----------------------------------------------------------------
// Name:			AwardPoints
// Class:			Player
//
// Description:		Gives the player points
//
// Parameters:		int numPoints -- the number of points to give
//
// Returns:			int -- The new total number of points
//----------------------------------------------------------------
int Player::AwardPoints(int numPoints)
{
	points += numPoints;
	
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	if ( !gpm ) return points ;
	
	float maxPoints		= 0.0f ;
	float experience	= 0.0f ;
	
	if ( gpm->hasProperty( "CurrentPlayer", "maxPoints" ) )
	{
		maxPoints  = gpm->getFloatValue( "CurrentPlayer", "maxPoints" );
		experience = 100.0f * (points / maxPoints) ;
		gpm->setFloatValue( "CurrentPlayer", "experience", experience );
		
		if ( experience >= 100.0f )
		{
			float level			= gpm->getFloatValue( "CurrentPlayer", "level" );
			float skillPoints	= gpm->getFloatValue( "CurrentPlayer", "SkillPoints" );
			
			level		+= 1.0 ;
			skillPoints += level ;
			maxPoints	 = level * level * 100.0f ;
			experience	 = 0.0f ;
			
			gpm->setFloatValue( "CurrentPlayer", "level",		level );
			gpm->setFloatValue( "CurrentPlayer", "SkillPoints",	skillPoints );
			gpm->setFloatValue( "CurrentPlayer", "maxPoints",	maxPoints );
			gpm->setFloatValue( "CurrentPlayer", "experience",	experience );
			points = 0 ;
			
			G_EnableWidgetOfPlayer( edict, "level_up", true );
		}
	}
	
	return points;
}

//----------------------------------------------------------------
// Name:			TakePoints
// Class:			Player
//
// Description:		Takes points away (never below 0)
//
// Parameters:		int numPoints -- the number of points to take
//
// Returns:			int -- The new total number of points
//----------------------------------------------------------------
int Player::TakePoints(int numPoints)
{
	points -= numPoints;
	if ( points < 0 )
		points = 0;
	
	return points;
}

//----------------------------------------------------------------
// Name:			GivePointsEvent
// Class:			Player
//
// Description:		Gives the player points (from script)
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::GivePointsEvent( Event *ev )
{
	if ( ev->NumArgs() > 0 )
		AwardPoints(ev->GetInteger( 1 ));
}

//----------------------------------------------------------------
// Name:			SetPointsEvent
// Class:			Player
//
// Description:		Sets the players total number of points
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::SetPointsEvent( Event *ev )
{
	if ( ev->NumArgs() > 0 )
		points = ev->GetInteger( 1 );
}

//----------------------------------------------------------------
// Name:			ChangeChar
// Class:			Player
//
// Description:		Starts the screen fading out.  When it fades to black
//					we switch characters.
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ChangeChar( Event *ev )
{
	if ( changingChar ) // In the process of changing don't allow this event AGAIN until we're done.
		return;
	
	// Don't switch characters if we're already that character.
	str curChar = gi.cvar("g_playermodel","",0)->string;
	str curStateFile = gi.cvar("g_statefile","",0)->string;
	if ((ev->GetString( 1 ) == curStateFile) && (ev->GetString( 2 ) == curChar))
		return;
	
	Actor *act = Actor::FindActorByName(ev->GetString( 3 ));
	if ( act )
	{
		changingChar = true;
		G_FadeOut(1.0f);
		Event *ev2 = new Event(EV_Player_ChangeCharFadeIn);
		ev2->AddString(ev->GetString( 1 ));
		ev2->AddString(ev->GetString( 2 ));
		ev2->AddString(ev->GetString( 3 ));
		ev2->AddString(ev->GetString( 4 ));
		ev2->AddEntity(act);
		PostEvent(ev2, 1.0f);
	}
}

//----------------------------------------------------------------
// Name:			ChangeCharFadeIn
// Class:			Player
//
// Description:		Changes to the specified state machine and model
//					as the screen fades in.
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ChangeCharFadeIn( Event *ev )
{
	str statemachine = ev->GetString( 1 );
	str newmodel = ev->GetString( 2 );
	str replacemodel = ev->GetString( 3 );
	str spawnNPC = ev->GetString( 4 );
	Actor *act = (Actor*)ev->GetEntity( 5 );

	ProcessEvent(EV_DetachAllChildren);

	gi.cvar_set( "g_statefile", statemachine.c_str() );
	gi.cvar_set( "g_playermodel", newmodel.c_str() );
	InitModel();
	LoadStateTable();

	Event *e = new Event( EV_Player_SpawnActor );
	e->AddString( spawnNPC.c_str() );
	e->AddString( "origin" );
	e->AddVector(origin);
	e->AddString( "angles" );
	e->AddVector(angles);
	// Spawn the actor where the player is currently positioned
	SpawnActor(e);

	// Set the player angles and origin to the new location
	origin = act->origin;
	SetViewAngles(act->angles);
	act->ProcessEvent(  EV_Remove );

	G_AutoFadeIn();
	changingChar = false;
}

//----------------------------------------------------------------
// Name:			SetPlayerChar
// Class:			Player
//
// Description:		Sets the player character
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::SetPlayerChar( Event *ev )
{
	str statemachine = ev->GetString( 1 );
	str newmodel = ev->GetString( 2 );
	
	// Don't switch characters if we're already that character.
	str curChar = gi.cvar("g_playermodel","",0)->string;
	str curStateFile = gi.cvar("g_statefile","",0)->string;
	if ((statemachine == curStateFile) && (newmodel == curChar))
		return;
	
	gi.cvar_set( "g_statefile", statemachine.c_str() );
	gi.cvar_set( "g_playermodel", newmodel.c_str() );
	ProcessEvent(EV_DetachAllChildren);
	InitModel();
	LoadStateTable();
}

//----------------------------------------------------------------
// Name:			PlayerKnockback
// Class:			Player
//
// Description:		Sets the player knockback value.
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::PlayerKnockback(Event *ev)
{
	playerKnockback = ev->GetInteger( 1 );
}

//----------------------------------------------------------------
// Name:			KnockbackMultiplier
// Class:			Player
//
// Description:		Sets the player knockback multiplier
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::KnockbackMultiplier(Event *ev)
{
	knockbackMultiplier = ev->GetInteger( 1 );
}

//----------------------------------------------------------------
// Name:			MeleeEvent
// Class:			Player
//
// Description:		Performs a weaponless melee attack.
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::MeleeEvent( Event *ev )
{
	Vector melee_pos;
	Vector melee_end;
	float damage = 20;
	str means_of_death_string;
	meansOfDeath_t attack_means_of_death;
	float knockback;
	
	// Get all of the parameters
	
	if ( ev->NumArgs() > 0 )
		damage = ev->GetFloat( 1 );
	
	if ( ev->NumArgs() > 1 )
		means_of_death_string = ev->GetString( 2 );
	
	if ( ev->NumArgs() > 2 )
		knockback = ev->GetFloat( 3 );
	else
		knockback = damage * 8.0f;
	
	melee_pos = centroid;
	melee_end = centroid + Vector( orientation[0] ) * 96.0f;
	
	if ( means_of_death_string.length() > 0 )
		attack_means_of_death = (meansOfDeath_t)MOD_NameToNum( means_of_death_string );
	else
		attack_means_of_death = MOD_CRUSH;
	
	// Do the actual attack
	MeleeAttack( melee_pos, melee_end, damage, this, attack_means_of_death, 15.0f, -45.0f, 45.0f, knockback );
}

//----------------------------------------------------------------
// Name:			MeleeDamageStart
// Class:			Player
//
// Description:		Sets flags to perform melee damage with the weapon
//					in the hand specified (defaults to right hand)
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::MeleeDamageStart( Event *ev )
{
	Weapon *weapon;
	weaponhand_t hand = WEAPON_RIGHT;
	
	if ( ev->NumArgs() > 0 )
		hand = WeaponHandNameToNum(ev->GetString( 1 ));
	
	weapon = GetActiveWeapon( hand );
	if ( !weapon )
		return;
	
	// Make sure the tags are there on the weapon, or it will crash.
	int tag_num = 0;
	tag_num += gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe1" );
	tag_num += gi.Tag_NumForName( weapon->edict->s.modelindex, "tag_swipe2" );
	if ( tag_num < 0 )
		return;
	
	weapon->ClearMeleeVictims();
	if ( hand == WEAPON_RIGHT )
		meleeAttackFlags |= MELEE_ATTACK_RIGHT;
	if ( hand == WEAPON_LEFT )
		meleeAttackFlags |= MELEE_ATTACK_LEFT;
}

//----------------------------------------------------------------
// Name:			MeleeDamageEnd
// Class:			Player
//
// Description:		Stops doing damage with the melee weapon in the hand
//					specified.
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::MeleeDamageEnd( Event *ev )
{	
	weaponhand_t hand = WEAPON_RIGHT;
	
	if ( ev->NumArgs() > 0 )
		hand = WeaponHandNameToNum(ev->GetString( 1 ));
	
	if ( hand == WEAPON_RIGHT )
		meleeAttackFlags &= ~MELEE_ATTACK_RIGHT;
	if ( hand == WEAPON_LEFT )
		meleeAttackFlags &= ~MELEE_ATTACK_LEFT;
}

//----------------------------------------------------------------
// Name:			ChangeStance
// Class:			Player
//
// Description:		Changes to the stance specified
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ChangeStance(Event *ev)
{
	if ( ev->NumArgs() < 1 )
		return;
	
	changedStanceTorso = true;
	changedStanceLegs = true;
	stanceNumber = ev->GetInteger( 1 );
}

//----------------------------------------------------------------
// Name:			ClearStanceTorso
// Class:			Player
//
// Description:		Clears internal torso stance data
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ClearStanceTorso(Event *ev)
{
	changedStanceTorso = false;
}

//----------------------------------------------------------------
// Name:			ClearStanceLegs
// Class:			Player
//
// Description:		Clears internal legs stance data
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ClearStanceLegs(Event *ev)
{
	changedStanceLegs = false;
}

//----------------------------------------------------------------
// Name:			ClearIncomingMelee
// Class:			Player
//
// Description:		Clears the incoming melee flag
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::ClearIncomingMelee(Event *ev)
{
	incomingMeleeAttack = false;
}

//----------------------------------------------------------------
// Name:			AddMeleeAttacker
// Class:			Player
//
// Description:		Adds the entity to the melee attacker container
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::AddMeleeAttacker( Event *ev)
{
	Entity *ent = ev->GetEntity( 1 );
	meleeAttackerList.AddUniqueObject( ent );
}

//----------------------------------------------------------------
// Name:			SetBendTorso
// Class:			Player
//
// Description:		Sets the torso bending for the player
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::SetBendTorso(Event *ev)
{
	if ( ev->NumArgs() > 0 )
		bendTorsoMult = ev->GetFloat( 1 );
	else
		bendTorsoMult = standardTorsoMult;
}

//----------------------------------------------------------------
// Name:			HeadWatchAllowed
// Class:			Player
//
// Description:		Sets whether to headwatch or not, defaults to true
//
// Parameters:		Event *ev
//
// Returns:			None
//----------------------------------------------------------------
void Player::HeadWatchAllowed(Event *ev)
{
	Sentient::HeadWatchAllowed( ev );
}

void Player::SetCurrentCallVolume( const str &volumeName )	
{
    currentCallVolume = volumeName;
}
	
str	Player::GetCurrentCallVolume()
{
	return currentCallVolume;
}

//
// Multiplayer stuff
//

void Player::Score( Event *ev )
{
	multiplayerManager.score( this );
}

void Player::joinTeam( Event *ev )
{
	str teamName;

	teamName = ev->GetString( 1 );

	multiplayerManager.joinTeam( this, teamName );
}

void Player::multiplayerCommand( Event *ev )
{
	str command;
	str parm;

	command = ev->GetString( 1 );
	parm    = ev->GetString( 2 );

	multiplayerManager.playerCommand( this, command, parm );
}

void Player::Disconnect( void )
{
	if ( multiplayerManager.inMultiplayer() )
	{
		multiplayerManager.removePlayer( this );
	}
}

void Player::CallVote( Event *ev )
{
	str command;
	str arg;

	if ( multiplayerManager.inMultiplayer() )
	{
		command = ev->GetString( 1 );

		if ( ev->NumArgs() > 1 )
			arg = ev->GetString( 2 );

		multiplayerManager.callVote( this, command, arg );
	}
}

void Player::Vote( Event *ev )
{
	str vote;

	if ( multiplayerManager.inMultiplayer() )
	{
		if ( ev->NumArgs() != 1 )
		{
			multiplayerManager.HUDPrint( entnum, "$$Usage$$: vote <1|0|y|n>" );
			return;
		}

		vote = ev->GetString( 1 );

		multiplayerManager.vote( this, vote );
	}
}

//
// Powerup stuff
//

void Player::addPowerupEffect( PowerupBase *powerup )
{
	str modelName;
	str tagName;
	float modelRemoveTime;
	str shaderName;

	if ( !powerup )
		return;

	// Attach a model to the player if necessary

	powerup->getModelToAttachOnUse( modelName, tagName, modelRemoveTime );

	if ( modelName.length() > 0 )
	{
		Event *attachModel;

		attachModel = new Event( EV_AttachModel );

		attachModel->AddString( modelName );
		attachModel->AddString( tagName );
		attachModel->AddFloat( 1.0f );
		attachModel->AddString( "" );
		attachModel->AddInteger( 0 );
		attachModel->AddFloat( modelRemoveTime );

		ProcessEvent( attachModel );
	}
}

void Player::removePowerupEffect( PowerupBase *powerup )
{
	str modelName;
	str tagName;
	float modelRemoveTime;
	str shaderName;

	if ( !powerup )
		return;

	// Remove the attached model from the player if attached before

	powerup->getModelToAttachOnUse( modelName, tagName, modelRemoveTime );

	if ( modelName.length() > 0 )
	{
		Event *removeAttachedModel;

		removeAttachedModel = new Event( EV_RemoveAttachedModel );
		
		removeAttachedModel->AddString( tagName );
		removeAttachedModel->AddFloat( 0.0f );
		removeAttachedModel->AddString( modelName );

		ProcessEvent( removeAttachedModel );
	}

	// Remove the custom shader from the player if set before

	powerup->getShaderToDisplayOnUse( shaderName );

	if ( shaderName.length() > 0 )
	{
		clearCustomShader( shaderName.c_str() );
	}
}

void Player::setPowerup( Powerup *powerup )
{
	// If this is the same powerup type, stack them

	if ( _powerup && powerup && ( _powerup->getName() == powerup->getName() ) && _powerup->canStack() && powerup->canStack() )
	{
		float newTimeLeft;
		newTimeLeft = _powerup->getTimeLeft() + powerup->getTimeLeft();
		_powerup->setTimeLeft( newTimeLeft );
	}
	else
	{
		removePowerup();

		CancelEventsOfType( EV_Player_RemovePowerup );

		_powerup = powerup;

		if ( !_powerup )
			return;

		addPowerupEffect( _powerup );
	}

	setItemText( _powerup->getIcon(), va( "$$Using$$ $$Item-%s$$", _powerup->getName().c_str() ) );
	//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ %s", _powerup->getRealName() );
}

void Player::removePowerup( void )
{
	if ( _powerup )
	{
		removePowerupEffect( _powerup );

		delete _powerup;
		_powerup = NULL;
	}
}

void Player::removePowerupEvent( Event *ev )
{
	removePowerup();
}

void Player::dropPowerup( void )
{
	if ( _powerup )
	{
		if ( _powerup->canDrop() )
		{
			_powerup->spawn( centroid );
		}

		removePowerup();
	}
}

//
// Rune stuff
//

bool Player::hasRune( void )
{
	if ( _rune )
		return true;
	else
		return false;
}

void Player::setRune( Rune *rune )
{
	removeRune();

	_rune = rune;

	if ( !_rune )
		return;

	addPowerupEffect( _rune );

	// Tell the player they are now using this rune

	setItemText( rune->getIcon(), va( "$$Using$$ $$Item-%s$$", _rune->getName().c_str() ) );
	//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ %s", _rune->getRealName() );
}

void Player::removeRune( void )
{
	if ( _rune )
	{
		removePowerupEffect( _rune );

		delete _rune;
		_rune = NULL;
	}
}

//
// Holdable item stuff
//

void Player::setHoldableItem( HoldableItem *holdableItem )
{
	removeHoldableItem();

	_holdableItem = holdableItem;
}

void Player::removeHoldableItem( void )
{
	if ( _holdableItem )
	{
		_holdableItem->PostEvent( EV_Remove, 0.0f );

		_holdableItem = NULL;
	}
}

void Player::useHoldableItem( void )
{
	if ( _holdableItem )
	{
		if ( multiplayerManager.inMultiplayer() )
		{
			multiplayerManager.playerEventNotification( "use-HoldableItem", _holdableItem->getName(), this );
		}

		if ( _holdableItem->use() )
		{
			// Must check again if holdable item exists, because use might have caused the holdable item to be destroyed

			if ( _holdableItem )
			{
				addPowerupEffect( _holdableItem );

				setItemText( _holdableItem->getIcon(), va( "$$Used$$ $$Item-%s$$", _holdableItem->getName().c_str() ) );
				//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Using$$ $$Item-%s$$", _holdableItem->getName() );
				removeHoldableItem();
			}
		}
	}
}

HoldableItem* Player::getHoldableItem( void )
{
	return _holdableItem;
}

float Player::getDamageDone( float damage, int meansOfDeath, bool inMelee )
{
	float damageDone;


	damageDone = damage;

	if ( inMelee )
		damageDone *= damage_multiplier;

	if ( _powerup )
		damageDone = _powerup->getDamageDone( damageDone, meansOfDeath );

	if ( _rune )
		damageDone = _rune->getDamageDone( damageDone, meansOfDeath );
	
	return damageDone;
}

meansOfDeath_t Player::changetMeansOfDeath( meansOfDeath_t meansOfDeath )
{
	meansOfDeath_t realMeansOfDeath;

	realMeansOfDeath = meansOfDeath;

	if ( _powerup )
		realMeansOfDeath = _powerup->changetMeansOfDeath( realMeansOfDeath );

	if ( _rune )
		realMeansOfDeath = _rune->changetMeansOfDeath( realMeansOfDeath );

	if ( _finishActor && _doingFinishingMove )
		realMeansOfDeath = MOD_REDEMPTION; // Finishing move MOD... oh sweet irony

	return realMeansOfDeath;
}

void Player::dropRune( Event *ev )
{
	if ( _rune )
	{
		dropRune();
	}
}

void Player::dropRune( void )
{
	if ( _rune )
	{
		setItemText( _rune->getIcon(), va( "$$Dropping$$ $$Item-%s$$", _rune->getName().c_str() ) );
		//gi.centerprintf ( edict, CENTERPRINT_IMPORTANCE_NORMAL, "$$Dropping$$ $$Item-%s$$", _rune->getName() );

		_rune->spawn( centroid );

		removeRune();
	}
	else
	{
		multiplayerManager.playerCommand( this, "dropItem", "" );
	}
}

//----------------------------------------------------------------
// Name:			setCanTransferEnergy
// Class:			Player
//
// Description:		Makes the player allowed to transfer energy from ammo to armor
//
// Parameters:		Event *
//
// Returns:			none
//----------------------------------------------------------------

void Player::setCanTransferEnergy( Event * )
{
	_canTransferEnergy = true;
}

//----------------------------------------------------------------
// Name:			transferEnergy
// Class:			Player
//
// Description:		Transfers some energy from ammo to the armor
//
// Parameters:		none
//
// Returns:			none
//----------------------------------------------------------------

void Player::transferEnergy( void )
{
	Event *armorEvent;

	// Make sure we are allowed to transfer energy

	if ( !_canTransferEnergy )
		return;

	// Make sure enough time has gone by to transfer more energy

	if ( _nextEnergyTransferTime > level.time )
		return;

	_nextEnergyTransferTime = level.time + level.frametime;

	// Make sure we have enough energy

	if ( AmmoCount( "Plasma" ) < 1 )
		return;

	// Make sure we still need more armor

	if ( GetArmorValue() >= 100 )
		return;

	// Give ourselves a little bit of armor

	armorEvent = new Event( EV_Sentient_GiveArmor );

	armorEvent->AddString( "BasicArmor" );
	armorEvent->AddFloat( 1.0f );

	ProcessEvent( armorEvent );	

	// Use up some energy

	UseAmmo( "Plasma", 1 );
}

//--------------------------------------------------------------
//
// Name:			AdvancedMeleeAttack
// Class:			Player
//
// Description:		Gets the waepon in the hand specified and calls
//					it's AdvancedMeleeAttack function.
//
// Parameters:		weaponhand_t hand -- weapon hand
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::AdvancedMeleeAttack(weaponhand_t hand)
{
	Weapon *weapon;
	bool	critical = false ;

	if ( hand == WEAPON_ERROR )
		return;

	weapon = GetActiveWeapon( hand );
	if ( !weapon )
		return;

	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	if ( gpm->hasProperty( "CurrentPlayer.Criticals", "value" ) )
	{
		float criticalSkill			= gpm->getFloatValue( "CurrentPlayer.Criticals", "value" );
		float criticalBaseChance	= gpm->getFloatValue( "Criticals", "baseChance" );
		float criticalChance		= criticalSkill * criticalBaseChance ;
		if ( G_Random() < criticalChance )
		{
			critical = true ;
		}
	}

	weapon->AdvancedMeleeAttack("tag_swipe1", "tag_swipe2", critical );
}

//--------------------------------------------------------------
// Name:			setDoDamageScreenFlash
// Class:			Player
//
// Description:		Sets whether or not we want to flash the player's screen when he is damaged
//
// Parameters:		Event *ev					- optionally contains a bool specifying on or off
//
// Returns:			None
//--------------------------------------------------------------

void Player::setDoDamageScreenFlash( Event *ev )
{
	if ( ev->NumArgs() > 0 )
		_doDamageScreenFlash = ev->GetBoolean( 1 );
	else
		_doDamageScreenFlash = true;
}

//--------------------------------------------------------------
// Name:			pointOfView
// Class:			Player
//
// Description:		Forces the player into a different point of view
//
// Parameters:		Event *ev - 1 = 1st person, 0 = 3rd person
//
// Returns:			None
//--------------------------------------------------------------

void Player::pointOfView( Event *ev )
{
	if ( ev->NumArgs() > 0 )
	{
		// More than one argument, we are attempting to SET
		// the point of view specifically.
		bool pov = ev->GetBoolean( 1 );
		if ( pov == _isThirdPerson )
			return;
	}
	
	// Toggle the point of view
	if ( _isThirdPerson )
	{
		G_SendCommandToPlayer(edict, "cg_3rd_person 0");
		_isThirdPerson = false;
	}
	else
	{
		G_SendCommandToPlayer(edict, "cg_3rd_person 1");
		_isThirdPerson = true;
	}
}

void Player::HandleFinishableList()
{
	int i,j;
	for ( i=1; i<=finishableList.NumObjects(); i++ )
	{
		Actor *act = finishableList.ObjectAt(i);
		for ( j=1; j<=finishingMoveList.NumObjects(); j++ )
		{
			FinishingMove *fm = finishingMoveList.ObjectAt(j);
			float fovdot = cos( DEG2RAD( fm->coneangle * 0.5f) );
			Vector delta = ( act->origin ) - origin;
			if ( delta.length() > fm->distance )
				continue; 
			
			// Enemy Angles not yet used...
			// Chance not yet used...
			
			delta.z = 0.0f;
			delta.normalize();
			float dot = 0.0f;
			switch ( fm->direction )
			{
			case 0 : dot = DotProduct( yaw_forward, delta ); break;
			case 1 : dot = DotProduct( yaw_forward*-1.0f, delta ); break;
			case 2 : dot = DotProduct( yaw_left, delta ); break;
			case 3 : dot = DotProduct( yaw_left*-1.0f, delta ); break;
			}
			
			if ( dot > fovdot )
			{
				//				G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", true );
				_finishActor = act;
				_finishState = fm->statename;
				return;
			}
		}
	}
	
	//	G_EnableWidgetOfPlayer( edict, "ActionIcon_Kick", false );
	_finishActor = NULL;
	_finishState = "";
}

//--------------------------------------------------------------
//
// Name:			addFinishingMove
// Class:			Player
//
// Description:		Add a finishing move to the list
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::addFinishingMove( Event *ev )
{
	str state, dirstr;
	float coneangle = 45.0f;
	float dist = 64.0f;
	float eyaw = 0.0f;
	float chance = 1.0f;
	
	state = ev->GetString( 1 );
	dirstr = ev->GetString( 2 );
	
	if ( ev->NumArgs() > 2 )
		coneangle = ev->GetFloat( 3 );
	if ( ev->NumArgs() > 3 )
		dist = ev->GetFloat( 4 );
	if ( ev->NumArgs() > 4 )
		eyaw = ev->GetFloat( 5 );
	if ( ev->NumArgs() > 5 )
		chance = ev->GetFloat( 6 );

	FinishingMove *fm = new FinishingMove();
	fm->statename = state;
	if ( dirstr == "front" )
		fm->direction = 0;
	else if ( dirstr == "behind" )
		fm->direction = 1;
	else if ( dirstr == "left" )
		fm->direction = 2;
	else if ( dirstr = "right" )
		fm->direction = 3;
	else 
		fm->direction = 0; // Front default
	fm->coneangle = coneangle;
	fm->distance = dist;
	fm->enemyyaw = eyaw;
	fm->chance = chance;

	finishingMoveList.AddObject(fm);
}

//--------------------------------------------------------------
//
// Name:			clearFinishingMove
// Class:			Player
//
// Description:		Clears the finishing move list.
//
// Parameters:		Event *ev -- no params
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::clearFinishingMove( Event *ev )
{
	int i;
	for ( i=1; i<=finishingMoveList.NumObjects(); i++ )
	{
		FinishingMove *fm = finishingMoveList.ObjectAt(i);
		delete fm;
	}
	finishingMoveList.FreeObjectList();
}

//--------------------------------------------------------------
//
// Name:			doFinishingMove
// Class:			Player
//
// Description:		Fires off the finishing move that's currently prepared
//
// Parameters:		Event *ev -- no params
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::doFinishingMove( Event *ev )
{
	movecontrol = MOVECONTROL_ABSOLUTE;
	
	if ( _finishState.length() )
	{
		State* newState = statemap_Torso->FindState( _finishState );
		if ( newState )
		{
			EvaluateState( newState );
			_doingFinishingMove = true;
			_finishActor->SetState("FINISH_ME");
		}
		else
			gi.WDPrintf( "Could not find state %s on doFinishingMove\n", _finishState.c_str() );
	}
}

//--------------------------------------------------------------
//
// Name:			forceTimeScale
// Class:			Player
//
// Description:		Forces timescale for the game
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::forceTimeScale( Event *ev )
{
	float timescale = 1.0f;
	if ( ev->NumArgs() > 0 )
		timescale = ev->GetFloat( 1 );

	char tmp[15];
	sprintf(tmp, "timescale %f", timescale);

	G_SendCommandToPlayer(edict, tmp);
}

//--------------------------------------------------------------
//
// Name:			freezePlayer
// Class:			Player
//
// Description:		Freezes the player
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::freezePlayer( Event *ev )
{
	bool freeze = true;
	if ( ev->NumArgs() > 0 )
		freeze = ev->GetBoolean( 1 );

	level.playerfrozen = freeze;
}

//--------------------------------------------------------------
//
// Name:			immobilizePlayer
// Class:			Player
//
// Description:		Immobilizes the player (can only look around)
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::immobilizePlayer( Event *ev )
{
	bool freeze = true;

	if ( ev->NumArgs() > 0 )
		freeze = ev->GetBoolean( 1 );

	if ( freeze )
		flags |= FL_IMMOBILE;
	else
		flags &= ~FL_IMMOBILE;

}

//--------------------------------------------------------------
//
// Name:			setAttackType
// Class:			Player
//
// Description:		Sets the attack type of the attack
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::setAttackType( Event *ev )
{
	_attackType = ev->GetString( 1 );
}


//--------------------------------------------------------------
//
// Name:			getGameplayAnim
// Class:			Player
//
// Description:		Gets the anim name from the gameplay database
//					based on the current gameplayAnimIdx
//
// Parameters:		const str& objname -- The object
//
// Returns:			const str
//
//--------------------------------------------------------------
const str Player::getGameplayAnim(const str& objname)
{
	if ( !objname.length() || !getArchetype().length() )
		return "";

	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = getArchetype() + "." + objname;
	if ( !gpm->hasObject(scopestr) )
		return "";

	char tmpstr[6];
	sprintf(tmpstr, "%d", _gameplayAnimIdx);
	return gpm->getStringValue(scopestr, tmpstr);
}


//--------------------------------------------------------------
//
// Name:			nextGameplayAnim
// Class:			Player
//
// Description:		Increment the the gameplay animation up to 
//					the maxchain value in the database.  Wrap
//					around afterwards.
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::nextGameplayAnim( Event *ev )
{
	if ( ev->NumArgs() < 1 )
		return;

	str objname = ev->GetString( 1 );
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	str scopestr = "CurrentPlayer.ChainedMoves";
	if ( !gpm->hasObject(scopestr) )
		return;

	int max = (int)gpm->getFloatValue(scopestr, "value");
	max++; // Increment to compensate for 0 based skill system, we always have to play the first anim
	if ( _gameplayAnimIdx < max )
		_gameplayAnimIdx++;
	else
		_gameplayAnimIdx = 1;

	// Max of 4 chains deep.
	if ( _gameplayAnimIdx > 4 )
		_gameplayAnimIdx = 1;
}

//--------------------------------------------------------------
//
// Name:			setGameplayAnim
// Class:			Player
//
// Description:		Sets the gameplayAnimIdx to the number specified
//
// Parameters:		Event *ev
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::setGameplayAnim( Event *ev )
{
	int val = 1;
	if ( ev->NumArgs() > 0)
		val = ev->GetInteger( 1 );

	_gameplayAnimIdx = val;
}


//-----------------------------------------------------
//
// Name:		SetDisableUseWeapon
// Class:		Player
//
// Description:	Can disable the use of a new weapon
//
// Parameters:	ev - the event that sets the disableUseWeapon
//
// Returns:		None
//-----------------------------------------------------
void Player::setDisableUseWeapon( Event* ev)
{
	if(ev->NumArgs() > 0)
	{
		_disableUseWeapon = ev->GetBoolean(1);
	}
	else
	{
		_disableUseWeapon = true;
	}


	Com_Printf("DisableUseWeapon %d", _disableUseWeapon);

}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::setDisableInventory( Event* ev )
{
	if(ev->NumArgs() > 0)
	{
		disableInventory();
		return;
	}
	else if( ev->GetFloat(1))
	{
		enableInventory();
		return;
	}

	disableInventory();
}

//--------------------------------------------------------------
//
// Name:			skillChanged
// Class:			Player
//
// Description:		Handles skills when they change
//
// Parameters:		const str& objname -- Object in the database that has changed
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::skillChanged(const str& objname)
{
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();
	if ( !gpm->hasObject(objname) )
		return;

	float value = gpm->getFloatValue(objname, "value");
	if ( objname == "CurrentPlayer.BonusHP" && value > 0.0f )
	{
		if ( gpm->hasFormula("BonusHP") )
		{
			GameplayFormulaData fd(this);
			float hp = gpm->calculate("BonusHP", fd);
			float maxhp = max_health + ( max_health * hp );
			setMaxHealth(maxhp);
		}
	}
}


//--------------------------------------------------------------
//
// Name:			EquipItems
// Class:			Player
//
// Description:		Equips items from the database
//
// Parameters:		Event *ev -- not used
//
// Returns:			None
//
//--------------------------------------------------------------
void Player::equipItems( Event *ev )
{
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();

	str itemName, modelName;
	
	itemName	= gpm->getStringValue("CurrentPlayer.DualWield", "name");
	modelName	= gpm->getStringValue(itemName, "model");
	if ( modelName.length() )
		giveItem(modelName);

	itemName	= gpm->getStringValue("CurrentPlayer.TwoHanded", "name");
	modelName	= gpm->getStringValue(itemName, "model");
	if ( modelName.length() )
		giveItem(modelName);

	itemName	= gpm->getStringValue("CurrentPlayer.Ranged", "name");
	modelName	= gpm->getStringValue(itemName, "model");
	if ( modelName.length() )
		giveItem(modelName);

	itemName	= gpm->getStringValue("CurrentPlayer.Ring", "name");
	modelName	= gpm->getStringValue(itemName, "model");
	if ( modelName.length() )
		giveItem(modelName);

	itemName	= gpm->getStringValue("CurrentPlayer.Amulet", "name");
	modelName	= gpm->getStringValue(itemName, "model");
	if ( modelName.length() )
		giveItem(modelName);

	useWeapon("DualWield", WEAPON_RIGHT);
}


//--------------------------------------------------------------
//
// Name:			getFreeInventorySlot
// Class:			Player
//
// Description:		Finds a free inventory slot from the database
//
// Parameters:		None
//
// Returns:			Object name of the free slot, or "" if the inventory
//					is full.
//
//--------------------------------------------------------------
const str Player::getFreeInventorySlot()
{
	GameplayManager *gpm = GameplayManager::getTheGameplayManager();

	int i;
	char tmpstr[128];
	for ( i=1; i<15; i++ )
	{
		sprintf(tmpstr,"PartyInventory.Slot%d",i);
		str invitem = gpm->getStringValue(tmpstr, "name");
		if ( invitem == "Empty" )
			return tmpstr;
	}
	
	return "";
}

void Player::usePlayer( Event *ev )
{
	Player *usingPlayer = NULL;
	Equipment *equipment = NULL;
	Entity *owner;

	if ( multiplayerManager.inMultiplayer() )
	{
		Entity *entity;

		entity = ev->GetEntity( 1 );

		if ( entity->isSubclassOf( Player ) )
		{
			usingPlayer = (Player *)entity;
		}
		else if ( entity->isSubclassOf( Equipment ) )
		{
			equipment = (Equipment *)entity;

			owner = equipment->GetOwner();

			if ( owner && owner->isSubclassOf( Player ) )
			{
				usingPlayer = (Player *)owner;
			}
		}

		multiplayerManager.playerUsed( this, usingPlayer, equipment );
	}
}


//-----------------------------------------------------
//
// Name:		addRosterTeammate1
// Class:		Player
//
// Description:	Sets the third teammate in the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::addRosterTeammate1( Event* ev )
{
}


//-----------------------------------------------------
//
// Name:		addRosterTeammate2
// Class:		Player
//
// Description:	Adds the second teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::addRosterTeammate2( Event* ev )
{
}


//-----------------------------------------------------
//
// Name:		addRosterTeammate3
// Class:		Player
//
// Description:	Adds the third teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::addRosterTeammate3( Event* ev )
{

}


//-----------------------------------------------------
//
// Name:		addRosterTeammate4
// Class:		Player
//
// Description:	Adds the fourth teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::addRosterTeammate4( Event* ev )
{

}


//-----------------------------------------------------
//
// Name:		removeRosterTeammate1
// Class:		Player
//
// Description:	Removes the first teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::removeRosterTeammate1( Event* ev )
{
}


//-----------------------------------------------------
//
// Name:		removeRosterTeammate2
// Class:		Player
//
// Description:	Removes the second teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::removeRosterTeammate2( Event* ev )
{
}


//-----------------------------------------------------
//
// Name:		removeRosterTeammate3
// Class:		Player
//
// Description:	Removes the third teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::removeRosterTeammate3( Event* ev )
{
}


//-----------------------------------------------------
//
// Name:		removeRosterTeammate4
// Class:		Player
//
// Description:	Removes the fourth teammate from the roster.
//
// Parameters:	ev
//
// Returns:		None
//-----------------------------------------------------
void Player::removeRosterTeammate4( Event* ev )
{
}


bool Player::isButtonDown( int button )
{
	if ( last_ucmd.buttons & button )
		return true;
	else
		return false;
}

void Player::notifyPlayerOfMultiplayerEvent( const char *eventName, const char *eventItemName, Player *eventPlayer )
{
	// Put stuff here :)
}

void Player::touchingLadder( Trigger *ladder, const Vector &normal, float top )
{
	// Make sure we are allowed to get on the ladder time wise

	if ( level.time < _nextLadderTime )
		return;

	// If we are near the top of the ladder and we have a groundentity don't get on the ladder

	if ( groundentity && origin.z > top - 48 )
		return;

	// Save off all necessary info

	_onLadder = true;
	_ladderNormal = normal;
	_ladderTop = top;
}

void Player::warp( Event *ev )
{
	setOrigin( ev->GetVector( 1 ) );
	NoLerpThisFrame();
	client->ps.pm_flags |= PMF_TIME_TELEPORT;
	CameraCut();
}

void Player::hudPrint( Event *ev )
{
	hudPrint( ev->GetString( 1 ) );
}

void Player::hudPrint( const str &string )
{
	str command;

	// Build the hud print command to send to the client

	command = "hudprint \"";
	command += string;
	command += "\"\n";

	// Send the HUD print command

	gi.SendServerCommand( edict - g_entities, command.c_str() );
}

void Player::setItemText( int itemIcon, const str &itemText )
{
	CancelEventsOfType( EV_Player_ClearItemText );

	_itemIcon = itemIcon;
	_itemText = itemText;

	PostEvent( EV_Player_ClearItemText, 2.0f );
}

void Player::clearItemText( void )
{
	_itemIcon = 0;
	_itemText = "";

	CancelEventsOfType( EV_Player_ClearItemText );
}

void Player::clearItemText( Event *ev )
{
	clearItemText();
}

void Player::shotFired( void )
{
	if ( p_heuristics )
	{
		p_heuristics->IncrementShotsFired();
	}
	
	++client->ps.stats[ STAT_SHOTS_FIRED ];

}

void Player::shotHit( void )
{
	if ( p_heuristics )
	{
		p_heuristics->IncrementShotsHit();
	}

	++client->ps.stats[ STAT_SHOTS_HIT ];
}


void Player::cinematicStarted( void )
{

	// Turn off any viewmodes

	setViewMode( "normal" );

	// Kill the zoom if any

	Weapon *weapon = GetActiveWeapon( WEAPON_DUAL );

	if ( weapon )
	{
		weapon->ProcessEvent( "endZoom" );

		// Force the weapon to idle

		weapon->ForceIdle();
	}
}

void Player::cinematicStopped( void )
{
	Weapon *weapon;
	Equipment *equipment;

	weapon = GetActiveWeapon( WEAPON_DUAL );

	if ( weapon && weapon->isSubclassOf( Equipment ) )
	{
		equipment = (Equipment *)weapon;

		equipment->updateMode();
	}

	// Force the player's state back to idle

	SetAnim( "stand_idle", legs, true );
	SetAnim( "stand_idle", torso, true );
	LoadStateTable();
}

void Player::loadUseItem( const str &item )
{
	Event *event;
	str itemName;

	itemName = item;

	if ( stricmp( item.c_str(), "tricorder" ) == 0 )
	{
		if ( HasItem( "Tricorder-stx" ) )
			itemName = "Tricorder-stx";
		else if ( HasItem( "Tricorder-rom" ) )
			itemName = "Tricorder-rom";
	}

	if ( itemName.length() )
	{
		event = new Event( EV_Player_UseItem );
		event->AddString( itemName );
		ProcessEvent( event );
	}
}

void Player::setValidPlayerModel( Event *ev )
{
	_validPlayerModel = true;
}

void Player::setVoteText( const str &voteText )
{
	_voteText = voteText;
}

void Player::clearVoteText( void )
{
	_voteText = "";
}

void Player::incrementSecretsFound( void )
{
	_secretsFound++;

	// Update the cvar if we are greater

	if ( _secretsFound > g_secretCount->integer )
	{
		gi.cvar_set( "g_secretCount", va( "%d", _secretsFound ) );
	}
}

void Player::addHud( Event *ev )
{
	addHud( ev->GetString( 1 ) );
}

void Player::addHud( const str &hudName )
{
	if ( !_hudList.ObjectInList( hudName ) )
	{
		addHudToClient( hudName );

		_hudList.AddObject( hudName );
	}
}

void Player::removeHud( Event *ev )
{
	removeHud( ev->GetString( 1 ) );
}

void Player::removeHud( const str &hudName )
{
	if ( _hudList.ObjectInList( hudName ) )
	{
		removeHudFromClient( hudName );

		_hudList.RemoveObject( hudName );
	}
}

bool Player::needToSendAllHudsToClient( void )
{
	if ( _needToSendHuds && _started )
		return true;
	else
		return false;
}

void Player::sendAllHudsToClient( void )
{
	int i;
	str commandString;
	str hudName;

	if ( _needToSendHuds )
	{
		for( i = 1 ; i <= _hudList.NumObjects() ; i++ )
		{
			hudName = _hudList.ObjectAt( i );

			addHudToClient( hudName );
		}
	}

	_needToSendHuds = false;
}

void Player::clearAllHuds( void )
{
	int i;
	str commandString;
	str hudName;

	for( i = 1 ; i <= _hudList.NumObjects() ; i++ )
	{
		hudName = _hudList.ObjectAt( i );

		removeHudFromClient( hudName );
	}

	_hudList.ClearObjectList();
}

void Player::addHudToClient( const str &hudName )
{
	str commandString;

	commandString = "stufftext \"ui_addhud ";
	commandString += hudName;
	commandString += "\"\n";

	gi.SendServerCommand( entnum, commandString.c_str() );
}

void Player::removeHudFromClient( const str &hudName )
{
	str commandString;

	commandString = "stufftext \"ui_removehud ";
	commandString += hudName;
	commandString += "\"\n";

	gi.SendServerCommand( entnum, commandString.c_str() );
}

void Player::killAllDialog( Event *ev )
{
	killAllDialog();
}

void Player::killAllDialog()
{
	Actor *theActor;
	int i;

	for ( i = 1; i <= SleepList.NumObjects(); i++ )
		{
		theActor = (Actor*)SleepList.ObjectAt( i );
		theActor->StopDialog();
		}		

	for ( i = 1; i <= ActiveList.NumObjects(); i++ )
		{
		theActor = (Actor*)ActiveList.ObjectAt( i );
		theActor->StopDialog();
		}
}

void Player::clearTempAttachments( void )
{
	int i;
	Entity *child;

	if ( bind_info )
	{
		for( i = 0; i < MAX_MODEL_CHILDREN ; i++ )
		{
			if ( bind_info->children[ i ] == ENTITYNUM_NONE )
				continue;

			child = ( Entity * )G_GetEntity( bind_info->children[ i ] );

			if ( child )
			{
				if ( child->isSubclassOf( Projectile ) || child->CancelEventsOfType( EV_Remove ) )
				{
					child->PostEvent( EV_Remove, 0.0f );			
				}
			}
		}
	}
}

void Player::setSkill( int skill )
{
	_skillLevel = skill;

	if ( _skillLevel < 0 )
		_skillLevel = 0;
	else if ( _skillLevel > 3 )
		_skillLevel = 3;


}

int Player::getSkill( void )
{
	return _skillLevel;
}

void Player::forceMoveType( Event *ev )
{
	str moveTypeName;

	moveTypeName = ev->GetString( 1 );

	if ( stricmp( moveTypeName, "secret" ) == 0 )
		_forcedMoveType = PM_SECRET_MOVE_MODE;
	else if ( stricmp( moveTypeName, "3rdPerson" ) == 0 )
		_forcedMoveType = PM_3RD_PERSON;
	else if ( stricmp( moveTypeName, "none" ) == 0 )
		_forcedMoveType = PM_NONE;
}

void Player::isPlayerOnGround( Event *ev )
{
	float onGround;

	if ( client->ps.walking ) 
		{
		onGround = 1.0f;
		}
	else
		{
		onGround = 0.0f;
		}


	ev->ReturnFloat( onGround );
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::setBranchDialogActor( const Actor* actor)
{
	if( _branchDialogActor != 0)
		_branchDialogActor->clearBranchDialog();

	_branchDialogActor = (Actor*)actor;
}


//-----------------------------------------------------
//
// Name:		
// Class:		
//
// Description:	
//
// Parameters:	
//
// Returns:		
//-----------------------------------------------------
void Player::clearBranchDialogActor( void )
{
	if( _branchDialogActor != 0)
		_branchDialogActor->clearBranchDialog( );

	_branchDialogActor = 0;
}

void Player::setBackpackAttachOffset( Event *ev )
{
	_backpackAttachOffset = ev->GetVector( 1 );
}

void Player::setBackpackAttachAngles( Event *ev )
{
	_backpackAttachAngles = ev->GetVector( 1 );
}

Vector Player::getBackpackAttachOffset( void )
{
	return _backpackAttachOffset;
}

Vector Player::getBackpackAttachAngles( void )
{
	return _backpackAttachAngles;
}

void Player::setFlagAttachOffset( Event *ev )
{
	_flagAttachOffset = ev->GetVector( 1 );
}

void Player::setFlagAttachAngles( Event *ev )
{
	_flagAttachAngles = ev->GetVector( 1 );
}

Vector Player::getFlagAttachOffset( void )
{
	return _flagAttachOffset;
}

Vector Player::getFlagAttachAngles( void )
{
	return _flagAttachAngles;
}

bool Player::canRegenerate( void )
{
	if ( _powerup && !_powerup->canOwnerRegenerate() )
		return false;

	if ( _rune && !_rune->canOwnerRegenerate() )
		return false;

	return true;
}

void Player::modelChanged( void )
{
	if ( _powerup )
	{
		removePowerupEffect( _powerup );
		addPowerupEffect( _powerup );
	}

	if ( _rune )
	{
		removePowerupEffect( _rune );
		addPowerupEffect( _rune );
	}
}

void Player::setBackupModel( Event *ev )
{
	setBackupModel( ev->GetString( 1 ) );
}

void Player::setBackupModel( const str &modelName )
{
	gi.setviewmodel( edict, modelName );
}
