mirror of
https://github.com/Gigaslav/HL2Overcharged.git
synced 2026-01-05 06:10:21 +03:00
11801 lines
308 KiB
C++
11801 lines
308 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
//
|
||
// Purpose: Functions dealing with the player.
|
||
//
|
||
//===========================================================================//
|
||
|
||
#include "cbase.h"
|
||
#include "const.h"
|
||
#include "baseplayer_shared.h"
|
||
#include "trains.h"
|
||
#include "soundent.h"
|
||
#include "gib.h"
|
||
#include "shake.h"
|
||
#include "decals.h"
|
||
#include "gamerules.h"
|
||
#include "game.h"
|
||
#include "entityapi.h"
|
||
#include "entitylist.h"
|
||
#include "eventqueue.h"
|
||
#include "worldsize.h"
|
||
#include "isaverestore.h"
|
||
#include "globalstate.h"
|
||
#include "basecombatweapon.h"
|
||
#include "ai_basenpc.h"
|
||
#include "ai_network.h"
|
||
#include "ai_node.h"
|
||
#include "ai_networkmanager.h"
|
||
#include "ammodef.h"
|
||
#include "mathlib/mathlib.h"
|
||
#include "ndebugoverlay.h"
|
||
#include "baseviewmodel.h"
|
||
#include "in_buttons.h"
|
||
#include "client.h"
|
||
#include "team.h"
|
||
#include "particle_smokegrenade.h"
|
||
#include "particle_parse.h"//OverCharged
|
||
#include "IEffects.h"
|
||
#include "vstdlib/random.h"
|
||
#include "engine/IEngineSound.h"
|
||
#include "movehelper_server.h"
|
||
#include "igamemovement.h"
|
||
#include "saverestoretypes.h"
|
||
#include "iservervehicle.h"
|
||
#include "movevars_shared.h"
|
||
#include "vcollide_parse.h"
|
||
#include "player_command.h"
|
||
#include "vehicle_base.h"
|
||
#include "AI_Criteria.h"
|
||
#include "globals.h"
|
||
#include "usermessages.h"
|
||
#include "gamevars_shared.h"
|
||
#include "world.h"
|
||
#include "physobj.h"
|
||
#include "KeyValues.h"
|
||
#include "coordsize.h"
|
||
#include "vphysics/player_controller.h"
|
||
#include "saverestore_utlvector.h"
|
||
#include "hltvdirector.h"
|
||
#include "nav_mesh.h"
|
||
#include "env_zoom.h"
|
||
#include "rumble_shared.h"
|
||
#include "gamestats.h"
|
||
#include "npcevent.h"
|
||
#include "datacache/imdlcache.h"
|
||
#include "hintsystem.h"
|
||
#include "env_debughistory.h"
|
||
#include "fogcontroller.h"
|
||
#include "gameinterface.h"
|
||
#include "hl2orange.spa.h"
|
||
#include "dt_utlvector_send.h"
|
||
#include "vote_controller.h"
|
||
#include "ai_speech.h"
|
||
#include "utlvector.h"
|
||
#include "soundenvelope.h"
|
||
#if defined USES_ECON_ITEMS
|
||
#include "econ_wearable.h"
|
||
#endif
|
||
|
||
// NVNT haptic utils
|
||
#include "haptics/haptic_utils.h"
|
||
#include "hl2_player.h"
|
||
#ifdef HL2_DLL
|
||
#include "combine_mine.h"
|
||
#include "weapon_physcannon.h"
|
||
#endif
|
||
|
||
|
||
|
||
ConVar autoaim_max_dist("autoaim_max_dist", "2160"); // 2160 = 180 feet
|
||
ConVar autoaim_max_deflect("autoaim_max_deflect", "0.99");
|
||
|
||
#ifdef CSTRIKE_DLL
|
||
ConVar spec_freeze_time("spec_freeze_time", "5.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam.");
|
||
ConVar spec_freeze_traveltime("spec_freeze_traveltime", "0.7", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0);
|
||
#else
|
||
ConVar spec_freeze_time("spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam.");
|
||
ConVar spec_freeze_traveltime("spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0);
|
||
#endif
|
||
|
||
ConVar sv_bonus_challenge("sv_bonus_challenge", "0", FCVAR_REPLICATED, "Set to values other than 0 to select a bonus map challenge type.");
|
||
|
||
static ConVar sv_maxusrcmdprocessticks("sv_maxusrcmdprocessticks", "24", FCVAR_NOTIFY, "Maximum number of client-issued usrcmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions");
|
||
|
||
// memdbgon must be the last include file in a .cpp file!!!
|
||
#include "tier0/memdbgon.h"
|
||
|
||
static ConVar old_armor("player_old_armor", "0");
|
||
|
||
static ConVar physicsshadowupdate_render("physicsshadowupdate_render", "0");
|
||
bool IsInCommentaryMode(void);
|
||
bool IsListeningToCommentary(void);
|
||
|
||
#if !defined( CSTRIKE_DLL )
|
||
ConVar cl_sidespeed("cl_sidespeed", "450", FCVAR_REPLICATED | FCVAR_CHEAT);
|
||
ConVar cl_upspeed("cl_upspeed", "320", FCVAR_REPLICATED | FCVAR_CHEAT);
|
||
ConVar cl_forwardspeed("cl_forwardspeed", "450", FCVAR_REPLICATED | FCVAR_CHEAT);
|
||
ConVar cl_backspeed("cl_backspeed", "450", FCVAR_REPLICATED | FCVAR_CHEAT);
|
||
#endif // CSTRIKE_DLL
|
||
|
||
// This is declared in the engine, too
|
||
ConVar sv_noclipduringpause("sv_noclipduringpause", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "If cheats are enabled, then you can noclip with the game paused (for doing screenshots, etc.).");
|
||
|
||
extern ConVar sv_maxunlag;
|
||
extern ConVar sv_turbophysics;
|
||
extern ConVar *sv_maxreplay;
|
||
|
||
/*extern ConVar *hl2_walkspeed;
|
||
extern ConVar *hl2_normspeed;
|
||
extern ConVar *hl2_sprintspeed;*/
|
||
|
||
extern CServerGameDLL g_ServerGameDLL;
|
||
|
||
// TIME BASED DAMAGE AMOUNT
|
||
// tweak these values based on gameplay feedback:
|
||
#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage
|
||
#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval
|
||
|
||
#define NERVEGAS_DURATION 2
|
||
#define NERVEGAS_DAMAGE 5.0
|
||
|
||
#define POISON_DURATION 5
|
||
#define POISON_DAMAGE 2.0
|
||
|
||
#define RADIATION_DURATION 2
|
||
#define RADIATION_DAMAGE 1.0
|
||
|
||
#define ACID_DURATION 2
|
||
#define ACID_DAMAGE 5.0
|
||
|
||
#define SLOWBURN_DURATION 2
|
||
#define SLOWBURN_DAMAGE 1.0
|
||
|
||
#define SLOWFREEZE_DURATION 2
|
||
#define SLOWFREEZE_DAMAGE 1.0
|
||
|
||
//----------------------------------------------------
|
||
// Player Physics Shadow
|
||
//----------------------------------------------------
|
||
#define VPHYS_MAX_DISTANCE 2.0
|
||
#define VPHYS_MAX_VEL 10
|
||
#define VPHYS_MAX_DISTSQR (VPHYS_MAX_DISTANCE*VPHYS_MAX_DISTANCE)
|
||
#define VPHYS_MAX_VELSQR (VPHYS_MAX_VEL*VPHYS_MAX_VEL)
|
||
|
||
|
||
extern bool g_fDrawLines;
|
||
int gEvilImpulse101;
|
||
|
||
bool gInitHUD = true;
|
||
|
||
extern void respawn(CBaseEntity *pEdict, bool fCopyCorpse);
|
||
int MapTextureTypeStepType(char chTextureType);
|
||
extern void SpawnBlood(Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
|
||
extern void AddMultiDamage(const CTakeDamageInfo &info, CBaseEntity *pEntity);
|
||
|
||
|
||
#define CMD_MOSTRECENT 0
|
||
|
||
//#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes
|
||
//#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit)
|
||
|
||
|
||
//#define PLAYER_MAX_SAFE_FALL_DIST 20// falling any farther than this many feet will inflict damage
|
||
//#define PLAYER_FATAL_FALL_DIST 60// 100% damage inflicted if player falls this many feet
|
||
//#define DAMAGE_PER_UNIT_FALLEN (float)( 100 ) / ( ( PLAYER_FATAL_FALL_DIST - PLAYER_MAX_SAFE_FALL_DIST ) * 12 )
|
||
//#define MAX_SAFE_FALL_UNITS ( PLAYER_MAX_SAFE_FALL_DIST * 12 )
|
||
|
||
// player damage adjusters
|
||
ConVar sk_player_head("sk_player_head", "2");
|
||
ConVar sk_player_chest("sk_player_chest", "1");
|
||
ConVar sk_player_stomach("sk_player_stomach", "1");
|
||
ConVar sk_player_arm("sk_player_arm", "1");
|
||
ConVar sk_player_leg("sk_player_leg", "1");
|
||
|
||
ConVar *host_timescale = NULL;
|
||
|
||
//ConVar player_usercommand_timeout( "player_usercommand_timeout", "10", 0, "After this many seconds without a usercommand from a player, the client is kicked." );
|
||
#ifdef _DEBUG
|
||
ConVar sv_player_net_suppress_usercommands("sv_player_net_suppress_usercommands", "0", FCVAR_CHEAT, "For testing usercommand hacking sideeffects. DO NOT SHIP");
|
||
#endif // _DEBUG
|
||
ConVar sv_player_display_usercommand_errors("sv_player_display_usercommand_errors", "0", FCVAR_CHEAT, "1 = Display warning when command values are out-of-range. 2 = Spew invalid ranges.");
|
||
|
||
ConVar player_debug_print_damage("player_debug_print_damage", "0", FCVAR_CHEAT, "When true, print amount and type of all damage received by player to console.");
|
||
|
||
|
||
void CC_GiveCurrentAmmo(void)
|
||
{
|
||
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
|
||
|
||
if (pPlayer)
|
||
{
|
||
CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
|
||
|
||
if (pWeapon)
|
||
{
|
||
if (pWeapon->UsesPrimaryAmmo())
|
||
{
|
||
int ammoIndex = pWeapon->GetPrimaryAmmoType();
|
||
|
||
if (ammoIndex != -1)
|
||
{
|
||
int giveAmount;
|
||
giveAmount = GetAmmoDef()->MaxCarry(ammoIndex);
|
||
pPlayer->GiveAmmo(giveAmount, GetAmmoDef()->GetAmmoOfIndex(ammoIndex)->pName);
|
||
}
|
||
}
|
||
if (pWeapon->UsesSecondaryAmmo() && pWeapon->HasSecondaryAmmo())
|
||
{
|
||
// Give secondary ammo out, as long as the player already has some
|
||
// from a presumeably natural source. This prevents players on XBox
|
||
// having Combine Balls and so forth in areas of the game that
|
||
// were not tested with these items.
|
||
int ammoIndex = pWeapon->GetSecondaryAmmoType();
|
||
|
||
if (ammoIndex != -1)
|
||
{
|
||
int giveAmount;
|
||
giveAmount = GetAmmoDef()->MaxCarry(ammoIndex);
|
||
pPlayer->GiveAmmo(giveAmount, GetAmmoDef()->GetAmmoOfIndex(ammoIndex)->pName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
static ConCommand givecurrentammo("givecurrentammo", CC_GiveCurrentAmmo, "Give a supply of ammo for current weapon..\n", FCVAR_CHEAT);
|
||
|
||
|
||
// pl
|
||
BEGIN_SIMPLE_DATADESC(CPlayerState)
|
||
// DEFINE_FIELD( netname, FIELD_STRING ), // Don't stomp player name with what's in save/restore
|
||
DEFINE_FIELD(v_angle, FIELD_VECTOR),
|
||
DEFINE_FIELD(deadflag, FIELD_BOOLEAN),
|
||
|
||
// this is always set to true on restore, don't bother saving it.
|
||
// DEFINE_FIELD( fixangle, FIELD_INTEGER ),
|
||
// DEFINE_FIELD( anglechange, FIELD_FLOAT ),
|
||
// DEFINE_FIELD( hltv, FIELD_BOOLEAN ),
|
||
// DEFINE_FIELD( replay, FIELD_BOOLEAN ),
|
||
// DEFINE_FIELD( frags, FIELD_INTEGER ),
|
||
// DEFINE_FIELD( deaths, FIELD_INTEGER ),
|
||
END_DATADESC()
|
||
|
||
// Global Savedata for player
|
||
BEGIN_DATADESC(CBasePlayer)
|
||
|
||
DEFINE_EMBEDDED(m_Local),
|
||
#if defined USES_ECON_ITEMS
|
||
DEFINE_EMBEDDED(m_AttributeList),
|
||
#endif
|
||
DEFINE_FIELD(m_bSlowMoIsEnabled, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_bNightvisionEnabled, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_flNextSlowMoTick, FIELD_TIME),
|
||
/*DEFINE_FIELD(m_bIsInSelectionMode, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_flSelectionTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_flSelectionAlpha, FIELD_TIME),*/
|
||
DEFINE_FIELD(ChangedBulletsStatment, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iSlowMoPercentage, FIELD_INTEGER),
|
||
DEFINE_UTLVECTOR(m_hTriggerSoundscapeList, FIELD_EHANDLE),
|
||
DEFINE_EMBEDDED(pl),
|
||
DEFINE_FIELD(pCurWeapon, FIELD_CLASSPTR),
|
||
DEFINE_FIELD(pCurGrenade, FIELD_CLASSPTR),
|
||
//DEFINE_UTLVECTOR(pAllGrenades, FIELD_EHANDLE),
|
||
//DEFINE_AUTO_ARRAY(pAllGrenades, FIELD_EHANDLE),
|
||
DEFINE_UTLVECTOR(pAllGrenades, FIELD_CLASSPTR),
|
||
DEFINE_UTLVECTOR(garbage, FIELD_CLASSPTR),
|
||
DEFINE_UTLVECTOR(garbageIndex, FIELD_CLASSPTR),
|
||
DEFINE_FIELD(m_bShouldDrawBloodOverlay, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_bCleanUpWeapons, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_iBloodOverlayDetailFrame, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_flNextBloodDryDisappear, FIELD_TIME),
|
||
DEFINE_FIELD(throwingStateGate, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(throwingState, FIELD_INTEGER),
|
||
DEFINE_FIELD(grenadeState, FIELD_INTEGER),
|
||
DEFINE_FIELD(grenType, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_flNextGrenadeThrow, FIELD_FLOAT),
|
||
DEFINE_FIELD(sequenceDuration, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flNextGrenadeSelect, FIELD_FLOAT),
|
||
DEFINE_FIELD(CheatsWasEnabled, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_StuckLast, FIELD_INTEGER),
|
||
DEFINE_FIELD(AllowCamAttachment, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(SpecialBodyDraw, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_nButtons, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_afButtonLast, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_afButtonPressed, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_afButtonReleased, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_afButtonDisabled, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_afButtonForced, FIELD_INTEGER),
|
||
DEFINE_FIELD(refov, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_iFOV, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iFOVStart, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_flFOVTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_flSwingEventAnimTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_iDefaultFOV, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_flVehicleViewFOV, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_bIsRunning, FIELD_BOOLEAN),
|
||
//DEFINE_FIELD(m_bIsSighted, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(clearDecals, FIELD_BOOLEAN),
|
||
//DEFINE_FIELD( m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore
|
||
DEFINE_FIELD(m_iObserverMode, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iObserverLastMode, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_hObserverTarget, FIELD_EHANDLE),
|
||
DEFINE_FIELD(m_bForcedObserverMode, FIELD_BOOLEAN),
|
||
DEFINE_AUTO_ARRAY(m_szAnimExtension, FIELD_CHARACTER),
|
||
// DEFINE_CUSTOM_FIELD( m_Activity, ActivityDataOps() ),
|
||
|
||
DEFINE_FIELD(m_nUpdateRate, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_fLerpTime, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_bLagCompensation, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_bPredictWeapons, FIELD_BOOLEAN),
|
||
|
||
DEFINE_FIELD(m_vecAdditionalPVSOrigin, FIELD_POSITION_VECTOR),
|
||
DEFINE_FIELD(m_vecCameraPVSOrigin, FIELD_POSITION_VECTOR),
|
||
DEFINE_FIELD(CanDropGarbage, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_hUseEntity, FIELD_EHANDLE),
|
||
DEFINE_FIELD(m_iTrain, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iRespawnFrames, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_afPhysicsFlags, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_hVehicle, FIELD_EHANDLE),
|
||
// recreate, don't restore
|
||
// DEFINE_FIELD( m_CommandContext, CUtlVector < CCommandContext > ),
|
||
//DEFINE_FIELD( m_pPhysicsController, FIELD_POINTER ),
|
||
//DEFINE_FIELD( m_pShadowStand, FIELD_POINTER ),
|
||
//DEFINE_FIELD( m_pShadowCrouch, FIELD_POINTER ),
|
||
//DEFINE_FIELD( m_vphysicsCollisionState, FIELD_INTEGER ),
|
||
DEFINE_ARRAY(m_szNetworkIDString, FIELD_CHARACTER, MAX_NETWORKID_LENGTH),
|
||
DEFINE_FIELD(m_oldOrigin, FIELD_POSITION_VECTOR),
|
||
DEFINE_FIELD(m_vecSmoothedVelocity, FIELD_VECTOR),
|
||
//DEFINE_FIELD( m_touchedPhysObject, FIELD_BOOLEAN ),
|
||
//DEFINE_FIELD( m_bPhysicsWasFrozen, FIELD_BOOLEAN ),
|
||
//DEFINE_FIELD( m_iPlayerSound, FIELD_INTEGER ), // Don't restore, set in Precache()
|
||
DEFINE_FIELD(m_iTargetVolume, FIELD_INTEGER),
|
||
DEFINE_AUTO_ARRAY(m_rgItems, FIELD_INTEGER),
|
||
//DEFINE_FIELD( m_fNextSuicideTime, FIELD_TIME ),
|
||
// DEFINE_FIELD( m_PlayerInfo, CPlayerInfo ),
|
||
|
||
DEFINE_FIELD(m_flSwimTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_flDuckTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_flDuckJumpTime, FIELD_TIME),
|
||
|
||
DEFINE_FIELD(m_flSuitUpdate, FIELD_TIME),
|
||
DEFINE_AUTO_ARRAY(m_rgSuitPlayList, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iSuitPlayNext, FIELD_INTEGER),
|
||
DEFINE_AUTO_ARRAY(m_rgiSuitNoRepeat, FIELD_INTEGER),
|
||
DEFINE_AUTO_ARRAY(m_rgflSuitNoRepeatTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_bPauseBonusProgress, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_iBonusProgress, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iBonusChallenge, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_lastDamageAmount, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_tbdPrev, FIELD_TIME),
|
||
DEFINE_FIELD(m_flStepSoundTime, FIELD_FLOAT),
|
||
DEFINE_ARRAY(m_szNetname, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH),
|
||
|
||
//DEFINE_FIELD( m_flgeigerRange, FIELD_FLOAT ), // Don't restore, reset in Precache()
|
||
//DEFINE_FIELD( m_flgeigerDelay, FIELD_FLOAT ), // Don't restore, reset in Precache()
|
||
//DEFINE_FIELD( m_igeigerRangePrev, FIELD_FLOAT ), // Don't restore, reset in Precache()
|
||
//DEFINE_FIELD( m_iStepLeft, FIELD_INTEGER ), // Don't need to restore
|
||
//DEFINE_FIELD( m_chTextureType, FIELD_CHARACTER ), // Don't need to restore
|
||
//DEFINE_FIELD( m_surfaceProps, FIELD_INTEGER ), // don't need to restore, reset by gamemovement
|
||
// DEFINE_FIELD( m_pSurfaceData, surfacedata_t* ),
|
||
//DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ),
|
||
//DEFINE_FIELD( m_chPreviousTextureType, FIELD_CHARACTER ),
|
||
|
||
DEFINE_FIELD(m_idrowndmg, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_idrownrestored, FIELD_INTEGER),
|
||
|
||
DEFINE_FIELD(m_nPoisonDmg, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_nPoisonRestored, FIELD_INTEGER),
|
||
|
||
DEFINE_FIELD(m_bitsHUDDamage, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_fInitHUD, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_flDeathTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_flDeathAnimTime, FIELD_TIME),
|
||
|
||
//DEFINE_FIELD( m_fGameHUDInitialized, FIELD_BOOLEAN ), // only used in multiplayer games
|
||
//DEFINE_FIELD( m_fWeapon, FIELD_BOOLEAN ), // Don't restore, client needs reset
|
||
//DEFINE_FIELD( m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore
|
||
//DEFINE_FIELD( m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset
|
||
//DEFINE_FIELD( m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset
|
||
//DEFINE_FIELD( m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed
|
||
//DEFINE_FIELD( m_lastx, FIELD_INTEGER ),
|
||
//DEFINE_FIELD( m_lasty, FIELD_INTEGER ),
|
||
DEFINE_FIELD(WasFreeAim, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(WasFreeAim2, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(WasHolster, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_iFrags, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iDeaths, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_bAllowInstantSpawn, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_flNextDecalTime, FIELD_TIME),
|
||
//DEFINE_AUTO_ARRAY( m_szTeamName, FIELD_STRING ), // mp
|
||
|
||
//DEFINE_FIELD( m_iConnected, FIELD_INTEGER ),
|
||
// from edict_t
|
||
DEFINE_FIELD(m_ArmorValue, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_DmgOrigin, FIELD_VECTOR),
|
||
DEFINE_FIELD(m_DmgTake, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_DmgSave, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_AirFinished, FIELD_TIME),
|
||
DEFINE_FIELD(m_PainFinished, FIELD_TIME),
|
||
|
||
DEFINE_FIELD(m_iPlayerLocked, FIELD_INTEGER),
|
||
|
||
DEFINE_AUTO_ARRAY(m_hViewModel, FIELD_EHANDLE),
|
||
|
||
DEFINE_FIELD(m_flMaxspeed, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flWaterJumpTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_vecWaterJumpVel, FIELD_VECTOR),
|
||
DEFINE_FIELD(m_nImpulse, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_flSwimSoundTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_vecLadderNormal, FIELD_VECTOR),
|
||
|
||
DEFINE_FIELD(m_flFlashTime, FIELD_TIME),
|
||
DEFINE_FIELD(m_nDrownDmgRate, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_iSuicideCustomKillFlags, FIELD_INTEGER),
|
||
|
||
// NOT SAVED
|
||
//DEFINE_FIELD( m_vForcedOrigin, FIELD_VECTOR ),
|
||
//DEFINE_FIELD( m_bForceOrigin, FIELD_BOOLEAN ),
|
||
//DEFINE_FIELD( m_nTickBase, FIELD_INTEGER ),
|
||
//DEFINE_FIELD( m_LastCmd, FIELD_ ),
|
||
// DEFINE_FIELD( m_pCurrentCommand, CUserCmd ),
|
||
//DEFINE_FIELD( m_bGamePaused, FIELD_BOOLEAN ),
|
||
// DEFINE_FIELD( m_iVehicleAnalogBias, FIELD_INTEGER ),
|
||
|
||
// m_flVehicleViewFOV
|
||
// m_vecVehicleViewOrigin
|
||
// m_vecVehicleViewAngles
|
||
// m_nVehicleViewSavedFrame
|
||
|
||
DEFINE_FIELD(m_bitsDamageType, FIELD_INTEGER),
|
||
DEFINE_AUTO_ARRAY(m_rgbTimeBasedDamage, FIELD_CHARACTER),
|
||
DEFINE_FIELD(m_fLastPlayerTalkTime, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_hLastWeapon, FIELD_EHANDLE),
|
||
|
||
#if !defined( NO_ENTITY_PREDICTION )
|
||
// DEFINE_FIELD( m_SimulatedByThisPlayer, CUtlVector < CHandle < CBaseEntity > > ),
|
||
#endif
|
||
|
||
DEFINE_FIELD(m_flOldPlayerZ, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flOldPlayerViewOffsetZ, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_bPlayerUnderwater, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_hViewEntity, FIELD_EHANDLE),
|
||
|
||
DEFINE_FIELD(m_hConstraintEntity, FIELD_EHANDLE),
|
||
DEFINE_FIELD(m_vecConstraintCenter, FIELD_VECTOR),
|
||
DEFINE_FIELD(m_flConstraintRadius, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flConstraintWidth, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flConstraintSpeedFactor, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_hZoomOwner, FIELD_EHANDLE),
|
||
|
||
DEFINE_FIELD(m_flLaggedMovementValue, FIELD_FLOAT),
|
||
|
||
DEFINE_FIELD(m_vNewVPhysicsPosition, FIELD_VECTOR),
|
||
DEFINE_FIELD(m_vNewVPhysicsVelocity, FIELD_VECTOR),
|
||
|
||
DEFINE_FIELD(m_bSinglePlayerGameEnding, FIELD_BOOLEAN),
|
||
DEFINE_ARRAY(m_szLastPlaceName, FIELD_CHARACTER, MAX_PLACE_NAME_LENGTH),
|
||
|
||
DEFINE_FIELD(m_autoKickDisabled, FIELD_BOOLEAN),
|
||
|
||
// Function Pointers
|
||
DEFINE_FUNCTION(PlayerDeathThink),
|
||
|
||
// Inputs
|
||
DEFINE_INPUTFUNC(FIELD_INTEGER, "SetHealth", InputSetHealth),
|
||
DEFINE_INPUTFUNC(FIELD_BOOLEAN, "SetHUDVisibility", InputSetHUDVisibility),
|
||
DEFINE_INPUTFUNC(FIELD_STRING, "SetFogController", InputSetFogController),
|
||
DEFINE_INPUTFUNC(FIELD_STRING, "HandleMapEvent", InputHandleMapEvent),
|
||
|
||
DEFINE_FIELD(m_nNumCrouches, FIELD_INTEGER),
|
||
DEFINE_FIELD(m_bDuckToggled, FIELD_BOOLEAN),
|
||
DEFINE_FIELD(m_flForwardMove, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_flSideMove, FIELD_FLOAT),
|
||
DEFINE_FIELD(m_vecPreviouslyPredictedOrigin, FIELD_POSITION_VECTOR),
|
||
|
||
DEFINE_FIELD(m_nNumCrateHudHints, FIELD_INTEGER),
|
||
|
||
// DEFINE_FIELD( m_nBodyPitchPoseParam, FIELD_INTEGER ),
|
||
// DEFINE_ARRAY( m_StepSoundCache, StepSoundCache_t, 2 ),
|
||
|
||
// DEFINE_UTLVECTOR( m_vecPlayerCmdInfo ),
|
||
// DEFINE_UTLVECTOR( m_vecPlayerSimInfo ),
|
||
END_DATADESC()
|
||
|
||
int giPrecacheGrunt = 0;
|
||
|
||
edict_t *CBasePlayer::s_PlayerEdict = NULL;
|
||
|
||
|
||
inline bool ShouldRunCommandsInContext(const CCommandContext *ctx)
|
||
{
|
||
// TODO: This should be enabled at some point. If usercmds can run while paused, then
|
||
// they can create entities which will never die and it will fill up the entity list.
|
||
#ifdef NO_USERCMDS_DURING_PAUSE
|
||
return !ctx->paused || sv_noclipduringpause.GetInt();
|
||
#else
|
||
return true;
|
||
#endif
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : CBaseViewModel
|
||
//-----------------------------------------------------------------------------
|
||
CBaseViewModel *CBasePlayer::GetViewModel(int index /*= 0*/, bool bObserverOK, bool DefRenderGroup)
|
||
{
|
||
Assert(index >= 0 && index < MAX_VIEWMODELS);
|
||
|
||
/*if (m_hViewModel[index].Get())
|
||
{
|
||
if (DefRenderGroup)
|
||
m_hViewModel[index].Get()->m_bDefRenderGroup = true;
|
||
else
|
||
m_hViewModel[index].Get()->m_bDefRenderGroup = false;
|
||
}*/
|
||
return m_hViewModel[index].Get();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::CreateViewModel(int index /*=0*/, bool DefRenderGroup)
|
||
{
|
||
Assert(index >= 0 && index < MAX_VIEWMODELS);
|
||
|
||
if (GetViewModel(index))
|
||
return;
|
||
|
||
CBaseViewModel *vm = (CBaseViewModel *)CreateEntityByName("viewmodel");
|
||
if (vm)
|
||
{
|
||
vm->SetAbsOrigin(GetAbsOrigin());
|
||
vm->SetOwner(this);
|
||
vm->SetIndex(index);
|
||
DispatchSpawn(vm);
|
||
vm->FollowEntity(this);
|
||
m_hViewModel.Set(index, vm);
|
||
|
||
if (DefRenderGroup)
|
||
vm->m_bDefRenderGroup = true;
|
||
else
|
||
vm->m_bDefRenderGroup = false;
|
||
}
|
||
}
|
||
|
||
// BriJee OVR: C_ arms aka custom hands method
|
||
/*void CBasePlayer::CreateHandModel(int index, int iOtherVm)
|
||
{
|
||
Assert(index >= 0 && index < MAX_VIEWMODELS && iOtherVm >= 0 && iOtherVm < MAX_VIEWMODELS);
|
||
|
||
if (GetViewModel(index))
|
||
return;
|
||
|
||
CBaseViewModel *vm = (CBaseViewModel *)CreateEntityByName("hand_viewmodel");
|
||
if (vm)
|
||
{
|
||
vm->SetAbsOrigin(GetAbsOrigin());
|
||
vm->SetOwner(this);
|
||
vm->SetIndex(index);
|
||
DispatchSpawn(vm);
|
||
vm->FollowEntity(GetViewModel(iOtherVm), true);
|
||
m_hViewModel.Set(index, vm);
|
||
}
|
||
}*/
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::DestroyViewModels(void)
|
||
{
|
||
int i;
|
||
for (i = MAX_VIEWMODELS - 1; i >= 0; i--)
|
||
{
|
||
CBaseViewModel *vm = GetViewModel(i);
|
||
if (!vm)
|
||
continue;
|
||
|
||
UTIL_Remove(vm);
|
||
m_hViewModel.Set(i, NULL);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Static member function to create a player of the specified class
|
||
// Input : *className -
|
||
// *ed -
|
||
// Output : CBasePlayer
|
||
//-----------------------------------------------------------------------------
|
||
CBasePlayer *CBasePlayer::CreatePlayer(const char *className, edict_t *ed)
|
||
{
|
||
CBasePlayer *player;
|
||
CBasePlayer::s_PlayerEdict = ed;
|
||
player = (CBasePlayer *)CreateEntityByName(className);
|
||
return player;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CBasePlayer::CBasePlayer()
|
||
{
|
||
AddEFlags(EFL_NO_AUTO_EDICT_ATTACH);
|
||
clearDecals = false;
|
||
m_bCleanUpWeapons = false;
|
||
m_bIsRunning = false;
|
||
//m_bIsSighted = false;
|
||
host_timescale = g_pCVar->FindVar("host_timescale");
|
||
//MikeD SlowMo
|
||
//engine->ServerCommand("Server_HideSelection\n");
|
||
m_bIsInSelectionMode = false;
|
||
m_flSelectionAlpha = 0;
|
||
m_bSlowMoIsEnabled = false;
|
||
m_bSlowMoIsEnabledTemp = false;
|
||
|
||
m_bNightvisionEnabled = false;
|
||
m_flNextSlowMoTick = 0.0f;
|
||
ChangedBulletsStatment = 0;
|
||
m_iSlowMoPercentage = 100;
|
||
#ifdef _DEBUG
|
||
m_vecAutoAim.Init();
|
||
m_vecAdditionalPVSOrigin.Init();
|
||
m_vecCameraPVSOrigin.Init();
|
||
m_DmgOrigin.Init();
|
||
m_vecLadderNormal.Init();
|
||
|
||
m_oldOrigin.Init();
|
||
m_vecSmoothedVelocity.Init();
|
||
#endif
|
||
|
||
SetupBloodOverlay(false);
|
||
SetupBloodOverlayFrame(0);
|
||
SetupBloodOverlayDelay(0.0f);
|
||
|
||
CheatsWasEnabled = false;//cvar->FindVar("sv_cheats")->GetBool();
|
||
grenType = 0;
|
||
grenadeState = 0;
|
||
throwingState = 0;
|
||
throwingStateGate = false;
|
||
if (s_PlayerEdict)
|
||
{
|
||
// take the assigned edict_t and attach it
|
||
Assert(s_PlayerEdict != NULL);
|
||
NetworkProp()->AttachEdict(s_PlayerEdict);
|
||
s_PlayerEdict = NULL;
|
||
}
|
||
m_flSwingEventAnimTime = 0.f;
|
||
refov = false;
|
||
m_flFlashTime = -1;
|
||
pl.fixangle = FIXANGLE_ABSOLUTE;
|
||
pl.hltv = false;
|
||
pl.replay = false;
|
||
pl.frags = 0;
|
||
pl.deaths = 0;
|
||
|
||
m_szNetname[0] = '\0';
|
||
|
||
m_iHealth = 0;
|
||
Weapon_SetLast(NULL);
|
||
m_bitsDamageType = 0;
|
||
|
||
m_bForceOrigin = false;
|
||
m_hVehicle = NULL;
|
||
m_pCurrentCommand = NULL;
|
||
|
||
// Setup our default FOV
|
||
m_iDefaultFOV = g_pGameRules->DefaultFOV();
|
||
|
||
m_hZoomOwner = NULL;
|
||
|
||
m_nUpdateRate = 20; // cl_updaterate defualt
|
||
m_fLerpTime = 0.1f; // cl_interp default
|
||
m_bPredictWeapons = true;
|
||
m_bLagCompensation = false;
|
||
m_flLaggedMovementValue = 1.0f;
|
||
m_StuckLast = 0;
|
||
m_impactEnergyScale = 1.0f;
|
||
m_fLastPlayerTalkTime = 0.0f;
|
||
m_PlayerInfo.SetParent(this);
|
||
|
||
ResetObserverMode();
|
||
|
||
m_surfaceProps = 0;
|
||
m_pSurfaceData = NULL;
|
||
m_surfaceFriction = 1.0f;
|
||
m_chTextureType = 0;
|
||
m_chPreviousTextureType = 0;
|
||
|
||
m_iSuicideCustomKillFlags = 0;
|
||
m_fDelay = 0.0f;
|
||
m_fReplayEnd = -1;
|
||
m_iReplayEntity = 0;
|
||
|
||
m_autoKickDisabled = false;
|
||
|
||
m_nNumCrouches = 0;
|
||
m_bDuckToggled = false;
|
||
m_bPhysicsWasFrozen = false;
|
||
|
||
// Used to mask off buttons
|
||
m_afButtonDisabled = 0;
|
||
m_afButtonForced = 0;
|
||
|
||
m_nBodyPitchPoseParam = -1;
|
||
m_flForwardMove = 0;
|
||
m_flSideMove = 0;
|
||
|
||
// NVNT default to no haptics
|
||
m_bhasHaptics = false;
|
||
|
||
m_vecConstraintCenter = vec3_origin;
|
||
|
||
m_flLastUserCommandTime = 0.f;
|
||
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
|
||
|
||
CanDropGarbage = false;
|
||
}
|
||
|
||
CBasePlayer::~CBasePlayer()
|
||
{
|
||
VPhysicsDestroyObject();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::UpdateOnRemove(void)
|
||
{
|
||
VPhysicsDestroyObject();
|
||
|
||
// Remove him from his current team
|
||
if (GetTeam())
|
||
{
|
||
GetTeam()->RemovePlayer(this);
|
||
}
|
||
|
||
// Chain at end to mimic destructor unwind order
|
||
BaseClass::UpdateOnRemove();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : **pvs -
|
||
// **pas -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SetupVisibility(CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize)
|
||
{
|
||
// If we have a viewentity, we don't add the player's origin.
|
||
if (pViewEntity)
|
||
return;
|
||
|
||
Vector org;
|
||
org = EyePosition();
|
||
|
||
engine->AddOriginToPVS(org);
|
||
}
|
||
|
||
int CBasePlayer::UpdateTransmitState()
|
||
{
|
||
// always call ShouldTransmit() for players
|
||
return SetTransmitState(FL_EDICT_FULLCHECK);
|
||
}
|
||
|
||
int CBasePlayer::ShouldTransmit(const CCheckTransmitInfo *pInfo)
|
||
{
|
||
// Allow me to introduce myself to, err, myself.
|
||
// I.e., always update the recipient player data even if it's nodraw (first person mode)
|
||
if (pInfo->m_pClientEnt == edict())
|
||
{
|
||
return FL_EDICT_ALWAYS;
|
||
}
|
||
|
||
// when HLTV/Replay is connected and spectators press +USE, they
|
||
// signal that they are recording a interesting scene
|
||
// so transmit these 'cameramans' to the HLTV or Replay client
|
||
if (HLTVDirector()->GetCameraMan() == entindex())
|
||
{
|
||
CBaseEntity *pRecipientEntity = CBaseEntity::Instance(pInfo->m_pClientEnt);
|
||
|
||
Assert(pRecipientEntity->IsPlayer());
|
||
|
||
CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>(pRecipientEntity);
|
||
if (pRecipientPlayer->IsHLTV() ||
|
||
pRecipientPlayer->IsReplay())
|
||
{
|
||
// HACK force calling RecomputePVSInformation to update PVS data
|
||
NetworkProp()->AreaNum();
|
||
return FL_EDICT_ALWAYS;
|
||
}
|
||
}
|
||
|
||
// Transmit for a short time after death and our death anim finishes so ragdolls can access reliable player data.
|
||
// Note that if m_flDeathAnimTime is never set, as long as m_lifeState is set to LIFE_DEAD after dying, this
|
||
// test will act as if the death anim is finished.
|
||
if (IsEffectActive(EF_NODRAW) || (IsObserver() && (gpGlobals->curtime - m_flDeathTime > 0.5) &&
|
||
(m_lifeState == LIFE_DEAD) && (gpGlobals->curtime - m_flDeathAnimTime > 0.5)))
|
||
{
|
||
return FL_EDICT_DONTSEND;
|
||
}
|
||
|
||
return BaseClass::ShouldTransmit(pInfo);
|
||
}
|
||
|
||
|
||
bool CBasePlayer::WantsLagCompensationOnEntity(const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits) const
|
||
{
|
||
// Team members shouldn't be adjusted unless friendly fire is on.
|
||
if (!friendlyfire.GetInt() && pPlayer->GetTeamNumber() == GetTeamNumber())
|
||
return false;
|
||
|
||
// If this entity hasn't been transmitted to us and acked, then don't bother lag compensating it.
|
||
if (pEntityTransmitBits && !pEntityTransmitBits->Get(pPlayer->entindex()))
|
||
return false;
|
||
|
||
const Vector &vMyOrigin = GetAbsOrigin();
|
||
const Vector &vHisOrigin = pPlayer->GetAbsOrigin();
|
||
|
||
// get max distance player could have moved within max lag compensation time,
|
||
// multiply by 1.5 to to avoid "dead zones" (sqrt(2) would be the exact value)
|
||
float maxDistance = 1.5 * pPlayer->MaxSpeed() * sv_maxunlag.GetFloat();
|
||
|
||
// If the player is within this distance, lag compensate them in case they're running past us.
|
||
if (vHisOrigin.DistTo(vMyOrigin) < maxDistance)
|
||
return true;
|
||
|
||
// If their origin is not within a 45 degree cone in front of us, no need to lag compensate.
|
||
Vector vForward;
|
||
AngleVectors(pCmd->viewangles, &vForward);
|
||
|
||
Vector vDiff = vHisOrigin - vMyOrigin;
|
||
VectorNormalize(vDiff);
|
||
|
||
float flCosAngle = 0.707107f; // 45 degree angle
|
||
if (vForward.Dot(vDiff) < flCosAngle)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
void CBasePlayer::PauseBonusProgress(bool bPause)
|
||
{
|
||
m_bPauseBonusProgress = bPause;
|
||
}
|
||
|
||
void CBasePlayer::SetBonusProgress(int iBonusProgress)
|
||
{
|
||
if (!m_bPauseBonusProgress)
|
||
m_iBonusProgress = iBonusProgress;
|
||
}
|
||
|
||
void CBasePlayer::SetBonusChallenge(int iBonusChallenge)
|
||
{
|
||
m_iBonusChallenge = iBonusChallenge;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Sets the view angles
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SnapEyeAngles(const QAngle &viewAngles)
|
||
{
|
||
pl.v_angle = viewAngles;
|
||
pl.fixangle = FIXANGLE_ABSOLUTE;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : iSpeed -
|
||
// iMax -
|
||
// Output : int
|
||
//-----------------------------------------------------------------------------
|
||
int TrainSpeed(int iSpeed, int iMax)
|
||
{
|
||
float fSpeed, fMax;
|
||
int iRet = 0;
|
||
|
||
fMax = (float)iMax;
|
||
fSpeed = iSpeed;
|
||
|
||
fSpeed = fSpeed / fMax;
|
||
|
||
if (iSpeed < 0)
|
||
iRet = TRAIN_BACK;
|
||
else if (iSpeed == 0)
|
||
iRet = TRAIN_NEUTRAL;
|
||
else if (fSpeed < 0.33)
|
||
iRet = TRAIN_SLOW;
|
||
else if (fSpeed < 0.66)
|
||
iRet = TRAIN_MEDIUM;
|
||
else
|
||
iRet = TRAIN_FAST;
|
||
|
||
return iRet;
|
||
}
|
||
|
||
void CBasePlayer::DeathSound(const CTakeDamageInfo &info)
|
||
{
|
||
// temporarily using pain sounds for death sounds
|
||
|
||
// Did we die from falling?
|
||
if (m_bitsDamageType & DMG_FALL)
|
||
{
|
||
// They died in the fall. Play a splat sound.
|
||
EmitSound("Player.FallGib");
|
||
}
|
||
else
|
||
{
|
||
EmitSound("Player.Death");
|
||
}
|
||
|
||
// play one of the suit death alarms
|
||
if (IsSuitEquipped())
|
||
{
|
||
UTIL_EmitGroupnameSuit(edict(), "HEV_DEAD");
|
||
}
|
||
}
|
||
|
||
// override takehealth
|
||
// bitsDamageType indicates type of damage healed.
|
||
|
||
int CBasePlayer::TakeHealth(float flHealth, int bitsDamageType)
|
||
{
|
||
// clear out any damage types we healed.
|
||
// UNDONE: generic health should not heal any
|
||
// UNDONE: time-based damage
|
||
if (m_takedamage)
|
||
{
|
||
int bitsDmgTimeBased = g_pGameRules->Damage_GetTimeBased();
|
||
m_bitsDamageType &= ~(bitsDamageType & ~bitsDmgTimeBased);
|
||
}
|
||
|
||
/*SetupBloodOverlay(false);
|
||
SetupBloodOverlayDelay(0.0f);*/
|
||
|
||
// I disabled reporting history into the dbghist because it was super spammy.
|
||
// But, if you need to reenable it, the code is below in the "else" clause.
|
||
#if 1 // #ifdef DISABLE_DEBUG_HISTORY
|
||
return BaseClass::TakeHealth(flHealth, bitsDamageType);
|
||
#else
|
||
const int healingTaken = BaseClass::TakeHealth(flHealth, bitsDamageType);
|
||
char buf[256];
|
||
Q_snprintf(buf, 256, "[%f] Player %s healed for %d with damagetype %X\n", gpGlobals->curtime, GetDebugName(), healingTaken, bitsDamageType);
|
||
ADD_DEBUG_HISTORY(HISTORY_PLAYER_DAMAGE, buf);
|
||
|
||
return healingTaken;
|
||
#endif
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Draw all overlays (should be implemented in cascade by subclass to add
|
||
// any additional non-text overlays)
|
||
// Input :
|
||
// Output : Current text offset from the top
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::DrawDebugGeometryOverlays(void)
|
||
{
|
||
// --------------------------------------------------------
|
||
// If in buddha mode and dead draw lines to indicate death
|
||
// --------------------------------------------------------
|
||
if ((m_debugOverlays & OVERLAY_BUDDHA_MODE) && m_iHealth == 1)
|
||
{
|
||
Vector vBodyDir = BodyDirection2D();
|
||
Vector eyePos = EyePosition() + vBodyDir*10.0;
|
||
Vector vUp = Vector(0, 0, 8);
|
||
Vector vSide;
|
||
CrossProduct(vBodyDir, vUp, vSide);
|
||
NDebugOverlay::Line(eyePos + vSide + vUp, eyePos - vSide - vUp, 255, 0, 0, false, 0);
|
||
NDebugOverlay::Line(eyePos + vSide - vUp, eyePos - vSide + vUp, 255, 0, 0, false, 0);
|
||
}
|
||
BaseClass::DrawDebugGeometryOverlays();
|
||
}
|
||
|
||
//=========================================================
|
||
// TraceAttack
|
||
//=========================================================
|
||
void CBasePlayer::TraceAttack(const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
|
||
{
|
||
if (m_takedamage)
|
||
{
|
||
CTakeDamageInfo info = inputInfo;
|
||
|
||
if (info.GetAttacker())
|
||
{
|
||
// --------------------------------------------------
|
||
// If an NPC check if friendly fire is disallowed
|
||
// --------------------------------------------------
|
||
CAI_BaseNPC *pNPC = info.GetAttacker()->MyNPCPointer();
|
||
if (pNPC && (pNPC->CapabilitiesGet() & bits_CAP_NO_HIT_PLAYER) && pNPC->IRelationType(this) != D_HT)
|
||
return;
|
||
|
||
// Prevent team damage here so blood doesn't appear
|
||
if (info.GetAttacker()->IsPlayer())
|
||
{
|
||
if (!g_pGameRules->FPlayerCanTakeDamage(this, info.GetAttacker(), info))
|
||
return;
|
||
}
|
||
}
|
||
|
||
SetLastHitGroup(ptr->hitgroup);
|
||
|
||
|
||
switch (ptr->hitgroup)
|
||
{
|
||
case HITGROUP_GENERIC:
|
||
break;
|
||
case HITGROUP_HEAD:
|
||
info.ScaleDamage(sk_player_head.GetFloat());
|
||
break;
|
||
case HITGROUP_CHEST:
|
||
info.ScaleDamage(sk_player_chest.GetFloat());
|
||
break;
|
||
case HITGROUP_STOMACH:
|
||
info.ScaleDamage(sk_player_stomach.GetFloat());
|
||
break;
|
||
case HITGROUP_LEFTARM:
|
||
case HITGROUP_RIGHTARM:
|
||
info.ScaleDamage(sk_player_arm.GetFloat());
|
||
break;
|
||
case HITGROUP_LEFTLEG:
|
||
case HITGROUP_RIGHTLEG:
|
||
info.ScaleDamage(sk_player_leg.GetFloat());
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
#ifdef HL2_EPISODIC
|
||
// If this damage type makes us bleed, then do so
|
||
bool bShouldBleed = !g_pGameRules->Damage_ShouldNotBleed(info.GetDamageType());
|
||
if (bShouldBleed)
|
||
#endif
|
||
{
|
||
SpawnBlood(ptr->endpos, vecDir, BloodColor(), info.GetDamage());// a little surface blood.
|
||
TraceBleed(info.GetDamage(), vecDir, ptr, info.GetDamageType());
|
||
}
|
||
|
||
AddMultiDamage(info, this);
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Purpose : Do some kind of damage effect for the type of damage
|
||
// Input :
|
||
// Output :
|
||
//------------------------------------------------------------------------------
|
||
void CBasePlayer::DamageEffect(float flDamage, int fDamageType)
|
||
{
|
||
int Click;
|
||
if (fDamageType & DMG_CRUSH)
|
||
{
|
||
//Red damage indicator
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_SHOCK);
|
||
MessageEnd();
|
||
color32 red = { 128, 0, 0, 128 };
|
||
UTIL_ScreenFade(this, red, 1.0f, 0.1f, FFADE_IN);
|
||
}
|
||
else if (fDamageType & DMG_DROWN)
|
||
{
|
||
//Red damage indicator
|
||
EntityMessageBegin(this);
|
||
(PLAYER_MSG_DO_DMG_BULLET);
|
||
MessageEnd();
|
||
color32 blue = { 0, 0, 128, 128 };
|
||
UTIL_ScreenFade(this, blue, 1.0f, 0.1f, FFADE_IN);
|
||
}
|
||
else if (fDamageType & DMG_SLASH)
|
||
{
|
||
// If slash damage shoot some blood
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_BULLET);
|
||
MessageEnd();
|
||
SpawnBlood(EyePosition(), g_vecAttackDir, BloodColor(), flDamage);
|
||
}
|
||
else if (fDamageType & DMG_PLASMA)
|
||
{
|
||
// Blue screen fade
|
||
color32 blue = { 0, 0, 255, 100 };
|
||
UTIL_ScreenFade(this, blue, 0.2, 0.4, FFADE_MODULATE);
|
||
|
||
// Very small screen shake
|
||
// Both -0.1 and 0.1 map to 0 when converted to integer, so all of these RandomInt
|
||
// calls are just expensive ways of returning zero. This code has always been this
|
||
// way and has never had any value. clang complains about the conversion from a
|
||
// literal floating-point number to an integer.
|
||
//ViewPunch(QAngle(random->RandomInt(-0.1,0.1), random->RandomInt(-0.1,0.1), random->RandomInt(-0.1,0.1)));
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_BULLET);
|
||
MessageEnd();
|
||
// Burn sound
|
||
EmitSound("Player.PlasmaDamage");
|
||
}
|
||
else if (fDamageType & DMG_SONIC)
|
||
{
|
||
// Sonic damage sound
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_SHOCK);
|
||
MessageEnd();
|
||
EmitSound("Player.SonicDamage");
|
||
}
|
||
else if (fDamageType & DMG_BULLET)
|
||
{
|
||
Click = RandomInt(1, 2);
|
||
if (Click == 1)
|
||
{
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_BULLET);
|
||
MessageEnd();
|
||
}
|
||
if (Click == 2)
|
||
{
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAYER_MSG_DO_DMG_SHOCK);
|
||
MessageEnd();
|
||
}
|
||
|
||
EmitSound("Flesh.BulletImpact");
|
||
}
|
||
}
|
||
|
||
/*
|
||
Take some damage.
|
||
NOTE: each call to OnTakeDamage with bitsDamageType set to a time-based damage
|
||
type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation
|
||
etc are implemented with subsequent calls to OnTakeDamage using DMG_GENERIC.
|
||
*/
|
||
|
||
// Old values
|
||
#define OLD_ARMOR_RATIO 0.2 // Armor Takes 80% of the damage
|
||
#define OLD_ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health
|
||
|
||
// New values
|
||
#define ARMOR_RATIO 0.2
|
||
#define ARMOR_BONUS 1.0
|
||
|
||
//---------------------------------------------------------
|
||
//---------------------------------------------------------
|
||
bool CBasePlayer::ShouldTakeDamageInCommentaryMode(const CTakeDamageInfo &inputInfo)
|
||
{
|
||
// Only ignore damage when we're listening to a commentary node
|
||
if (!IsListeningToCommentary())
|
||
return true;
|
||
|
||
// Allow SetHealth inputs to kill player.
|
||
if (inputInfo.GetAttacker() && inputInfo.GetInflictor() && inputInfo.GetInflictor() == this && inputInfo.GetAttacker() == this)
|
||
return true;
|
||
|
||
#ifdef PORTAL
|
||
if (inputInfo.GetDamageType() & DMG_ACID)
|
||
return true;
|
||
#endif
|
||
|
||
// In commentary, ignore all damage except for falling and leeches
|
||
if (!(inputInfo.GetDamageType() & (DMG_BURN | DMG_PLASMA | DMG_FALL | DMG_CRUSH)) && inputInfo.GetDamageType() != DMG_GENERIC)
|
||
return false;
|
||
|
||
// We let DMG_CRUSH pass the check above so that we can check here for stress damage. Deny the CRUSH damage if there is no attacker,
|
||
// or if the attacker isn't a BSP model. Therefore, we're allowing any CRUSH damage done by a BSP model.
|
||
if ((inputInfo.GetDamageType() & DMG_CRUSH) && (inputInfo.GetAttacker() == NULL || !inputInfo.GetAttacker()->IsBSPModel()))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
int CBasePlayer::OnTakeDamage(const CTakeDamageInfo &inputInfo)
|
||
{
|
||
// have suit diagnose the problem - ie: report damage type
|
||
int bitsDamage = inputInfo.GetDamageType();
|
||
int ffound = true;
|
||
int fmajor;
|
||
int fcritical;
|
||
int fTookDamage;
|
||
int ftrivial;
|
||
float flRatio;
|
||
float flBonus;
|
||
float flHealthPrev = m_iHealth;
|
||
|
||
CTakeDamageInfo info = inputInfo;
|
||
|
||
IServerVehicle *pVehicle = GetVehicle();
|
||
if (pVehicle)
|
||
{
|
||
// Let the vehicle decide if we should take this damage or not
|
||
if (pVehicle->PassengerShouldReceiveDamage(info) == false)
|
||
return 0;
|
||
}
|
||
|
||
if (IsInCommentaryMode())
|
||
{
|
||
if (!ShouldTakeDamageInCommentaryMode(info))
|
||
return 0;
|
||
}
|
||
|
||
if (GetFlags() & FL_GODMODE)
|
||
return 0;
|
||
|
||
if (m_debugOverlays & OVERLAY_BUDDHA_MODE)
|
||
{
|
||
if ((m_iHealth - info.GetDamage()) <= 0)
|
||
{
|
||
m_iHealth = 1;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// Early out if there's no damage
|
||
if (!info.GetDamage())
|
||
return 0;
|
||
|
||
if (old_armor.GetBool())
|
||
{
|
||
flBonus = OLD_ARMOR_BONUS;
|
||
flRatio = OLD_ARMOR_RATIO;
|
||
}
|
||
else
|
||
{
|
||
flBonus = ARMOR_BONUS;
|
||
flRatio = ARMOR_RATIO;
|
||
}
|
||
|
||
if ((info.GetDamageType() & DMG_BLAST) && g_pGameRules->IsMultiplayer())
|
||
{
|
||
// blasts damage armor more.
|
||
flBonus *= 2;
|
||
}
|
||
|
||
// Already dead
|
||
if (!IsAlive())
|
||
return 0;
|
||
// go take the damage first
|
||
|
||
|
||
if (!g_pGameRules->FPlayerCanTakeDamage(this, info.GetAttacker(), inputInfo))
|
||
{
|
||
// Refuse the damage
|
||
return 0;
|
||
}
|
||
|
||
// print to console if the appropriate cvar is set
|
||
#ifdef DISABLE_DEBUG_HISTORY
|
||
if (player_debug_print_damage.GetBool() && info.GetDamage() > 0)
|
||
#endif
|
||
{
|
||
char dmgtype[64];
|
||
CTakeDamageInfo::DebugGetDamageTypeString(info.GetDamageType(), dmgtype, 512);
|
||
char outputString[256];
|
||
Q_snprintf(outputString, 256, "%f: Player %s at [%0.2f %0.2f %0.2f] took %f damage from %s, type %s\n", gpGlobals->curtime, GetDebugName(),
|
||
GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, info.GetDamage(), info.GetInflictor()->GetDebugName(), dmgtype);
|
||
|
||
//Msg( "%f: Player %s at [%0.2f %0.2f %0.2f] took %f damage from %s, type %s\n", gpGlobals->curtime, GetDebugName(),
|
||
// GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, info.GetDamage(), info.GetInflictor()->GetDebugName(), dmgtype );
|
||
|
||
ADD_DEBUG_HISTORY(HISTORY_PLAYER_DAMAGE, outputString);
|
||
#ifndef DISABLE_DEBUG_HISTORY
|
||
if (player_debug_print_damage.GetBool()) // if we're not in here just for the debug history
|
||
#endif
|
||
{
|
||
Msg("%s", outputString);
|
||
}
|
||
}
|
||
|
||
// keep track of amount of damage last sustained
|
||
m_lastDamageAmount = info.GetDamage();
|
||
|
||
// Armor.
|
||
if (m_ArmorValue && !(info.GetDamageType() & (DMG_FALL | DMG_DROWN | DMG_POISON | DMG_RADIATION)))// armor doesn't protect against fall or drown damage!
|
||
{
|
||
float flNew = info.GetDamage() * flRatio;
|
||
|
||
float flArmor;
|
||
|
||
flArmor = (info.GetDamage() - flNew) * flBonus;
|
||
|
||
if (!old_armor.GetBool())
|
||
{
|
||
if (flArmor < 1.0)
|
||
{
|
||
flArmor = 1.0;
|
||
}
|
||
}
|
||
|
||
// Does this use more armor than we have?
|
||
if (flArmor > m_ArmorValue)
|
||
{
|
||
flArmor = m_ArmorValue;
|
||
flArmor *= (1 / flBonus);
|
||
flNew = info.GetDamage() - flArmor;
|
||
m_DmgSave = m_ArmorValue;
|
||
m_ArmorValue = 0;
|
||
}
|
||
else
|
||
{
|
||
m_DmgSave = flArmor;
|
||
m_ArmorValue -= flArmor;
|
||
}
|
||
|
||
info.SetDamage(flNew);
|
||
}
|
||
|
||
|
||
#if defined( WIN32 ) && !defined( _X360 )
|
||
// NVNT if player's client has a haptic device send them a user message with the damage.
|
||
if (HasHaptics())
|
||
HapticsDamage(this, info);
|
||
#endif
|
||
|
||
// this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that
|
||
// as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc)
|
||
|
||
// NOTENOTE: jdw - We are now capable of retaining the mantissa of this damage value and deferring its application
|
||
|
||
// info.SetDamage( (int)info.GetDamage() );
|
||
|
||
// Call up to the base class
|
||
fTookDamage = BaseClass::OnTakeDamage(info);
|
||
|
||
// Early out if the base class took no damage
|
||
if (!fTookDamage)
|
||
return 0;
|
||
|
||
// add to the damage total for clients, which will be sent as a single
|
||
// message at the end of the frame
|
||
// todo: remove after combining shotgun blasts?
|
||
if (info.GetInflictor() && info.GetInflictor()->edict())
|
||
m_DmgOrigin = info.GetInflictor()->GetAbsOrigin();
|
||
|
||
m_DmgTake += (int)info.GetDamage();
|
||
|
||
// Reset damage time countdown for each type of time based damage player just sustained
|
||
for (int i = 0; i < CDMG_TIMEBASED; i++)
|
||
{
|
||
// Make sure the damage type is really time-based.
|
||
// This is kind of hacky but necessary until we setup DamageType as an enum.
|
||
int iDamage = (DMG_PARALYZE << i);
|
||
if ((info.GetDamageType() & iDamage) && g_pGameRules->Damage_IsTimeBased(iDamage))
|
||
{
|
||
m_rgbTimeBasedDamage[i] = 0;
|
||
}
|
||
}
|
||
|
||
// Display any effect associate with this damage type
|
||
DamageEffect(info.GetDamage(), bitsDamage);
|
||
|
||
// how bad is it, doc?
|
||
ftrivial = (m_iHealth > 75 || m_lastDamageAmount < 5);
|
||
fmajor = (m_lastDamageAmount > 25);
|
||
fcritical = (m_iHealth < 30);
|
||
|
||
// handle all bits set in this damage message,
|
||
// let the suit give player the diagnosis
|
||
|
||
// UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash )
|
||
|
||
// UNDONE: still need to record damage and heal messages for the following types
|
||
|
||
// DMG_BURN
|
||
// DMG_FREEZE
|
||
// DMG_BLAST
|
||
// DMG_SHOCK
|
||
|
||
m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client
|
||
m_bitsHUDDamage = -1; // make sure the damage bits get resent
|
||
|
||
while (fTookDamage && (!ftrivial || g_pGameRules->Damage_IsTimeBased(bitsDamage)) && ffound && bitsDamage)
|
||
{
|
||
ffound = false;
|
||
|
||
if (bitsDamage & DMG_CLUB)
|
||
{
|
||
if (fmajor)
|
||
SetSuitUpdate("!HEV_DMG4", false, SUIT_NEXT_IN_30SEC); // minor fracture
|
||
bitsDamage &= ~DMG_CLUB;
|
||
ffound = true;
|
||
}
|
||
if (bitsDamage & (DMG_FALL | DMG_CRUSH))
|
||
{
|
||
if (fmajor)
|
||
SetSuitUpdate("!HEV_DMG5", false, SUIT_NEXT_IN_30SEC); // major fracture
|
||
else
|
||
SetSuitUpdate("!HEV_DMG4", false, SUIT_NEXT_IN_30SEC); // minor fracture
|
||
|
||
bitsDamage &= ~(DMG_FALL | DMG_CRUSH);
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_BULLET)
|
||
{
|
||
if (m_lastDamageAmount > 5)
|
||
SetSuitUpdate("!HEV_DMG6", false, SUIT_NEXT_IN_30SEC); // blood loss detected
|
||
//else
|
||
// SetSuitUpdate("!HEV_DMG0", false, SUIT_NEXT_IN_30SEC); // minor laceration
|
||
|
||
bitsDamage &= ~DMG_BULLET;
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_SLASH)
|
||
{
|
||
if (fmajor)
|
||
SetSuitUpdate("!HEV_DMG1", false, SUIT_NEXT_IN_30SEC); // major laceration
|
||
else
|
||
SetSuitUpdate("!HEV_DMG0", false, SUIT_NEXT_IN_30SEC); // minor laceration
|
||
|
||
bitsDamage &= ~DMG_SLASH;
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_SONIC)
|
||
{
|
||
if (fmajor)
|
||
SetSuitUpdate("!HEV_DMG2", false, SUIT_NEXT_IN_1MIN); // internal bleeding
|
||
bitsDamage &= ~DMG_SONIC;
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & (DMG_POISON | DMG_PARALYZE))
|
||
{
|
||
if (bitsDamage & DMG_POISON)
|
||
{
|
||
m_nPoisonDmg += info.GetDamage();
|
||
m_tbdPrev = gpGlobals->curtime;
|
||
m_rgbTimeBasedDamage[itbd_PoisonRecover] = 0;
|
||
}
|
||
|
||
SetSuitUpdate("!HEV_DMG3", false, SUIT_NEXT_IN_1MIN); // blood toxins detected
|
||
bitsDamage &= ~(DMG_POISON | DMG_PARALYZE);
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_ACID)
|
||
{
|
||
SetSuitUpdate("!HEV_DET1", false, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected
|
||
bitsDamage &= ~DMG_ACID;
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_NERVEGAS)
|
||
{
|
||
SetSuitUpdate("!HEV_DET0", false, SUIT_NEXT_IN_1MIN); // biohazard detected
|
||
bitsDamage &= ~DMG_NERVEGAS;
|
||
ffound = true;
|
||
}
|
||
|
||
if (bitsDamage & DMG_RADIATION)
|
||
{
|
||
SetSuitUpdate("!HEV_DET2", false, SUIT_NEXT_IN_1MIN); // radiation detected
|
||
bitsDamage &= ~DMG_RADIATION;
|
||
ffound = true;
|
||
}
|
||
if (bitsDamage & DMG_SHOCK)
|
||
{
|
||
bitsDamage &= ~DMG_SHOCK;
|
||
ffound = true;
|
||
}
|
||
}
|
||
|
||
float flPunch = -2;
|
||
|
||
if (hl2_episodic.GetBool() && info.GetAttacker() && !FInViewCone(info.GetAttacker()))
|
||
{
|
||
if (info.GetDamage() > 10.0f)
|
||
flPunch = -10;
|
||
else
|
||
flPunch = RandomFloat(-5, -7);
|
||
}
|
||
|
||
m_Local.m_vecPunchAngle.SetX(flPunch);
|
||
|
||
if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75)
|
||
{
|
||
// first time we take major damage...
|
||
// turn automedic on if not on
|
||
SetSuitUpdate("!HEV_MED1", false, SUIT_NEXT_IN_30MIN); // automedic on
|
||
|
||
// give morphine shot if not given recently
|
||
SetSuitUpdate("!HEV_HEAL7", false, SUIT_NEXT_IN_30MIN); // morphine shot
|
||
}
|
||
|
||
if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75)
|
||
{
|
||
|
||
// already took major damage, now it's critical...
|
||
if (m_iHealth < 6)
|
||
SetSuitUpdate("!HEV_HLTH3", false, SUIT_NEXT_IN_10MIN); // near death
|
||
else if (m_iHealth < 20)
|
||
SetSuitUpdate("!HEV_HLTH2", false, SUIT_NEXT_IN_10MIN); // health critical
|
||
|
||
// give critical health warnings
|
||
if (!random->RandomInt(0, 3) && flHealthPrev < 50)
|
||
SetSuitUpdate("!HEV_DMG7", false, SUIT_NEXT_IN_5MIN); //seek medical attention
|
||
}
|
||
|
||
// if we're taking time based damage, warn about its continuing effects
|
||
if (fTookDamage && g_pGameRules->Damage_IsTimeBased(info.GetDamageType()) && flHealthPrev < 75)
|
||
{
|
||
if (flHealthPrev < 50)
|
||
{
|
||
if (!random->RandomInt(0, 3))
|
||
SetSuitUpdate("!HEV_DMG7", false, SUIT_NEXT_IN_5MIN); //seek medical attention
|
||
}
|
||
else
|
||
SetSuitUpdate("!HEV_HLTH1", false, SUIT_NEXT_IN_10MIN); // health dropping
|
||
}
|
||
|
||
// Do special explosion damage effect
|
||
if (bitsDamage & DMG_BLAST)
|
||
{
|
||
OnDamagedByExplosion(info);
|
||
}
|
||
|
||
return fTookDamage;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &info -
|
||
// damageAmount -
|
||
//-----------------------------------------------------------------------------
|
||
#define MIN_SHOCK_AND_CONFUSION_DAMAGE 30.0f
|
||
#define MIN_EAR_RINGING_DISTANCE 240.0f // 20 feet
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &info -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::OnDamagedByExplosion(const CTakeDamageInfo &info)
|
||
{
|
||
float lastDamage = info.GetDamage();
|
||
|
||
float distanceFromPlayer = 9999.0f;
|
||
|
||
CBaseEntity *inflictor = info.GetInflictor();
|
||
if (inflictor)
|
||
{
|
||
Vector delta = GetAbsOrigin() - inflictor->GetAbsOrigin();
|
||
distanceFromPlayer = delta.Length();
|
||
}
|
||
|
||
bool ear_ringing = distanceFromPlayer < MIN_EAR_RINGING_DISTANCE ? true : false;
|
||
bool shock = lastDamage >= MIN_SHOCK_AND_CONFUSION_DAMAGE;
|
||
|
||
if (!shock && !ear_ringing)
|
||
return;
|
||
|
||
int effect = shock ?
|
||
random->RandomInt(35, 37) :
|
||
random->RandomInt(32, 34);
|
||
|
||
CSingleUserRecipientFilter user(this);
|
||
enginesound->SetPlayerDSP(user, effect, false);
|
||
|
||
CSoundParameters sprms;
|
||
|
||
sprms.pitch = 10;
|
||
}
|
||
|
||
//=========================================================
|
||
// PackDeadPlayerItems - call this when a player dies to
|
||
// pack up the appropriate weapons and ammo items, and to
|
||
// destroy anything that shouldn't be packed.
|
||
//
|
||
// This is pretty brute force :(
|
||
//=========================================================
|
||
void CBasePlayer::PackDeadPlayerItems(void)
|
||
{
|
||
int iWeaponRules;
|
||
int iAmmoRules;
|
||
int i;
|
||
CBaseCombatWeapon *rgpPackWeapons[20];// 20 hardcoded for now. How to determine exactly how many weapons we have?
|
||
int iPackAmmo[MAX_AMMO_SLOTS + 1];
|
||
int iPW = 0;// index into packweapons array
|
||
int iPA = 0;// index into packammo array
|
||
|
||
memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons));
|
||
memset(iPackAmmo, -1, sizeof(iPackAmmo));
|
||
|
||
// get the game rules
|
||
iWeaponRules = g_pGameRules->DeadPlayerWeapons(this);
|
||
iAmmoRules = g_pGameRules->DeadPlayerAmmo(this);
|
||
|
||
if (iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO)
|
||
{
|
||
// nothing to pack. Remove the weapons and return. Don't call create on the box!
|
||
RemoveAllItems(true);
|
||
return;
|
||
}
|
||
|
||
// go through all of the weapons and make a list of the ones to pack
|
||
for (i = 0; i < WeaponCount(); i++)
|
||
{
|
||
// there's a weapon here. Should I pack it?
|
||
CBaseCombatWeapon *pPlayerItem = GetWeapon(i);
|
||
if (pPlayerItem)
|
||
{
|
||
switch (iWeaponRules)
|
||
{
|
||
case GR_PLR_DROP_GUN_ACTIVE:
|
||
if (GetActiveWeapon() && pPlayerItem == GetActiveWeapon())
|
||
{
|
||
// this is the active item. Pack it.
|
||
rgpPackWeapons[iPW++] = pPlayerItem;
|
||
}
|
||
break;
|
||
|
||
case GR_PLR_DROP_GUN_ALL:
|
||
rgpPackWeapons[iPW++] = pPlayerItem;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// now go through ammo and make a list of which types to pack.
|
||
if (iAmmoRules != GR_PLR_DROP_AMMO_NO)
|
||
{
|
||
for (i = 0; i < MAX_AMMO_SLOTS; i++)
|
||
{
|
||
if (GetAmmoCount(i) > 0)
|
||
{
|
||
// player has some ammo of this type.
|
||
switch (iAmmoRules)
|
||
{
|
||
case GR_PLR_DROP_AMMO_ALL:
|
||
iPackAmmo[iPA++] = i;
|
||
break;
|
||
|
||
case GR_PLR_DROP_AMMO_ACTIVE:
|
||
// WEAPONTODO: Make this work
|
||
/*
|
||
if ( GetActiveWeapon() && i == GetActiveWeapon()->m_iPrimaryAmmoType )
|
||
{
|
||
// this is the primary ammo type for the active weapon
|
||
iPackAmmo[ iPA++ ] = i;
|
||
}
|
||
else if ( GetActiveWeapon() && i == GetActiveWeapon()->m_iSecondaryAmmoType )
|
||
{
|
||
// this is the secondary ammo type for the active weapon
|
||
iPackAmmo[ iPA++ ] = i;
|
||
}
|
||
*/
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
RemoveAllItems(true);// now strip off everything that wasn't handled by the code above.
|
||
}
|
||
|
||
void CBasePlayer::RemoveAllItems(bool removeSuit)
|
||
{
|
||
if (GetActiveWeapon())
|
||
{
|
||
ResetAutoaim();
|
||
GetActiveWeapon()->Holster();
|
||
}
|
||
|
||
Weapon_SetLast(NULL);
|
||
RemoveAllWeapons();
|
||
RemoveAllAmmo();
|
||
|
||
if (removeSuit)
|
||
{
|
||
RemoveSuit();
|
||
}
|
||
|
||
UpdateClientData();
|
||
}
|
||
|
||
bool CBasePlayer::IsDead() const
|
||
{
|
||
return m_lifeState == LIFE_DEAD;
|
||
}
|
||
|
||
static float DamageForce(const Vector &size, float damage)
|
||
{
|
||
float force = damage * ((32 * 32 * 72.0) / (size.x * size.y * size.z)) * 5;
|
||
|
||
if (force > 1000.0)
|
||
{
|
||
force = 1000.0;
|
||
}
|
||
|
||
return force;
|
||
}
|
||
|
||
|
||
const impactdamagetable_t &CBasePlayer::GetPhysicsImpactDamageTable()
|
||
{
|
||
return gDefaultPlayerImpactDamageTable;
|
||
}
|
||
|
||
|
||
void CBasePlayer::DispatchBloodOverlay(const CTakeDamageInfo &info)
|
||
{
|
||
// Handle the viewmodel blood splatter overlay effect here:
|
||
if (cvar->FindVar("oc_player_bloodoverlay")->GetInt() && info.GetDamageType() & (DMG_ACID))
|
||
{
|
||
this->SetupBloodOverlay(true);
|
||
|
||
if (this->GetActiveWeapon())
|
||
this->SetupWeaponBloodOverlay(true);
|
||
|
||
this->SetupBloodOverlayDelay(cvar->FindVar("oc_player_bloodoverlay_lifetime")->GetFloat());
|
||
|
||
int yellowBloodFrames = cvar->FindVar("oc_player_bloodoverlay_yellow_count")->GetInt();
|
||
|
||
int redBloodFrames = cvar->FindVar("oc_player_bloodoverlay_red_count")->GetInt();
|
||
|
||
int acidBloodFrames = cvar->FindVar("oc_player_bloodoverlay_green_count")->GetInt();
|
||
|
||
int acidBloodVar = random->RandomInt(yellowBloodFrames + redBloodFrames, yellowBloodFrames + redBloodFrames + acidBloodFrames - 1);
|
||
|
||
switch (this->BloodColor())
|
||
{
|
||
case BLOOD_COLOR_RED:
|
||
{
|
||
this->SetupBloodOverlayFrame(acidBloodVar);
|
||
if (this->GetActiveWeapon())
|
||
this->SetupWeaponBloodOverlayFrame(acidBloodVar);
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
this->SetupBloodOverlay(false);
|
||
|
||
if (this->GetActiveWeapon())
|
||
this->SetupWeaponBloodOverlay(false);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
int CBasePlayer::OnTakeDamage_Alive(const CTakeDamageInfo &info)
|
||
{
|
||
// set damage type sustained
|
||
m_bitsDamageType |= info.GetDamageType();
|
||
|
||
if (!BaseClass::OnTakeDamage_Alive(info))
|
||
return 0;
|
||
|
||
CBaseEntity * attacker = info.GetAttacker();
|
||
|
||
if (!attacker)
|
||
return 0;
|
||
|
||
DispatchBloodOverlay(info);
|
||
|
||
Vector vecDir = vec3_origin;
|
||
if (info.GetInflictor())
|
||
{
|
||
vecDir = info.GetInflictor()->WorldSpaceCenter() - Vector(0, 0, 10) - WorldSpaceCenter();
|
||
VectorNormalize(vecDir);
|
||
}
|
||
|
||
if (info.GetInflictor() && (GetMoveType() == MOVETYPE_WALK) &&
|
||
(!attacker->IsSolidFlagSet(FSOLID_TRIGGER)))
|
||
{
|
||
Vector force = vecDir * -DamageForce(WorldAlignSize(), info.GetBaseDamage());
|
||
if (force.z > 250.0f)
|
||
{
|
||
force.z = 250.0f;
|
||
}
|
||
ApplyAbsVelocityImpulse(force);
|
||
}
|
||
|
||
// fire global game event
|
||
|
||
IGameEvent * event = gameeventmanager->CreateEvent("player_hurt");
|
||
if (event)
|
||
{
|
||
event->SetInt("userid", GetUserID());
|
||
event->SetInt("health", MAX(0, m_iHealth));
|
||
event->SetInt("priority", 5); // HLTV event priority, not transmitted
|
||
|
||
if (attacker->IsPlayer())
|
||
{
|
||
CBasePlayer *player = ToBasePlayer(attacker);
|
||
event->SetInt("attacker", player->GetUserID()); // hurt by other player
|
||
}
|
||
else
|
||
{
|
||
event->SetInt("attacker", 0); // hurt by "world"
|
||
}
|
||
|
||
gameeventmanager->FireEvent(event);
|
||
}
|
||
|
||
// Insert a combat sound so that nearby NPCs hear battle
|
||
if (attacker->IsNPC())
|
||
{
|
||
CSoundEnt::InsertSound(SOUND_COMBAT, GetAbsOrigin(), 512, 0.5, this);//<<TODO>>//magic number
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
void CBasePlayer::Event_Killed(const CTakeDamageInfo &info)
|
||
{
|
||
CSound *pSound;
|
||
|
||
if (Hints())
|
||
{
|
||
Hints()->ResetHintTimers();
|
||
}
|
||
|
||
g_pGameRules->PlayerKilled(this, info);
|
||
|
||
gamestats->Event_PlayerKilled(this, info);
|
||
|
||
RumbleEffect(RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE);
|
||
|
||
#if defined( WIN32 ) && !defined( _X360 )
|
||
// NVNT set the drag to zero in the case of underwater death.
|
||
HapticSetDrag(this, 0);
|
||
#endif
|
||
ClearUseEntity();
|
||
|
||
// this client isn't going to be thinking for a while, so reset the sound until they respawn
|
||
pSound = CSoundEnt::SoundPointerForIndex(CSoundEnt::ClientSoundIndex(edict()));
|
||
{
|
||
if (pSound)
|
||
{
|
||
pSound->Reset();
|
||
}
|
||
}
|
||
|
||
// don't let the status bar glitch for players with <0 health.
|
||
if (m_iHealth < -99)
|
||
{
|
||
m_iHealth = 0;
|
||
}
|
||
|
||
// holster the current weapon
|
||
if (GetActiveWeapon())
|
||
{
|
||
GetActiveWeapon()->Holster();
|
||
}
|
||
|
||
SetAnimation(PLAYER_DIE);
|
||
|
||
if (!IsObserver())
|
||
{
|
||
SetViewOffset(VEC_DEAD_VIEWHEIGHT_SCALED(this));
|
||
}
|
||
m_lifeState = LIFE_DYING;
|
||
|
||
pl.deadflag = true;
|
||
AddSolidFlags(FSOLID_NOT_SOLID);
|
||
// force contact points to get flushed if no longer valid
|
||
// UNDONE: Always do this on RecheckCollisionFilter() ?
|
||
IPhysicsObject *pObject = VPhysicsGetObject();
|
||
|
||
if (pObject)
|
||
{
|
||
pObject->RecheckContactPoints();
|
||
}
|
||
|
||
SetMoveType(MOVETYPE_FLYGRAVITY);
|
||
SetGroundEntity(NULL);
|
||
|
||
// clear out the suit message cache so we don't keep chattering
|
||
SetSuitUpdate(NULL, false, 0);
|
||
|
||
// reset FOV
|
||
SetFOV(this, 0);
|
||
|
||
if (FlashlightIsOn())
|
||
{
|
||
FlashlightTurnOff();
|
||
}
|
||
|
||
m_flDeathTime = gpGlobals->curtime;
|
||
|
||
ClearLastKnownArea();
|
||
|
||
BaseClass::Event_Killed(info);
|
||
}
|
||
|
||
void CBasePlayer::Event_Dying(const CTakeDamageInfo& info)
|
||
{
|
||
// NOT GIBBED, RUN THIS CODE
|
||
|
||
DeathSound(info);
|
||
|
||
// The dead body rolls out of the vehicle.
|
||
if (IsInAVehicle())
|
||
{
|
||
LeaveVehicle();
|
||
}
|
||
|
||
QAngle angles = GetLocalAngles();
|
||
|
||
angles.x = 0;
|
||
angles.z = 0;
|
||
|
||
SetLocalAngles(angles);
|
||
|
||
SetThink(&CBasePlayer::PlayerDeathThink);
|
||
SetNextThink(gpGlobals->curtime + 0.1f);
|
||
BaseClass::Event_Dying(info);
|
||
}
|
||
|
||
|
||
// Set the activity based on an event or current state
|
||
void CBasePlayer::SetAnimation(PLAYER_ANIM playerAnim)
|
||
{
|
||
return;
|
||
int animDesired;
|
||
char szAnim[64];
|
||
|
||
float speed;
|
||
|
||
speed = GetAbsVelocity().Length2D();
|
||
|
||
if (GetFlags() & (FL_FROZEN | FL_ATCONTROLS))
|
||
{
|
||
speed = 0;
|
||
playerAnim = PLAYER_IDLE;
|
||
}
|
||
|
||
Activity idealActivity = ACT_WALK;// TEMP!!!!!
|
||
|
||
// This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
|
||
if (playerAnim == PLAYER_JUMP)
|
||
{
|
||
idealActivity = ACT_HOP;
|
||
}
|
||
else if (playerAnim == PLAYER_SUPERJUMP)
|
||
{
|
||
idealActivity = ACT_LEAP;
|
||
}
|
||
else if (playerAnim == PLAYER_DIE)
|
||
{
|
||
if (m_lifeState == LIFE_ALIVE)
|
||
{
|
||
idealActivity = GetDeathActivity();
|
||
}
|
||
}
|
||
else if (playerAnim == PLAYER_ATTACK1)
|
||
{
|
||
if (m_Activity == ACT_HOVER ||
|
||
m_Activity == ACT_SWIM ||
|
||
m_Activity == ACT_HOP ||
|
||
m_Activity == ACT_LEAP ||
|
||
m_Activity == ACT_DIESIMPLE)
|
||
{
|
||
idealActivity = m_Activity;
|
||
}
|
||
else
|
||
{
|
||
idealActivity = ACT_RANGE_ATTACK1;
|
||
}
|
||
}
|
||
else if (playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK)
|
||
{
|
||
if (!(GetFlags() & FL_ONGROUND) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP)) // Still jumping
|
||
{
|
||
idealActivity = m_Activity;
|
||
}
|
||
else if (GetWaterLevel() > 1)
|
||
{
|
||
if (speed == 0)
|
||
idealActivity = ACT_HOVER;
|
||
else
|
||
idealActivity = ACT_SWIM;
|
||
}
|
||
else
|
||
{
|
||
idealActivity = ACT_WALK;
|
||
}
|
||
}
|
||
|
||
|
||
if (idealActivity == ACT_RANGE_ATTACK1)
|
||
{
|
||
if (GetFlags() & FL_DUCKING) // crouching
|
||
{
|
||
Q_strncpy(szAnim, "crouch_shoot_", sizeof(szAnim));
|
||
}
|
||
else
|
||
{
|
||
Q_strncpy(szAnim, "ref_shoot_", sizeof(szAnim));
|
||
}
|
||
Q_strncat(szAnim, m_szAnimExtension, sizeof(szAnim), COPY_ALL_CHARACTERS);
|
||
animDesired = LookupSequence(szAnim);
|
||
if (animDesired == -1)
|
||
animDesired = 0;
|
||
|
||
if (GetSequence() != animDesired || !SequenceLoops())
|
||
{
|
||
SetCycle(0);
|
||
}
|
||
|
||
// Tracker 24588: In single player when firing own weapon this causes eye and punchangle to jitter
|
||
//if (!SequenceLoops())
|
||
//{
|
||
// IncrementInterpolationFrame();
|
||
//}
|
||
|
||
SetActivity(idealActivity);
|
||
ResetSequence(animDesired);
|
||
}
|
||
else if (idealActivity == ACT_WALK)
|
||
{
|
||
if (GetActivity() != ACT_RANGE_ATTACK1 || IsActivityFinished())
|
||
{
|
||
if (GetFlags() & FL_DUCKING) // crouching
|
||
{
|
||
Q_strncpy(szAnim, "crouch_aim_", sizeof(szAnim));
|
||
}
|
||
else
|
||
{
|
||
Q_strncpy(szAnim, "ref_aim_", sizeof(szAnim));
|
||
}
|
||
Q_strncat(szAnim, m_szAnimExtension, sizeof(szAnim), COPY_ALL_CHARACTERS);
|
||
animDesired = LookupSequence(szAnim);
|
||
if (animDesired == -1)
|
||
animDesired = 0;
|
||
SetActivity(ACT_WALK);
|
||
}
|
||
else
|
||
{
|
||
animDesired = GetSequence();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (GetActivity() == idealActivity)
|
||
return;
|
||
|
||
SetActivity(idealActivity);
|
||
|
||
animDesired = SelectWeightedSequence(m_Activity);
|
||
|
||
// Already using the desired animation?
|
||
if (GetSequence() == animDesired)
|
||
return;
|
||
|
||
ResetSequence(animDesired);
|
||
SetCycle(0);
|
||
return;
|
||
}
|
||
|
||
// Already using the desired animation?
|
||
if (GetSequence() == animDesired)
|
||
return;
|
||
|
||
//Msg( "Set animation to %d\n", animDesired );
|
||
// Reset to first frame of desired animation
|
||
ResetSequence(animDesired);
|
||
SetCycle(0);
|
||
}
|
||
|
||
/*
|
||
===========
|
||
WaterMove
|
||
============
|
||
*/
|
||
#ifdef HL2_DLL
|
||
|
||
// test for HL2 drowning damage increase (aux power used instead)
|
||
#define AIRTIME 7 // lung full of air lasts this many seconds
|
||
#define DROWNING_DAMAGE_INITIAL 10
|
||
#define DROWNING_DAMAGE_MAX 10
|
||
|
||
#else
|
||
|
||
#define AIRTIME 12 // lung full of air lasts this many seconds
|
||
#define DROWNING_DAMAGE_INITIAL 2
|
||
#define DROWNING_DAMAGE_MAX 5
|
||
|
||
#endif
|
||
|
||
void CBasePlayer::WaterMove()
|
||
{
|
||
if (GetWaterLevel() > 1 && !clearDecals)
|
||
{
|
||
this->GetBaseAnimating()->RemoveAllDecals();
|
||
clearDecals = true;
|
||
}
|
||
else// if (GetWaterLevel() <= 1 && clearDecals)
|
||
{
|
||
clearDecals = false;
|
||
}
|
||
|
||
if ((GetMoveType() == MOVETYPE_NOCLIP) && !GetMoveParent())
|
||
{
|
||
m_AirFinished = gpGlobals->curtime + AIRTIME;
|
||
return;
|
||
}
|
||
|
||
if (GetWaterLevel() > 2)
|
||
{
|
||
if (m_bShouldDrawBloodOverlay)
|
||
{
|
||
SetupBloodOverlay(false);
|
||
SetupBloodOverlayDelay(10.0f);
|
||
//SetupWeaponBloodOverlay(false, true);
|
||
}
|
||
}
|
||
|
||
if (m_iHealth < 0 || !IsAlive())
|
||
{
|
||
UpdateUnderwaterState();
|
||
return;
|
||
}
|
||
|
||
// waterlevel 0 - not in water (WL_NotInWater)
|
||
// waterlevel 1 - feet in water (WL_Feet)
|
||
// waterlevel 2 - waist in water (WL_Waist)
|
||
// waterlevel 3 - head in water (WL_Eyes)
|
||
|
||
if (GetWaterLevel() != WL_Eyes || CanBreatheUnderwater())
|
||
{
|
||
// not underwater
|
||
|
||
// play 'up for air' sound
|
||
|
||
if (m_AirFinished < gpGlobals->curtime)
|
||
{
|
||
EmitSound("Player.DrownStart");
|
||
}
|
||
|
||
m_AirFinished = gpGlobals->curtime + AIRTIME;
|
||
m_nDrownDmgRate = DROWNING_DAMAGE_INITIAL;
|
||
|
||
// if we took drowning damage, give it back slowly
|
||
if (m_idrowndmg > m_idrownrestored)
|
||
{
|
||
// set drowning damage bit. hack - dmg_drownrecover actually
|
||
// makes the time based damage code 'give back' health over time.
|
||
// make sure counter is cleared so we start count correctly.
|
||
|
||
// NOTE: this actually causes the count to continue restarting
|
||
// until all drowning damage is healed.
|
||
|
||
m_bitsDamageType |= DMG_DROWNRECOVER;
|
||
m_bitsDamageType &= ~DMG_DROWN;
|
||
m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
|
||
}
|
||
|
||
}
|
||
else
|
||
{ // fully under water
|
||
// stop restoring damage while underwater
|
||
m_bitsDamageType &= ~DMG_DROWNRECOVER;
|
||
m_rgbTimeBasedDamage[itbd_DrownRecover] = 0;
|
||
|
||
if (m_AirFinished < gpGlobals->curtime && !(GetFlags() & FL_GODMODE)) // drown!
|
||
{
|
||
if (m_PainFinished < gpGlobals->curtime)
|
||
{
|
||
// take drowning damage
|
||
m_nDrownDmgRate += 1;
|
||
if (m_nDrownDmgRate > DROWNING_DAMAGE_MAX)
|
||
{
|
||
m_nDrownDmgRate = DROWNING_DAMAGE_MAX;
|
||
}
|
||
|
||
OnTakeDamage(CTakeDamageInfo(GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), m_nDrownDmgRate, DMG_DROWN));
|
||
m_PainFinished = gpGlobals->curtime + 1;
|
||
|
||
// track drowning damage, give it back when
|
||
// player finally takes a breath
|
||
m_idrowndmg += m_nDrownDmgRate;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_bitsDamageType &= ~DMG_DROWN;
|
||
}
|
||
}
|
||
|
||
UpdateUnderwaterState();
|
||
}
|
||
|
||
|
||
// true if the player is attached to a ladder
|
||
bool CBasePlayer::IsOnLadder(void)
|
||
{
|
||
return (GetMoveType() == MOVETYPE_LADDER);
|
||
}
|
||
|
||
|
||
float CBasePlayer::GetWaterJumpTime() const
|
||
{
|
||
return m_flWaterJumpTime;
|
||
}
|
||
|
||
void CBasePlayer::SetWaterJumpTime(float flWaterJumpTime)
|
||
{
|
||
m_flWaterJumpTime = flWaterJumpTime;
|
||
}
|
||
|
||
float CBasePlayer::GetSwimSoundTime(void) const
|
||
{
|
||
return m_flSwimSoundTime;
|
||
}
|
||
|
||
void CBasePlayer::SetSwimSoundTime(float flSwimSoundTime)
|
||
{
|
||
m_flSwimSoundTime = flSwimSoundTime;
|
||
}
|
||
|
||
void CBasePlayer::ShowViewPortPanel(const char * name, bool bShow, KeyValues *data)
|
||
{
|
||
CSingleUserRecipientFilter filter(this);
|
||
filter.MakeReliable();
|
||
|
||
int count = 0;
|
||
KeyValues *subkey = NULL;
|
||
|
||
if (data)
|
||
{
|
||
subkey = data->GetFirstSubKey();
|
||
while (subkey)
|
||
{
|
||
count++; subkey = subkey->GetNextKey();
|
||
}
|
||
|
||
subkey = data->GetFirstSubKey(); // reset
|
||
}
|
||
|
||
UserMessageBegin(filter, "VGUIMenu");
|
||
WRITE_STRING(name); // menu name
|
||
WRITE_BYTE(bShow ? 1 : 0);
|
||
WRITE_BYTE(count);
|
||
|
||
// write additional data (be careful not more than 192 bytes!)
|
||
while (subkey)
|
||
{
|
||
WRITE_STRING(subkey->GetName());
|
||
WRITE_STRING(subkey->GetString());
|
||
subkey = subkey->GetNextKey();
|
||
}
|
||
MessageEnd();
|
||
}
|
||
|
||
|
||
void CBasePlayer::PlayerDeathThink(void)
|
||
{
|
||
float flForward;
|
||
|
||
SetNextThink(gpGlobals->curtime + 0.1f);
|
||
|
||
if (GetFlags() & FL_ONGROUND)
|
||
{
|
||
flForward = GetAbsVelocity().Length() - 20;
|
||
if (flForward <= 0)
|
||
{
|
||
SetAbsVelocity(vec3_origin);
|
||
}
|
||
else
|
||
{
|
||
Vector vecNewVelocity = GetAbsVelocity();
|
||
VectorNormalize(vecNewVelocity);
|
||
vecNewVelocity *= flForward;
|
||
SetAbsVelocity(vecNewVelocity);
|
||
}
|
||
}
|
||
|
||
if (HasWeapons())
|
||
{
|
||
// we drop the guns here because weapons that have an area effect and can kill their user
|
||
// will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the
|
||
// player class sometimes is freed. It's safer to manipulate the weapons once we know
|
||
// we aren't calling into any of their code anymore through the player pointer.
|
||
PackDeadPlayerItems();
|
||
}
|
||
|
||
if (GetModelIndex() && (!IsSequenceFinished()) && (m_lifeState == LIFE_DYING))
|
||
{
|
||
StudioFrameAdvance();
|
||
|
||
m_iRespawnFrames++;
|
||
if (m_iRespawnFrames < 60) // animations should be no longer than this
|
||
return;
|
||
}
|
||
|
||
if (m_lifeState == LIFE_DYING)
|
||
{
|
||
m_lifeState = LIFE_DEAD;
|
||
m_flDeathAnimTime = gpGlobals->curtime;
|
||
}
|
||
|
||
StopAnimation();
|
||
|
||
IncrementInterpolationFrame();
|
||
m_flPlaybackRate = 0.0;
|
||
|
||
int fAnyButtonDown = (m_nButtons & ~IN_SCORE);
|
||
|
||
// Strip out the duck key from this check if it's toggled
|
||
if ((fAnyButtonDown & IN_DUCK) && GetToggledDuckState())
|
||
{
|
||
fAnyButtonDown &= ~IN_DUCK;
|
||
}
|
||
|
||
// wait for all buttons released
|
||
if (m_lifeState == LIFE_DEAD)
|
||
{
|
||
if (fAnyButtonDown)
|
||
return;
|
||
|
||
if (g_pGameRules->FPlayerCanRespawn(this))
|
||
{
|
||
m_lifeState = LIFE_RESPAWNABLE;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// if the player has been dead for one second longer than allowed by forcerespawn,
|
||
// forcerespawn isn't on. Send the player off to an intermission camera until they
|
||
// choose to respawn.
|
||
if (g_pGameRules->IsMultiplayer() && (gpGlobals->curtime > (m_flDeathTime + DEATH_ANIMATION_TIME)) && !IsObserver())
|
||
{
|
||
// go to dead camera.
|
||
StartObserverMode(m_iObserverLastMode);
|
||
}
|
||
|
||
// wait for any button down, or mp_forcerespawn is set and the respawn time is up
|
||
if (!fAnyButtonDown
|
||
&& !(g_pGameRules->IsMultiplayer() && forcerespawn.GetInt() > 0 && (gpGlobals->curtime > (m_flDeathTime + 5))))
|
||
return;
|
||
|
||
m_nButtons = 0;
|
||
m_iRespawnFrames = 0;
|
||
|
||
//Msg( "Respawn\n");
|
||
|
||
respawn(this, !IsObserver());// don't copy a corpse if we're in deathcam.
|
||
SetNextThink(TICK_NEVER_THINK);
|
||
}
|
||
|
||
/*
|
||
|
||
//=========================================================
|
||
// StartDeathCam - find an intermission spot and send the
|
||
// player off into observer mode
|
||
//=========================================================
|
||
void CBasePlayer::StartDeathCam( void )
|
||
{
|
||
CBaseEntity *pSpot, *pNewSpot;
|
||
int iRand;
|
||
|
||
if ( GetViewOffset() == vec3_origin )
|
||
{
|
||
// don't accept subsequent attempts to StartDeathCam()
|
||
return;
|
||
}
|
||
|
||
pSpot = gEntList.FindEntityByClassname( NULL, "info_intermission");
|
||
|
||
if ( pSpot )
|
||
{
|
||
// at least one intermission spot in the world.
|
||
iRand = random->RandomInt( 0, 3 );
|
||
|
||
while ( iRand > 0 )
|
||
{
|
||
pNewSpot = gEntList.FindEntityByClassname( pSpot, "info_intermission");
|
||
|
||
if ( pNewSpot )
|
||
{
|
||
pSpot = pNewSpot;
|
||
}
|
||
|
||
iRand--;
|
||
}
|
||
|
||
CreateCorpse();
|
||
StartObserverMode( pSpot->GetAbsOrigin(), pSpot->GetAbsAngles() );
|
||
}
|
||
else
|
||
{
|
||
// no intermission spot. Push them up in the air, looking down at their corpse
|
||
trace_t tr;
|
||
|
||
CreateCorpse();
|
||
|
||
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, 128 ),
|
||
MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
|
||
QAngle angles;
|
||
VectorAngles( GetAbsOrigin() - tr.endpos, angles );
|
||
StartObserverMode( tr.endpos, angles );
|
||
return;
|
||
}
|
||
} */
|
||
|
||
void CBasePlayer::StopObserverMode()
|
||
{
|
||
m_bForcedObserverMode = false;
|
||
m_afPhysicsFlags &= ~PFLAG_OBSERVER;
|
||
|
||
if (m_iObserverMode == OBS_MODE_NONE)
|
||
return;
|
||
|
||
if (m_iObserverMode > OBS_MODE_DEATHCAM)
|
||
{
|
||
m_iObserverLastMode = m_iObserverMode;
|
||
}
|
||
|
||
m_iObserverMode.Set(OBS_MODE_NONE);
|
||
|
||
ShowViewPortPanel("specmenu", false);
|
||
ShowViewPortPanel("specgui", false);
|
||
ShowViewPortPanel("overview", false);
|
||
}
|
||
|
||
bool CBasePlayer::StartObserverMode(int mode)
|
||
{
|
||
if (!IsObserver())
|
||
{
|
||
// set position to last view offset
|
||
SetAbsOrigin(GetAbsOrigin() + GetViewOffset());
|
||
SetViewOffset(vec3_origin);
|
||
}
|
||
|
||
Assert(mode > OBS_MODE_NONE);
|
||
|
||
m_afPhysicsFlags |= PFLAG_OBSERVER;
|
||
|
||
// Holster weapon immediately, to allow it to cleanup
|
||
if (GetActiveWeapon())
|
||
GetActiveWeapon()->Holster();
|
||
|
||
// clear out the suit message cache so we don't keep chattering
|
||
SetSuitUpdate(NULL, FALSE, 0);
|
||
|
||
SetGroundEntity((CBaseEntity *)NULL);
|
||
|
||
RemoveFlag(FL_DUCKING);
|
||
|
||
AddSolidFlags(FSOLID_NOT_SOLID);
|
||
|
||
SetObserverMode(mode);
|
||
|
||
if (gpGlobals->eLoadType != MapLoad_Background)
|
||
{
|
||
ShowViewPortPanel("specgui", ModeWantsSpectatorGUI(mode));
|
||
}
|
||
|
||
// Setup flags
|
||
m_Local.m_iHideHUD = HIDEHUD_HEALTH;
|
||
m_takedamage = DAMAGE_NO;
|
||
|
||
// Become invisible
|
||
AddEffects(EF_NODRAW);
|
||
|
||
m_iHealth = 1;
|
||
m_lifeState = LIFE_DEAD; // Can't be dead, otherwise movement doesn't work right.
|
||
m_flDeathAnimTime = gpGlobals->curtime;
|
||
pl.deadflag = true;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CBasePlayer::SetObserverMode(int mode)
|
||
{
|
||
if (mode < OBS_MODE_NONE || mode >= NUM_OBSERVER_MODES)
|
||
return false;
|
||
|
||
|
||
// check mp_forcecamera settings for dead players
|
||
if (mode > OBS_MODE_FIXED && GetTeamNumber() > TEAM_SPECTATOR)
|
||
{
|
||
switch (mp_forcecamera.GetInt())
|
||
{
|
||
case OBS_ALLOW_ALL: break; // no restrictions
|
||
case OBS_ALLOW_TEAM: mode = OBS_MODE_IN_EYE; break;
|
||
case OBS_ALLOW_NONE: mode = OBS_MODE_FIXED; break; // don't allow anything
|
||
}
|
||
}
|
||
|
||
if (m_iObserverMode > OBS_MODE_DEATHCAM)
|
||
{
|
||
// remember mode if we were really spectating before
|
||
m_iObserverLastMode = m_iObserverMode;
|
||
}
|
||
|
||
m_iObserverMode = mode;
|
||
|
||
switch (mode)
|
||
{
|
||
case OBS_MODE_NONE:
|
||
case OBS_MODE_FIXED:
|
||
case OBS_MODE_DEATHCAM:
|
||
SetFOV(this, 0); // Reset FOV
|
||
SetViewOffset(vec3_origin);
|
||
SetMoveType(MOVETYPE_NONE);
|
||
break;
|
||
|
||
case OBS_MODE_CHASE:
|
||
case OBS_MODE_IN_EYE:
|
||
// udpate FOV and viewmodels
|
||
SetObserverTarget(m_hObserverTarget);
|
||
SetMoveType(MOVETYPE_OBSERVER);
|
||
break;
|
||
|
||
//=============================================================================
|
||
// HPE_BEGIN:
|
||
// [menglish] Added freeze cam to the setter. Uses same setup as the roaming mode
|
||
//=============================================================================
|
||
|
||
case OBS_MODE_ROAMING:
|
||
case OBS_MODE_FREEZECAM:
|
||
SetFOV(this, 0); // Reset FOV
|
||
SetObserverTarget(m_hObserverTarget);
|
||
SetViewOffset(vec3_origin);
|
||
SetMoveType(MOVETYPE_OBSERVER);
|
||
break;
|
||
|
||
//=============================================================================
|
||
// HPE_END
|
||
//=============================================================================
|
||
}
|
||
|
||
CheckObserverSettings();
|
||
|
||
return true;
|
||
}
|
||
|
||
int CBasePlayer::GetObserverMode()
|
||
{
|
||
return m_iObserverMode;
|
||
}
|
||
|
||
void CBasePlayer::ForceObserverMode(int mode)
|
||
{
|
||
int tempMode = OBS_MODE_ROAMING;
|
||
|
||
if (m_iObserverMode == mode)
|
||
return;
|
||
|
||
// don't change last mode if already in forced mode
|
||
|
||
if (m_bForcedObserverMode)
|
||
{
|
||
tempMode = m_iObserverLastMode;
|
||
}
|
||
|
||
SetObserverMode(mode);
|
||
|
||
if (m_bForcedObserverMode)
|
||
{
|
||
m_iObserverLastMode = tempMode;
|
||
}
|
||
|
||
m_bForcedObserverMode = true;
|
||
}
|
||
|
||
void CBasePlayer::CheckObserverSettings()
|
||
{
|
||
// check if we are in forced mode and may go back to old mode
|
||
if (m_bForcedObserverMode)
|
||
{
|
||
CBaseEntity * target = m_hObserverTarget;
|
||
|
||
if (!IsValidObserverTarget(target))
|
||
{
|
||
// if old target is still invalid, try to find valid one
|
||
target = FindNextObserverTarget(false);
|
||
}
|
||
|
||
if (target)
|
||
{
|
||
// we found a valid target
|
||
m_bForcedObserverMode = false; // disable force mode
|
||
SetObserverMode(m_iObserverLastMode); // switch to last mode
|
||
SetObserverTarget(target); // goto target
|
||
|
||
// TODO check for HUD icons
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
// else stay in forced mode, no changes
|
||
return;
|
||
}
|
||
}
|
||
|
||
// make sure our last mode is valid
|
||
if (m_iObserverLastMode < OBS_MODE_FIXED)
|
||
{
|
||
m_iObserverLastMode = OBS_MODE_ROAMING;
|
||
}
|
||
|
||
// check if our spectating target is still a valid one
|
||
|
||
if (m_iObserverMode == OBS_MODE_IN_EYE || m_iObserverMode == OBS_MODE_CHASE || m_iObserverMode == OBS_MODE_FIXED)
|
||
{
|
||
ValidateCurrentObserverTarget();
|
||
|
||
CBasePlayer *target = ToBasePlayer(m_hObserverTarget.Get());
|
||
|
||
// for ineye mode we have to copy several data to see exactly the same
|
||
|
||
if (target && m_iObserverMode == OBS_MODE_IN_EYE)
|
||
{
|
||
int flagMask = FL_ONGROUND | FL_DUCKING;
|
||
|
||
int flags = target->GetFlags() & flagMask;
|
||
|
||
if ((GetFlags() & flagMask) != flags)
|
||
{
|
||
flags |= GetFlags() & (~flagMask); // keep other flags
|
||
ClearFlags();
|
||
AddFlag(flags);
|
||
}
|
||
|
||
if (target->GetViewOffset() != GetViewOffset())
|
||
{
|
||
SetViewOffset(target->GetViewOffset());
|
||
}
|
||
}
|
||
|
||
// Update the fog.
|
||
if (target)
|
||
{
|
||
if (target->m_Local.m_PlayerFog.m_hCtrl.Get() != m_Local.m_PlayerFog.m_hCtrl.Get())
|
||
{
|
||
m_Local.m_PlayerFog.m_hCtrl.Set(target->m_Local.m_PlayerFog.m_hCtrl.Get());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ValidateCurrentObserverTarget(void)
|
||
{
|
||
if (!IsValidObserverTarget(m_hObserverTarget.Get()))
|
||
{
|
||
// our target is not valid, try to find new target
|
||
CBaseEntity * target = FindNextObserverTarget(false);
|
||
if (target)
|
||
{
|
||
// switch to new valid target
|
||
SetObserverTarget(target);
|
||
}
|
||
else
|
||
{
|
||
// couldn't find new target, switch to temporary mode
|
||
if (mp_forcecamera.GetInt() == OBS_ALLOW_ALL)
|
||
{
|
||
// let player roam around
|
||
ForceObserverMode(OBS_MODE_ROAMING);
|
||
}
|
||
else
|
||
{
|
||
// fix player view right where it is
|
||
ForceObserverMode(OBS_MODE_FIXED);
|
||
m_hObserverTarget.Set(NULL); // no traget to follow
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::AttemptToExitFreezeCam(void)
|
||
{
|
||
StartObserverMode(OBS_MODE_DEATHCAM);
|
||
}
|
||
|
||
bool CBasePlayer::StartReplayMode(float fDelay, float fDuration, int iEntity)
|
||
{
|
||
if ((sv_maxreplay == NULL) || (sv_maxreplay->GetFloat() <= 0))
|
||
return false;
|
||
|
||
m_fDelay = fDelay;
|
||
m_fReplayEnd = gpGlobals->curtime + fDuration;
|
||
m_iReplayEntity = iEntity;
|
||
|
||
return true;
|
||
}
|
||
|
||
void CBasePlayer::StopReplayMode()
|
||
{
|
||
m_fDelay = 0.0f;
|
||
m_fReplayEnd = -1;
|
||
m_iReplayEntity = 0;
|
||
}
|
||
|
||
int CBasePlayer::GetDelayTicks()
|
||
{
|
||
if (m_fReplayEnd > gpGlobals->curtime)
|
||
{
|
||
return TIME_TO_TICKS(m_fDelay);
|
||
}
|
||
else
|
||
{
|
||
if (m_fDelay > 0.0f)
|
||
StopReplayMode();
|
||
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
int CBasePlayer::GetReplayEntity()
|
||
{
|
||
return m_iReplayEntity;
|
||
}
|
||
|
||
CBaseEntity * CBasePlayer::GetObserverTarget()
|
||
{
|
||
return m_hObserverTarget.Get();
|
||
}
|
||
|
||
void CBasePlayer::ObserverUse(bool bIsPressed)
|
||
{
|
||
#ifndef _XBOX
|
||
if (!HLTVDirector()->IsActive())
|
||
return;
|
||
|
||
if (GetTeamNumber() != TEAM_SPECTATOR)
|
||
return; // only pure spectators can play cameraman
|
||
|
||
if (!bIsPressed)
|
||
return;
|
||
|
||
bool bIsHLTV = HLTVDirector()->IsActive();
|
||
|
||
if (bIsHLTV)
|
||
{
|
||
int iCameraManIndex = HLTVDirector()->GetCameraMan();
|
||
|
||
if (iCameraManIndex == 0)
|
||
{
|
||
// turn camera on
|
||
HLTVDirector()->SetCameraMan(entindex());
|
||
}
|
||
else if (iCameraManIndex == entindex())
|
||
{
|
||
// turn camera off
|
||
HLTVDirector()->SetCameraMan(0);
|
||
}
|
||
else
|
||
{
|
||
ClientPrint(this, HUD_PRINTTALK, "Camera in use by other player.");
|
||
}
|
||
}
|
||
|
||
/* UTIL_SayText( "Spectator can not USE anything", this );
|
||
|
||
Vector dir,end;
|
||
Vector start = GetAbsOrigin();
|
||
|
||
AngleVectors( GetAbsAngles(), &dir );
|
||
VectorNormalize( dir );
|
||
|
||
VectorMA( start, 32.0f, dir, end );
|
||
|
||
trace_t tr;
|
||
UTIL_TraceLine( start, end, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
|
||
|
||
if ( tr.fraction == 1.0f )
|
||
return; // no obstacles in spectators way
|
||
|
||
VectorMA( start, 128.0f, dir, end );
|
||
|
||
Ray_t ray;
|
||
ray.Init( end, start, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
|
||
|
||
UTIL_TraceRay( ray, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
|
||
|
||
if ( tr.startsolid || tr.allsolid )
|
||
return;
|
||
|
||
SetAbsOrigin( tr.endpos ); */
|
||
#endif
|
||
}
|
||
|
||
void CBasePlayer::JumptoPosition(const Vector &origin, const QAngle &angles)
|
||
{
|
||
SetAbsOrigin(origin);
|
||
SetAbsVelocity(vec3_origin); // stop movement
|
||
SetLocalAngles(angles);
|
||
SnapEyeAngles(angles);
|
||
}
|
||
|
||
bool CBasePlayer::SetObserverTarget(CBaseEntity *target)
|
||
{
|
||
if (!IsValidObserverTarget(target))
|
||
return false;
|
||
|
||
// set new target
|
||
m_hObserverTarget.Set(target);
|
||
|
||
// reset fov to default
|
||
SetFOV(this, 0);
|
||
|
||
if (m_iObserverMode == OBS_MODE_ROAMING)
|
||
{
|
||
Vector dir, end;
|
||
Vector start = target->EyePosition();
|
||
|
||
AngleVectors(target->EyeAngles(), &dir);
|
||
VectorNormalize(dir);
|
||
VectorMA(start, -64.0f, dir, end);
|
||
|
||
Ray_t ray;
|
||
ray.Init(start, end, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
|
||
|
||
trace_t tr;
|
||
UTIL_TraceRay(ray, MASK_PLAYERSOLID, target, COLLISION_GROUP_PLAYER_MOVEMENT, &tr);
|
||
|
||
JumptoPosition(tr.endpos, target->EyeAngles());
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CBasePlayer::IsValidObserverTarget(CBaseEntity * target)
|
||
{
|
||
if (target == NULL)
|
||
return false;
|
||
|
||
// MOD AUTHORS: Add checks on target here or in derived method
|
||
|
||
if (!target->IsPlayer()) // only track players
|
||
return false;
|
||
|
||
CBasePlayer * player = ToBasePlayer(target);
|
||
|
||
/* Don't spec observers or players who haven't picked a class yet
|
||
if ( player->IsObserver() )
|
||
return false; */
|
||
|
||
if (player == this)
|
||
return false; // We can't observe ourselves.
|
||
|
||
if (player->IsEffectActive(EF_NODRAW)) // don't watch invisible players
|
||
return false;
|
||
|
||
if (player->m_lifeState == LIFE_RESPAWNABLE) // target is dead, waiting for respawn
|
||
return false;
|
||
|
||
if (player->m_lifeState == LIFE_DEAD || player->m_lifeState == LIFE_DYING)
|
||
{
|
||
if ((player->m_flDeathTime + DEATH_ANIMATION_TIME) < gpGlobals->curtime)
|
||
{
|
||
return false; // allow watching until 3 seconds after death to see death animation
|
||
}
|
||
}
|
||
|
||
// check forcecamera settings for active players
|
||
if (GetTeamNumber() != TEAM_SPECTATOR)
|
||
{
|
||
switch (mp_forcecamera.GetInt())
|
||
{
|
||
case OBS_ALLOW_ALL: break;
|
||
case OBS_ALLOW_TEAM: if (GetTeamNumber() != target->GetTeamNumber())
|
||
return false;
|
||
break;
|
||
case OBS_ALLOW_NONE: return false;
|
||
}
|
||
}
|
||
|
||
return true; // passed all test
|
||
}
|
||
|
||
int CBasePlayer::GetNextObserverSearchStartPoint(bool bReverse)
|
||
{
|
||
int iDir = bReverse ? -1 : 1;
|
||
|
||
int startIndex;
|
||
|
||
if (m_hObserverTarget)
|
||
{
|
||
// start using last followed player
|
||
startIndex = m_hObserverTarget->entindex();
|
||
}
|
||
else
|
||
{
|
||
// start using own player index
|
||
startIndex = this->entindex();
|
||
}
|
||
|
||
startIndex += iDir;
|
||
if (startIndex > gpGlobals->maxClients)
|
||
startIndex = 1;
|
||
else if (startIndex < 1)
|
||
startIndex = gpGlobals->maxClients;
|
||
|
||
return startIndex;
|
||
}
|
||
|
||
CBaseEntity * CBasePlayer::FindNextObserverTarget(bool bReverse)
|
||
{
|
||
// MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching
|
||
// only a subset of the players. e.g. Make it check the target's team.
|
||
|
||
/* if ( m_flNextFollowTime && m_flNextFollowTime > gpGlobals->time )
|
||
{
|
||
return;
|
||
}
|
||
|
||
m_flNextFollowTime = gpGlobals->time + 0.25;
|
||
*/ // TODO move outside this function
|
||
|
||
int startIndex = GetNextObserverSearchStartPoint(bReverse);
|
||
|
||
int currentIndex = startIndex;
|
||
int iDir = bReverse ? -1 : 1;
|
||
|
||
do
|
||
{
|
||
CBaseEntity * nextTarget = UTIL_PlayerByIndex(currentIndex);
|
||
|
||
if (IsValidObserverTarget(nextTarget))
|
||
{
|
||
return nextTarget; // found next valid player
|
||
}
|
||
|
||
currentIndex += iDir;
|
||
|
||
// Loop through the clients
|
||
if (currentIndex > gpGlobals->maxClients)
|
||
currentIndex = 1;
|
||
else if (currentIndex < 1)
|
||
currentIndex = gpGlobals->maxClients;
|
||
|
||
} while (currentIndex != startIndex);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Return true if this object can be +used by the player
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::IsUseableEntity(CBaseEntity *pEntity, unsigned int requiredCaps)
|
||
{
|
||
if (pEntity)
|
||
{
|
||
int caps = pEntity->ObjectCaps();
|
||
if (caps & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE))
|
||
{
|
||
if ((caps & requiredCaps) == requiredCaps)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::CanPickupObject(CBaseEntity *pObject, float massLimit, float sizeLimit)
|
||
{
|
||
// UNDONE: Make this virtual and move to HL2 player
|
||
#ifdef HL2_DLL
|
||
//Must be valid
|
||
if (pObject == NULL)
|
||
return false;
|
||
|
||
//Must move with physics
|
||
if (pObject->GetMoveType() != MOVETYPE_VPHYSICS)
|
||
return false;
|
||
|
||
IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
|
||
int count = pObject->VPhysicsGetObjectList(pList, ARRAYSIZE(pList));
|
||
|
||
//Must have a physics object
|
||
if (!count)
|
||
return false;
|
||
|
||
float objectMass = 0;
|
||
bool checkEnable = false;
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
objectMass += pList[i]->GetMass();
|
||
if (!pList[i]->IsMoveable())
|
||
{
|
||
checkEnable = true;
|
||
}
|
||
if (pList[i]->GetGameFlags() & FVPHYSICS_NO_PLAYER_PICKUP)
|
||
return false;
|
||
if (pList[i]->IsHinged())
|
||
return false;
|
||
}
|
||
|
||
|
||
//Msg( "Target mass: %f\n", pPhys->GetMass() );
|
||
|
||
//Must be under our threshold weight
|
||
if (massLimit > 0 && objectMass > massLimit)
|
||
return false;
|
||
|
||
if (checkEnable)
|
||
{
|
||
// Allowing picking up of bouncebombs.
|
||
CBounceBomb *pBomb = dynamic_cast<CBounceBomb*>(pObject);
|
||
if (pBomb)
|
||
return true;
|
||
|
||
// Allow pickup of phys props that are motion enabled on player pickup
|
||
CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>(pObject);
|
||
CPhysBox *pBox = dynamic_cast<CPhysBox*>(pObject);
|
||
if (!pProp && !pBox)
|
||
return false;
|
||
|
||
if (pProp && !(pProp->HasSpawnFlags(SF_PHYSPROP_ENABLE_ON_PHYSCANNON)))
|
||
return false;
|
||
|
||
if (pBox && !(pBox->HasSpawnFlags(SF_PHYSBOX_ENABLE_ON_PHYSCANNON)))
|
||
return false;
|
||
}
|
||
|
||
if (sizeLimit > 0)
|
||
{
|
||
const Vector &size = pObject->CollisionProp()->OBBSize();
|
||
if (size.x > sizeLimit || size.y > sizeLimit || size.z > sizeLimit)
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
|
||
float CBasePlayer::GetHeldObjectMass(IPhysicsObject *pHeldObject)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Server side of jumping rules. Most jumping logic is already
|
||
// handled in shared gamemovement code. Put stuff here that should
|
||
// only be done server side.
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::Jump()
|
||
{
|
||
}
|
||
|
||
void CBasePlayer::Duck()
|
||
{
|
||
if (m_nButtons & IN_DUCK)
|
||
{
|
||
if (m_Activity != ACT_LEAP)
|
||
{
|
||
SetAnimation(PLAYER_WALK);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// ID's player as such.
|
||
//
|
||
Class_T CBasePlayer::Classify(void)
|
||
{
|
||
return CLASS_PLAYER;
|
||
}
|
||
|
||
|
||
void CBasePlayer::ResetFragCount()
|
||
{
|
||
m_iFrags = 0;
|
||
pl.frags = m_iFrags;
|
||
}
|
||
|
||
void CBasePlayer::IncrementFragCount(int nCount)
|
||
{
|
||
m_iFrags += nCount;
|
||
pl.frags = m_iFrags;
|
||
}
|
||
|
||
void CBasePlayer::ResetDeathCount()
|
||
{
|
||
m_iDeaths = 0;
|
||
pl.deaths = m_iDeaths;
|
||
}
|
||
|
||
void CBasePlayer::IncrementDeathCount(int nCount)
|
||
{
|
||
m_iDeaths += nCount;
|
||
pl.deaths = m_iDeaths;
|
||
}
|
||
|
||
void CBasePlayer::AddPoints(int score, bool bAllowNegativeScore)
|
||
{
|
||
// Positive score always adds
|
||
if (score < 0)
|
||
{
|
||
if (!bAllowNegativeScore)
|
||
{
|
||
if (m_iFrags < 0) // Can't go more negative
|
||
return;
|
||
|
||
if (-score > m_iFrags) // Will this go negative?
|
||
{
|
||
score = -m_iFrags; // Sum will be 0
|
||
}
|
||
}
|
||
}
|
||
|
||
m_iFrags += score;
|
||
pl.frags = m_iFrags;
|
||
}
|
||
|
||
void CBasePlayer::AddPointsToTeam(int score, bool bAllowNegativeScore)
|
||
{
|
||
if (GetTeam())
|
||
{
|
||
GetTeam()->AddScore(score);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Output : int
|
||
//-----------------------------------------------------------------------------
|
||
int CBasePlayer::GetCommandContextCount(void) const
|
||
{
|
||
return m_CommandContext.Count();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : index -
|
||
// Output : CCommandContext
|
||
//-----------------------------------------------------------------------------
|
||
CCommandContext *CBasePlayer::GetCommandContext(int index)
|
||
{
|
||
if (index < 0 || index >= m_CommandContext.Count())
|
||
return NULL;
|
||
|
||
return &m_CommandContext[index];
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
CCommandContext *CBasePlayer::AllocCommandContext(void)
|
||
{
|
||
int idx = m_CommandContext.AddToTail();
|
||
if (m_CommandContext.Count() > 1000)
|
||
{
|
||
Assert(0);
|
||
}
|
||
return &m_CommandContext[idx];
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : index -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::RemoveCommandContext(int index)
|
||
{
|
||
m_CommandContext.Remove(index);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::RemoveAllCommandContexts()
|
||
{
|
||
m_CommandContext.RemoveAll();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Removes all existing contexts, but leaves the last one around ( or creates it if it doesn't exist -- which would be a bug )
|
||
//-----------------------------------------------------------------------------
|
||
CCommandContext *CBasePlayer::RemoveAllCommandContextsExceptNewest(void)
|
||
{
|
||
int count = m_CommandContext.Count();
|
||
int toRemove = count - 1;
|
||
if (toRemove > 0)
|
||
{
|
||
m_CommandContext.RemoveMultiple(0, toRemove);
|
||
}
|
||
|
||
if (!m_CommandContext.Count())
|
||
{
|
||
Assert(0);
|
||
CCommandContext *ctx = AllocCommandContext();
|
||
Q_memset(ctx, 0, sizeof(*ctx));
|
||
}
|
||
|
||
return &m_CommandContext[0];
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Replaces the first nCommands CUserCmds in the context with the ones passed in -- this is used to help meter out CUserCmds over the number of simulation ticks on the server
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ReplaceContextCommands(CCommandContext *ctx, CUserCmd *pCommands, int nCommands)
|
||
{
|
||
// Blow away all of the commands
|
||
ctx->cmds.RemoveAll();
|
||
|
||
ctx->numcmds = nCommands;
|
||
ctx->totalcmds = nCommands;
|
||
ctx->dropped_packets = 0; // meaningless in this context
|
||
|
||
// Add them in so the most recent is at slot 0
|
||
for (int i = nCommands - 1; i >= 0; --i)
|
||
{
|
||
ctx->cmds.AddToTail(pCommands[i]);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Determine how much time we will be running this frame
|
||
// Output : float
|
||
//-----------------------------------------------------------------------------
|
||
int CBasePlayer::DetermineSimulationTicks(void)
|
||
{
|
||
int command_context_count = GetCommandContextCount();
|
||
|
||
int context_number;
|
||
|
||
int simulation_ticks = 0;
|
||
|
||
// Determine how much time we will be running this frame and fixup player clock as needed
|
||
for (context_number = 0; context_number < command_context_count; context_number++)
|
||
{
|
||
CCommandContext const *ctx = GetCommandContext(context_number);
|
||
Assert(ctx);
|
||
Assert(ctx->numcmds > 0);
|
||
Assert(ctx->dropped_packets >= 0);
|
||
|
||
// Determine how long it will take to run those packets
|
||
simulation_ticks += ctx->numcmds + ctx->dropped_packets;
|
||
}
|
||
|
||
return simulation_ticks;
|
||
}
|
||
|
||
// 2 ticks ahead or behind current clock means we need to fix clock on client
|
||
static ConVar sv_clockcorrection_msecs("sv_clockcorrection_msecs", "60", 0, "The server tries to keep each player's m_nTickBase withing this many msecs of the server absolute tickcount");
|
||
static ConVar sv_playerperfhistorycount("sv_playerperfhistorycount", "60", 0, "Number of samples to maintain in player perf history", true, 1.0f, true, 128.0);
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Based upon amount of time in simulation time, adjust m_nTickBase so that
|
||
// we just end at the end of the current frame (so the player is basically on clock
|
||
// with the server)
|
||
// Input : simulation_ticks -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::AdjustPlayerTimeBase(int simulation_ticks)
|
||
{
|
||
Assert(simulation_ticks >= 0);
|
||
if (simulation_ticks < 0)
|
||
return;
|
||
|
||
CPlayerSimInfo *pi = NULL;
|
||
if (sv_playerperfhistorycount.GetInt() > 0)
|
||
{
|
||
while (m_vecPlayerSimInfo.Count() > sv_playerperfhistorycount.GetInt())
|
||
{
|
||
m_vecPlayerSimInfo.Remove(m_vecPlayerSimInfo.Head());
|
||
}
|
||
|
||
pi = &m_vecPlayerSimInfo[m_vecPlayerSimInfo.AddToTail()];
|
||
}
|
||
|
||
// Start in the past so that we get to the sv.time that we'll hit at the end of the
|
||
// frame, just as we process the final command
|
||
|
||
if (gpGlobals->maxClients == 1)
|
||
{
|
||
// set TickBase so that player simulation tick matches gpGlobals->tickcount after
|
||
// all commands have been executed
|
||
m_nTickBase = gpGlobals->tickcount - simulation_ticks + gpGlobals->simTicksThisFrame;
|
||
}
|
||
else // multiplayer
|
||
{
|
||
float flCorrectionSeconds = clamp(sv_clockcorrection_msecs.GetFloat() / 1000.0f, 0.0f, 1.0f);
|
||
int nCorrectionTicks = TIME_TO_TICKS(flCorrectionSeconds);
|
||
|
||
// Set the target tick flCorrectionSeconds (rounded to ticks) ahead in the future. this way the client can
|
||
// alternate around this target tick without getting smaller than gpGlobals->tickcount.
|
||
// After running the commands simulation time should be equal or after current gpGlobals->tickcount,
|
||
// otherwise the simulation time drops out of the client side interpolated var history window.
|
||
|
||
int nIdealFinalTick = gpGlobals->tickcount + nCorrectionTicks;
|
||
|
||
int nEstimatedFinalTick = m_nTickBase + simulation_ticks;
|
||
|
||
// If client gets ahead of this, we'll need to correct
|
||
int too_fast_limit = nIdealFinalTick + nCorrectionTicks;
|
||
// If client falls behind this, we'll also need to correct
|
||
int too_slow_limit = nIdealFinalTick - nCorrectionTicks;
|
||
|
||
// See if we are too fast
|
||
if (nEstimatedFinalTick > too_fast_limit ||
|
||
nEstimatedFinalTick < too_slow_limit)
|
||
{
|
||
int nCorrectedTick = nIdealFinalTick - simulation_ticks + gpGlobals->simTicksThisFrame;
|
||
|
||
if (pi)
|
||
{
|
||
pi->m_nTicksCorrected = nCorrectionTicks;
|
||
}
|
||
|
||
m_nTickBase = nCorrectedTick;
|
||
}
|
||
}
|
||
|
||
if (pi)
|
||
{
|
||
pi->m_flFinalSimulationTime = TICKS_TO_TIME(m_nTickBase + simulation_ticks + gpGlobals->simTicksThisFrame);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::RunNullCommand(void)
|
||
{
|
||
CUserCmd cmd; // NULL command
|
||
|
||
// Store off the globals.. they're gonna get whacked
|
||
float flOldFrametime = gpGlobals->frametime;
|
||
float flOldCurtime = gpGlobals->curtime;
|
||
|
||
pl.fixangle = FIXANGLE_NONE;
|
||
|
||
if (IsReplay())
|
||
{
|
||
cmd.viewangles = QAngle(0, 0, 0);
|
||
}
|
||
else
|
||
{
|
||
cmd.viewangles = EyeAngles();
|
||
}
|
||
|
||
float flTimeBase = gpGlobals->curtime;
|
||
SetTimeBase(flTimeBase);
|
||
|
||
MoveHelperServer()->SetHost(this);
|
||
PlayerRunCommand(&cmd, MoveHelperServer());
|
||
|
||
// save off the last good usercmd
|
||
SetLastUserCommand(cmd);
|
||
|
||
// Restore the globals..
|
||
gpGlobals->frametime = flOldFrametime;
|
||
gpGlobals->curtime = flOldCurtime;
|
||
|
||
MoveHelperServer()->SetHost(NULL);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Note, don't chain to BaseClass::PhysicsSimulate
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::PhysicsSimulate(void)
|
||
{
|
||
VPROF_BUDGET("CBasePlayer::PhysicsSimulate", VPROF_BUDGETGROUP_PLAYER);
|
||
|
||
// If we've got a moveparent, we must simulate that first.
|
||
CBaseEntity *pMoveParent = GetMoveParent();
|
||
if (pMoveParent)
|
||
{
|
||
pMoveParent->PhysicsSimulate();
|
||
}
|
||
|
||
// Make sure not to simulate this guy twice per frame
|
||
if (m_nSimulationTick == gpGlobals->tickcount)
|
||
{
|
||
return;
|
||
}
|
||
|
||
m_nSimulationTick = gpGlobals->tickcount;
|
||
|
||
// See how many CUserCmds are queued up for running
|
||
int simulation_ticks = DetermineSimulationTicks();
|
||
|
||
// If some time will elapse, make sure our clock (m_nTickBase) starts at the correct time
|
||
if (simulation_ticks > 0)
|
||
{
|
||
AdjustPlayerTimeBase(simulation_ticks);
|
||
}
|
||
|
||
if (IsHLTV() || IsReplay())
|
||
{
|
||
// just run a single, empty command to make sure
|
||
// all PreThink/PostThink functions are called as usual
|
||
Assert(GetCommandContextCount() == 0);
|
||
RunNullCommand();
|
||
RemoveAllCommandContexts();
|
||
return;
|
||
}
|
||
|
||
// Store off true server timestamps
|
||
float savetime = gpGlobals->curtime;
|
||
float saveframetime = gpGlobals->frametime;
|
||
|
||
int command_context_count = GetCommandContextCount();
|
||
|
||
|
||
// Build a list of all available commands
|
||
CUtlVector< CUserCmd > vecAvailCommands;
|
||
|
||
// Contexts go from oldest to newest
|
||
for (int context_number = 0; context_number < command_context_count; context_number++)
|
||
{
|
||
// Get oldest ( newer are added to tail )
|
||
CCommandContext *ctx = GetCommandContext(context_number);
|
||
if (!ShouldRunCommandsInContext(ctx))
|
||
continue;
|
||
|
||
if (!ctx->cmds.Count())
|
||
continue;
|
||
|
||
int numbackup = ctx->totalcmds - ctx->numcmds;
|
||
|
||
// If we haven't dropped too many packets, then run some commands
|
||
if (ctx->dropped_packets < 24)
|
||
{
|
||
int droppedcmds = ctx->dropped_packets;
|
||
|
||
// run the last known cmd for each dropped cmd we don't have a backup for
|
||
while (droppedcmds > numbackup)
|
||
{
|
||
m_LastCmd.tick_count++;
|
||
vecAvailCommands.AddToTail(m_LastCmd);
|
||
droppedcmds--;
|
||
}
|
||
|
||
// Now run the "history" commands if we still have dropped packets
|
||
while (droppedcmds > 0)
|
||
{
|
||
int cmdnum = ctx->numcmds + droppedcmds - 1;
|
||
vecAvailCommands.AddToTail(ctx->cmds[cmdnum]);
|
||
droppedcmds--;
|
||
}
|
||
}
|
||
|
||
// Now run any new command(s). Go backward because the most recent command is at index 0.
|
||
for (int i = ctx->numcmds - 1; i >= 0; i--)
|
||
{
|
||
vecAvailCommands.AddToTail(ctx->cmds[i]);
|
||
}
|
||
|
||
// Save off the last good command in case we drop > numbackup packets and need to rerun them
|
||
// we'll use this to "guess" at what was in the missing packets
|
||
m_LastCmd = ctx->cmds[CMD_MOSTRECENT];
|
||
}
|
||
|
||
// gpGlobals->simTicksThisFrame == number of ticks remaining to be run, so we should take the last N CUserCmds and postpone them until the next frame
|
||
|
||
// If we're running multiple ticks this frame, don't peel off all of the commands, spread them out over
|
||
// the server ticks. Use blocks of two in alternate ticks
|
||
int commandLimit = CBaseEntity::IsSimulatingOnAlternateTicks() ? 2 : 1;
|
||
int commandsToRun = vecAvailCommands.Count();
|
||
if (gpGlobals->simTicksThisFrame >= commandLimit && vecAvailCommands.Count() > commandLimit)
|
||
{
|
||
int commandsToRollOver = MIN(vecAvailCommands.Count(), (gpGlobals->simTicksThisFrame - 1));
|
||
commandsToRun = vecAvailCommands.Count() - commandsToRollOver;
|
||
Assert(commandsToRun >= 0);
|
||
// Clear all contexts except the last one
|
||
if (commandsToRollOver > 0)
|
||
{
|
||
CCommandContext *ctx = RemoveAllCommandContextsExceptNewest();
|
||
ReplaceContextCommands(ctx, &vecAvailCommands[commandsToRun], commandsToRollOver);
|
||
}
|
||
else
|
||
{
|
||
// Clear all contexts
|
||
RemoveAllCommandContexts();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Clear all contexts
|
||
RemoveAllCommandContexts();
|
||
}
|
||
|
||
float vphysicsArrivalTime = TICK_INTERVAL;
|
||
|
||
#ifdef _DEBUG
|
||
if (sv_player_net_suppress_usercommands.GetBool())
|
||
{
|
||
commandsToRun = 0;
|
||
}
|
||
#endif // _DEBUG
|
||
|
||
int numUsrCmdProcessTicksMax = sv_maxusrcmdprocessticks.GetInt();
|
||
if (gpGlobals->maxClients != 1 && numUsrCmdProcessTicksMax) // don't apply this filter in SP games
|
||
{
|
||
// Grant the client some time buffer to execute user commands
|
||
m_flMovementTimeForUserCmdProcessingRemaining += TICK_INTERVAL;
|
||
|
||
// but never accumulate more than N ticks
|
||
if (m_flMovementTimeForUserCmdProcessingRemaining > numUsrCmdProcessTicksMax * TICK_INTERVAL)
|
||
m_flMovementTimeForUserCmdProcessingRemaining = numUsrCmdProcessTicksMax * TICK_INTERVAL;
|
||
}
|
||
else
|
||
{
|
||
// Otherwise we don't care to track time
|
||
m_flMovementTimeForUserCmdProcessingRemaining = FLT_MAX;
|
||
}
|
||
|
||
// Now run the commands
|
||
if (commandsToRun > 0)
|
||
{
|
||
m_flLastUserCommandTime = savetime;
|
||
|
||
MoveHelperServer()->SetHost(this);
|
||
|
||
// Suppress predicted events, etc.
|
||
if (IsPredictingWeapons())
|
||
{
|
||
IPredictionSystem::SuppressHostEvents(this);
|
||
}
|
||
|
||
for (int i = 0; i < commandsToRun; ++i)
|
||
{
|
||
PlayerRunCommand(&vecAvailCommands[i], MoveHelperServer());
|
||
|
||
// Update our vphysics object.
|
||
if (m_pPhysicsController)
|
||
{
|
||
VPROF("CBasePlayer::PhysicsSimulate-UpdateVPhysicsPosition");
|
||
// If simulating at 2 * TICK_INTERVAL, add an extra TICK_INTERVAL to position arrival computation
|
||
UpdateVPhysicsPosition(m_vNewVPhysicsPosition, m_vNewVPhysicsVelocity, vphysicsArrivalTime);
|
||
vphysicsArrivalTime += TICK_INTERVAL;
|
||
}
|
||
}
|
||
|
||
// Always reset after running commands
|
||
IPredictionSystem::SuppressHostEvents(NULL);
|
||
|
||
MoveHelperServer()->SetHost(NULL);
|
||
|
||
// Copy in final origin from simulation
|
||
CPlayerSimInfo *pi = NULL;
|
||
if (m_vecPlayerSimInfo.Count() > 0)
|
||
{
|
||
pi = &m_vecPlayerSimInfo[m_vecPlayerSimInfo.Tail()];
|
||
pi->m_flTime = Plat_FloatTime();
|
||
pi->m_vecAbsOrigin = GetAbsOrigin();
|
||
pi->m_flGameSimulationTime = gpGlobals->curtime;
|
||
pi->m_nNumCmds = commandsToRun;
|
||
}
|
||
}
|
||
|
||
// Restore the true server clock
|
||
// FIXME: Should this occur after simulation of children so
|
||
// that they are in the timespace of the player?
|
||
gpGlobals->curtime = savetime;
|
||
gpGlobals->frametime = saveframetime;
|
||
|
||
// // Kick the player if they haven't sent a user command in awhile in order to prevent clients
|
||
// // from using packet-level manipulation to mess with gamestate. Not sending usercommands seems
|
||
// // to have all kinds of bad effects, such as stalling a bunch of Think()'s and gamestate handling.
|
||
// // An example from TF: A medic stops sending commands after deploying an uber on another player.
|
||
// // As a result, invuln is permanently on the heal target because the maintenance code is stalled.
|
||
// if ( GetTimeSinceLastUserCommand() > player_usercommand_timeout.GetFloat() )
|
||
// {
|
||
// // If they have an active netchan, they're almost certainly messing with usercommands?
|
||
// INetChannelInfo *pNetChanInfo = engine->GetPlayerNetInfo( entindex() );
|
||
// if ( pNetChanInfo && pNetChanInfo->GetTimeSinceLastReceived() < 5.f )
|
||
// {
|
||
// engine->ServerCommand( UTIL_VarArgs( "kickid %d %s\n", GetUserID(), "UserCommand Timeout" ) );
|
||
// }
|
||
// }
|
||
}
|
||
|
||
unsigned int CBasePlayer::PhysicsSolidMaskForEntity() const
|
||
{
|
||
return MASK_PLAYERSOLID;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: This will force usercmd processing to actually consume commands even if the global tick counter isn't incrementing
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ForceSimulation()
|
||
{
|
||
m_nSimulationTick = -1;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *buf -
|
||
// totalcmds -
|
||
// dropped_packets -
|
||
// ignore -
|
||
// paused -
|
||
// Output : float -- Time in seconds of last movement command
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ProcessUsercmds(CUserCmd *cmds, int numcmds, int totalcmds,
|
||
int dropped_packets, bool paused)
|
||
{
|
||
CCommandContext *ctx = AllocCommandContext();
|
||
Assert(ctx);
|
||
|
||
int i;
|
||
for (i = totalcmds - 1; i >= 0; i--)
|
||
{
|
||
CUserCmd *pCmd = &cmds[totalcmds - 1 - i];
|
||
|
||
// Validate values
|
||
if (!IsUserCmdDataValid(pCmd))
|
||
{
|
||
pCmd->MakeInert();
|
||
}
|
||
|
||
ctx->cmds.AddToTail(*pCmd);
|
||
}
|
||
ctx->numcmds = numcmds;
|
||
ctx->totalcmds = totalcmds,
|
||
ctx->dropped_packets = dropped_packets;
|
||
ctx->paused = paused;
|
||
|
||
// If the server is paused, zero out motion,buttons,view changes
|
||
if (ctx->paused)
|
||
{
|
||
bool clear_angles = true;
|
||
|
||
// If no clipping and cheats enabled and sv_noclipduringpause enabled, then don't zero out movement part of CUserCmd
|
||
if (GetMoveType() == MOVETYPE_NOCLIP &&
|
||
sv_cheats->GetBool() &&
|
||
sv_noclipduringpause.GetBool())
|
||
{
|
||
clear_angles = false;
|
||
}
|
||
|
||
for (i = 0; i < ctx->numcmds; i++)
|
||
{
|
||
ctx->cmds[i].buttons = 0;
|
||
if (clear_angles)
|
||
{
|
||
ctx->cmds[i].forwardmove = 0;
|
||
ctx->cmds[i].sidemove = 0;
|
||
ctx->cmds[i].upmove = 0;
|
||
VectorCopy(pl.v_angle, ctx->cmds[i].viewangles);
|
||
}
|
||
}
|
||
|
||
ctx->dropped_packets = 0;
|
||
}
|
||
|
||
// Set global pause state for this player
|
||
m_bGamePaused = paused;
|
||
|
||
if (paused)
|
||
{
|
||
ForceSimulation();
|
||
// Just run the commands right away if paused
|
||
PhysicsSimulate();
|
||
}
|
||
|
||
if (sv_playerperfhistorycount.GetInt() > 0)
|
||
{
|
||
CPlayerCmdInfo pi;
|
||
pi.m_flTime = Plat_FloatTime();
|
||
pi.m_nDroppedPackets = dropped_packets;
|
||
pi.m_nNumCmds = numcmds;
|
||
|
||
while (m_vecPlayerCmdInfo.Count() >= sv_playerperfhistorycount.GetInt())
|
||
{
|
||
m_vecPlayerCmdInfo.Remove(m_vecPlayerCmdInfo.Head());
|
||
}
|
||
|
||
m_vecPlayerCmdInfo.AddToTail(pi);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Check that command values are reasonable
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::IsUserCmdDataValid(CUserCmd *pCmd)
|
||
{
|
||
if (IsBot() || IsFakeClient())
|
||
return true;
|
||
|
||
// Maximum difference between client's and server's tick_count
|
||
const int nCmdMaxTickDelta = (1.f / gpGlobals->interval_per_tick) * 2.5f;
|
||
const int nMinDelta = Max(0, gpGlobals->tickcount - nCmdMaxTickDelta);
|
||
const int nMaxDelta = gpGlobals->tickcount + nCmdMaxTickDelta;
|
||
|
||
bool bValid = (pCmd->tick_count >= nMinDelta && pCmd->tick_count < nMaxDelta) &&
|
||
// Prevent clients from sending invalid view angles to try to get leaf server code to crash
|
||
(pCmd->viewangles.IsValid() && IsEntityQAngleReasonable(pCmd->viewangles)) &&
|
||
// Movement ranges
|
||
(IsFinite(pCmd->forwardmove) && IsEntityCoordinateReasonable(pCmd->forwardmove)) &&
|
||
(IsFinite(pCmd->sidemove) && IsEntityCoordinateReasonable(pCmd->sidemove)) &&
|
||
(IsFinite(pCmd->upmove) && IsEntityCoordinateReasonable(pCmd->upmove));
|
||
|
||
int nWarningLevel = sv_player_display_usercommand_errors.GetInt();
|
||
if (!bValid && nWarningLevel > 0)
|
||
{
|
||
DevMsg("UserCommand out-of-range for userid %i\n", GetUserID());
|
||
|
||
if (nWarningLevel == 2)
|
||
{
|
||
DevMsg(" tick_count: %i\n viewangles: %5.2f %5.2f %5.2f \n forward: %5.2f \n side: \t%5.2f \n up: \t%5.2f\n",
|
||
pCmd->tick_count,
|
||
pCmd->viewangles.x,
|
||
pCmd->viewangles.y,
|
||
pCmd->viewangles.x,
|
||
pCmd->forwardmove,
|
||
pCmd->sidemove,
|
||
pCmd->upmove);
|
||
}
|
||
}
|
||
|
||
return bValid;
|
||
}
|
||
|
||
void CBasePlayer::DumpPerfToRecipient(CBasePlayer *pRecipient, int nMaxRecords)
|
||
{
|
||
if (!pRecipient)
|
||
return;
|
||
|
||
char buf[256] = { 0 };
|
||
int curpos = 0;
|
||
|
||
int nDumped = 0;
|
||
Vector prevo(0, 0, 0);
|
||
float prevt = 0.0f;
|
||
|
||
for (int i = m_vecPlayerSimInfo.Tail(); i != m_vecPlayerSimInfo.InvalidIndex(); i = m_vecPlayerSimInfo.Previous(i))
|
||
{
|
||
const CPlayerSimInfo *pi = &m_vecPlayerSimInfo[i];
|
||
|
||
float vel = 0.0f;
|
||
|
||
// Note we're walking from newest backward
|
||
float dt = prevt - pi->m_flFinalSimulationTime;
|
||
if (nDumped > 0 && dt > 0.0f)
|
||
{
|
||
Vector d = pi->m_vecAbsOrigin - prevo;
|
||
vel = d.Length() / dt;
|
||
}
|
||
|
||
char line[128];
|
||
int len = Q_snprintf(line, sizeof(line), "%.3f %d %d %.3f %.3f vel %.2f\n",
|
||
pi->m_flTime,
|
||
pi->m_nNumCmds,
|
||
pi->m_nTicksCorrected,
|
||
pi->m_flFinalSimulationTime,
|
||
pi->m_flGameSimulationTime,
|
||
vel);
|
||
|
||
if (curpos + len > 200)
|
||
{
|
||
ClientPrint(pRecipient, HUD_PRINTCONSOLE, (char const *)buf);
|
||
buf[0] = 0;
|
||
curpos = 0;
|
||
}
|
||
|
||
Q_strncpy(&buf[curpos], line, sizeof(buf) - curpos);
|
||
curpos += len;
|
||
|
||
++nDumped;
|
||
if (nMaxRecords != -1 && nDumped >= nMaxRecords)
|
||
break;
|
||
|
||
prevo = pi->m_vecAbsOrigin;
|
||
prevt = pi->m_flFinalSimulationTime;
|
||
}
|
||
|
||
if (curpos > 0)
|
||
{
|
||
ClientPrint(pRecipient, HUD_PRINTCONSOLE, buf);
|
||
}
|
||
|
||
nDumped = 0;
|
||
curpos = 0;
|
||
|
||
for (int i = m_vecPlayerCmdInfo.Tail(); i != m_vecPlayerCmdInfo.InvalidIndex(); i = m_vecPlayerCmdInfo.Previous(i))
|
||
{
|
||
const CPlayerCmdInfo *pi = &m_vecPlayerCmdInfo[i];
|
||
|
||
char line[128];
|
||
int len = Q_snprintf(line, sizeof(line), "%.3f %d %d\n",
|
||
pi->m_flTime,
|
||
pi->m_nNumCmds,
|
||
pi->m_nDroppedPackets);
|
||
|
||
if (curpos + len > 200)
|
||
{
|
||
ClientPrint(pRecipient, HUD_PRINTCONSOLE, (char const *)buf);
|
||
buf[0] = 0;
|
||
curpos = 0;
|
||
}
|
||
|
||
Q_strncpy(&buf[curpos], line, sizeof(buf) - curpos);
|
||
curpos += len;
|
||
|
||
++nDumped;
|
||
if (nMaxRecords != -1 && nDumped >= nMaxRecords)
|
||
break;
|
||
}
|
||
|
||
if (curpos > 0)
|
||
{
|
||
ClientPrint(pRecipient, HUD_PRINTCONSOLE, buf);
|
||
}
|
||
}
|
||
|
||
// Duck debouncing code to stop menu changes from disallowing crouch/uncrouch
|
||
ConVar xc_crouch_debounce("xc_crouch_debounce", "0", FCVAR_NONE);
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *ucmd -
|
||
// *moveHelper -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper)
|
||
{
|
||
m_touchedPhysObject = false;
|
||
|
||
if (pl.fixangle == FIXANGLE_NONE)
|
||
{
|
||
VectorCopy(ucmd->viewangles, pl.v_angle);
|
||
}
|
||
|
||
// Handle FL_FROZEN.
|
||
// Prevent player moving for some seconds after New Game, so that they pick up everything
|
||
if (GetFlags() & FL_FROZEN ||
|
||
(developer.GetInt() == 0 && gpGlobals->eLoadType == MapLoad_NewGame && gpGlobals->curtime < 3.0))
|
||
{
|
||
ucmd->forwardmove = 0;
|
||
ucmd->sidemove = 0;
|
||
ucmd->upmove = 0;
|
||
ucmd->buttons = 0;
|
||
ucmd->impulse = 0;
|
||
VectorCopy(pl.v_angle, ucmd->viewangles);
|
||
}
|
||
else
|
||
{
|
||
// Force a duck if we're toggled
|
||
if (GetToggledDuckState())
|
||
{
|
||
// If this is set, we've altered our menu options and need to debounce the duck
|
||
if (xc_crouch_debounce.GetBool())
|
||
{
|
||
ToggleDuck();
|
||
|
||
// Mark it as handled
|
||
xc_crouch_debounce.SetValue(0);
|
||
}
|
||
else
|
||
{
|
||
ucmd->buttons |= IN_DUCK;
|
||
}
|
||
}
|
||
}
|
||
|
||
PlayerMove()->RunCommand(this, ucmd, moveHelper);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Strips off IN_xxx flags from the player's input
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::DisableButtons(int nButtons)
|
||
{
|
||
m_afButtonDisabled |= nButtons;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Re-enables stripped IN_xxx flags to the player's input
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::EnableButtons(int nButtons)
|
||
{
|
||
m_afButtonDisabled &= ~nButtons;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Strips off IN_xxx flags from the player's input
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ForceButtons(int nButtons)
|
||
{
|
||
m_afButtonForced |= nButtons;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Re-enables stripped IN_xxx flags to the player's input
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::UnforceButtons(int nButtons)
|
||
{
|
||
m_afButtonForced &= ~nButtons;
|
||
}
|
||
|
||
void CBasePlayer::HandleFuncTrain(void)
|
||
{
|
||
if (m_afPhysicsFlags & PFLAG_DIROVERRIDE)
|
||
AddFlag(FL_ONTRAIN);
|
||
else
|
||
RemoveFlag(FL_ONTRAIN);
|
||
|
||
// Train speed control
|
||
if ((m_afPhysicsFlags & PFLAG_DIROVERRIDE) == 0)
|
||
{
|
||
if (m_iTrain & TRAIN_ACTIVE)
|
||
{
|
||
m_iTrain = TRAIN_NEW; // turn off train
|
||
}
|
||
return;
|
||
}
|
||
|
||
CBaseEntity *pTrain = GetGroundEntity();
|
||
float vel;
|
||
|
||
if (pTrain)
|
||
{
|
||
if (!(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE))
|
||
pTrain = NULL;
|
||
}
|
||
|
||
if (!pTrain)
|
||
{
|
||
if (GetActiveWeapon()->ObjectCaps() & FCAP_DIRECTIONAL_USE)
|
||
{
|
||
m_iTrain = TRAIN_ACTIVE | TRAIN_NEW;
|
||
|
||
if (m_nButtons & IN_FORWARD)
|
||
{
|
||
m_iTrain |= TRAIN_FAST;
|
||
}
|
||
else if (m_nButtons & IN_BACK)
|
||
{
|
||
m_iTrain |= TRAIN_BACK;
|
||
}
|
||
else
|
||
{
|
||
m_iTrain |= TRAIN_NEUTRAL;
|
||
}
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
trace_t trainTrace;
|
||
// Maybe this is on the other side of a level transition
|
||
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -38),
|
||
MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trainTrace);
|
||
|
||
if (trainTrace.fraction != 1.0 && trainTrace.m_pEnt)
|
||
pTrain = trainTrace.m_pEnt;
|
||
|
||
|
||
if (!pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(this))
|
||
{
|
||
m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
|
||
m_iTrain = TRAIN_NEW | TRAIN_OFF;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else if (!(GetFlags() & FL_ONGROUND) || pTrain->HasSpawnFlags(SF_TRACKTRAIN_NOCONTROL) || (m_nButtons & (IN_MOVELEFT | IN_MOVERIGHT)))
|
||
{
|
||
// Turn off the train if you jump, strafe, or the train controls go dead
|
||
m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
|
||
m_iTrain = TRAIN_NEW | TRAIN_OFF;
|
||
return;
|
||
}
|
||
|
||
SetAbsVelocity(vec3_origin);
|
||
vel = 0;
|
||
if (m_afButtonPressed & IN_FORWARD)
|
||
{
|
||
vel = 1;
|
||
pTrain->Use(this, this, USE_SET, (float)vel);
|
||
}
|
||
else if (m_afButtonPressed & IN_BACK)
|
||
{
|
||
vel = -1;
|
||
pTrain->Use(this, this, USE_SET, (float)vel);
|
||
}
|
||
|
||
if (vel)
|
||
{
|
||
m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
|
||
m_iTrain |= TRAIN_ACTIVE | TRAIN_NEW;
|
||
}
|
||
}
|
||
|
||
|
||
void CBasePlayer::PreThink(void)
|
||
{
|
||
if (g_fGameOver || m_iPlayerLocked)
|
||
return; // intermission or finale
|
||
|
||
if (Hints())
|
||
{
|
||
Hints()->Update();
|
||
}
|
||
|
||
ItemPreFrame();
|
||
WaterMove();
|
||
|
||
if (g_pGameRules && g_pGameRules->FAllowFlashlight())
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
|
||
else
|
||
m_Local.m_iHideHUD |= HIDEHUD_FLASHLIGHT;
|
||
|
||
// checks if new client data (for HUD and view control) needs to be sent to the client
|
||
UpdateClientData();
|
||
|
||
CheckTimeBasedDamage();
|
||
|
||
CheckSuitUpdate();
|
||
|
||
if (GetObserverMode() > OBS_MODE_FREEZECAM)
|
||
{
|
||
CheckObserverSettings(); // do this each frame
|
||
}
|
||
|
||
if (m_lifeState >= LIFE_DYING)
|
||
{
|
||
// track where we are in the nav mesh even when dead
|
||
UpdateLastKnownArea();
|
||
return;
|
||
}
|
||
|
||
HandleFuncTrain();
|
||
|
||
if (m_nButtons & IN_JUMP)
|
||
{
|
||
// If on a ladder, jump off the ladder
|
||
// else Jump
|
||
Jump();
|
||
}
|
||
|
||
// If trying to duck, already ducked, or in the process of ducking
|
||
if ((m_nButtons & IN_DUCK) || (GetFlags() & FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING))
|
||
Duck();
|
||
|
||
//
|
||
// If we're not on the ground, we're falling. Update our falling velocity.
|
||
//
|
||
if (!(GetFlags() & FL_ONGROUND))
|
||
{
|
||
m_Local.m_flFallVelocity = -GetAbsVelocity().z;
|
||
}
|
||
|
||
// track where we are in the nav mesh
|
||
UpdateLastKnownArea();
|
||
|
||
|
||
// StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?
|
||
}
|
||
|
||
|
||
/* Time based Damage works as follows:
|
||
1) There are several types of timebased damage:
|
||
|
||
#define DMG_PARALYZE (1 << 14) // slows affected creature down
|
||
#define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad
|
||
#define DMG_POISON (1 << 16) // blood poisioning
|
||
#define DMG_RADIATION (1 << 17) // radiation exposure
|
||
#define DMG_DROWNRECOVER (1 << 18) // drown recovery
|
||
#define DMG_ACID (1 << 19) // toxic chemicals or acid burns
|
||
#define DMG_SLOWBURN (1 << 20) // in an oven
|
||
|
||
2) A new hit inflicting tbd restarts the tbd counter - each NPC has an 8bit counter,
|
||
per damage type. The counter is decremented every second, so the maximum time
|
||
an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius
|
||
of a damaging effect like fire, nervegas, radiation will continually reset the counter to max.
|
||
|
||
3) Every second that a tbd counter is running, the player takes damage. The damage
|
||
is determined by the type of tdb.
|
||
Paralyze - 1/2 movement rate, 30 second duration.
|
||
Nervegas - 5 points per second, 16 second duration = 80 points max dose.
|
||
Poison - 2 points per second, 25 second duration = 50 points max dose.
|
||
Radiation - 1 point per second, 50 second duration = 50 points max dose.
|
||
Drown - 5 points per second, 2 second duration.
|
||
Acid/Chemical - 5 points per second, 10 second duration = 50 points max.
|
||
Burn - 10 points per second, 2 second duration.
|
||
Freeze - 3 points per second, 10 second duration = 30 points max.
|
||
|
||
4) Certain actions or countermeasures counteract the damaging effects of tbds:
|
||
|
||
Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body
|
||
- recharged by suit recharger
|
||
Air In Lungs - drowning damage is done to air in lungs first, then to body
|
||
- recharged by poking head out of water
|
||
- 10 seconds if swiming fast
|
||
Air In SCUBA - drowning damage is done to air in tanks first, then to body
|
||
- 2 minutes in tanks. Need new tank once empty.
|
||
Radiation Syringe - Each syringe full provides protection vs one radiation dosage
|
||
Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison).
|
||
Health kit - Immediate stop to acid/chemical, fire or freeze damage.
|
||
Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage.
|
||
|
||
|
||
*/
|
||
|
||
// If player is taking time based damage, continue doing damage to player -
|
||
// this simulates the effect of being poisoned, gassed, dosed with radiation etc -
|
||
// anything that continues to do damage even after the initial contact stops.
|
||
// Update all time based damage counters, and shut off any that are done.
|
||
|
||
// The m_bitsDamageType bit MUST be set if any damage is to be taken.
|
||
// This routine will detect the initial on value of the m_bitsDamageType
|
||
// and init the appropriate counter. Only processes damage every second.
|
||
|
||
//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage
|
||
//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval
|
||
|
||
//#define NERVEGAS_DURATION 16
|
||
//#define NERVEGAS_DAMAGE 5.0
|
||
|
||
//#define POISON_DURATION 25
|
||
//#define POISON_DAMAGE 2.0
|
||
|
||
//#define RADIATION_DURATION 50
|
||
//#define RADIATION_DAMAGE 1.0
|
||
|
||
//#define ACID_DURATION 10
|
||
//#define ACID_DAMAGE 5.0
|
||
|
||
//#define SLOWBURN_DURATION 2
|
||
//#define SLOWBURN_DAMAGE 1.0
|
||
|
||
//#define SLOWFREEZE_DURATION 1.0
|
||
//#define SLOWFREEZE_DAMAGE 3.0
|
||
|
||
/* */
|
||
|
||
void CBasePlayer::CheckTimeBasedDamage()
|
||
{
|
||
int i;
|
||
byte bDuration = 0;
|
||
|
||
static float gtbdPrev = 0.0;
|
||
|
||
// If we don't have any time based damage return.
|
||
if (!g_pGameRules->Damage_IsTimeBased(m_bitsDamageType))
|
||
return;
|
||
|
||
// only check for time based damage approx. every 2 seconds
|
||
if (abs(gpGlobals->curtime - m_tbdPrev) < 2.0)
|
||
return;
|
||
|
||
m_tbdPrev = gpGlobals->curtime;
|
||
|
||
for (i = 0; i < CDMG_TIMEBASED; i++)
|
||
{
|
||
// Make sure the damage type is really time-based.
|
||
// This is kind of hacky but necessary until we setup DamageType as an enum.
|
||
int iDamage = (DMG_PARALYZE << i);
|
||
if (!g_pGameRules->Damage_IsTimeBased(iDamage))
|
||
continue;
|
||
|
||
|
||
// make sure bit is set for damage type
|
||
if (m_bitsDamageType & iDamage)
|
||
{
|
||
switch (i)
|
||
{
|
||
case itbd_Paralyze:
|
||
// UNDONE - flag movement as half-speed
|
||
bDuration = PARALYZE_DURATION;
|
||
break;
|
||
case itbd_NerveGas:
|
||
// OnTakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC);
|
||
bDuration = NERVEGAS_DURATION;
|
||
break;
|
||
// case itbd_Poison:
|
||
// OnTakeDamage( CTakeDamageInfo( this, this, POISON_DAMAGE, DMG_GENERIC ) );
|
||
// bDuration = POISON_DURATION;
|
||
// break;
|
||
case itbd_Radiation:
|
||
// OnTakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC);
|
||
bDuration = RADIATION_DURATION;
|
||
break;
|
||
case itbd_DrownRecover:
|
||
// NOTE: this hack is actually used to RESTORE health
|
||
// after the player has been drowning and finally takes a breath
|
||
if (m_idrowndmg > m_idrownrestored)
|
||
{
|
||
int idif = MIN(m_idrowndmg - m_idrownrestored, 10);
|
||
|
||
TakeHealth(idif, DMG_GENERIC);
|
||
m_idrownrestored += idif;
|
||
}
|
||
bDuration = 4; // get up to 5*10 = 50 points back
|
||
break;
|
||
|
||
case itbd_PoisonRecover:
|
||
{
|
||
// NOTE: this hack is actually used to RESTORE health
|
||
// after the player has been poisoned.
|
||
if (m_nPoisonDmg > m_nPoisonRestored)
|
||
{
|
||
int nDif = MIN(m_nPoisonDmg - m_nPoisonRestored, 10);
|
||
TakeHealth(nDif, DMG_GENERIC);
|
||
m_nPoisonRestored += nDif;
|
||
}
|
||
bDuration = 9; // get up to 10*10 = 100 points back
|
||
break;
|
||
}
|
||
|
||
case itbd_Acid:
|
||
// OnTakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC);
|
||
bDuration = ACID_DURATION;
|
||
break;
|
||
case itbd_SlowBurn:
|
||
// OnTakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC);
|
||
bDuration = SLOWBURN_DURATION;
|
||
break;
|
||
case itbd_SlowFreeze:
|
||
// OnTakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC);
|
||
bDuration = SLOWFREEZE_DURATION;
|
||
break;
|
||
default:
|
||
bDuration = 0;
|
||
}
|
||
|
||
if (m_rgbTimeBasedDamage[i])
|
||
{
|
||
// decrement damage duration, detect when done.
|
||
if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0)
|
||
{
|
||
m_rgbTimeBasedDamage[i] = 0;
|
||
// if we're done, clear damage bits
|
||
m_bitsDamageType &= ~(DMG_PARALYZE << i);
|
||
}
|
||
}
|
||
else
|
||
// first time taking this damage type - init damage duration
|
||
m_rgbTimeBasedDamage[i] = bDuration;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
THE POWER SUIT
|
||
|
||
The Suit provides 3 main functions: Protection, Notification and Augmentation.
|
||
Some functions are automatic, some require power.
|
||
The player gets the suit shortly after getting off the train in C1A0 and it stays
|
||
with him for the entire game.
|
||
|
||
Protection
|
||
|
||
Heat/Cold
|
||
When the player enters a hot/cold area, the heating/cooling indicator on the suit
|
||
will come on and the battery will drain while the player stays in the area.
|
||
After the battery is dead, the player starts to take damage.
|
||
This feature is built into the suit and is automatically engaged.
|
||
Radiation Syringe
|
||
This will cause the player to be immune from the effects of radiation for N seconds. Single use item.
|
||
Anti-Toxin Syringe
|
||
This will cure the player from being poisoned. Single use item.
|
||
Health
|
||
Small (1st aid kits, food, etc.)
|
||
Large (boxes on walls)
|
||
Armor
|
||
The armor works using energy to create a protective field that deflects a
|
||
percentage of damage projectile and explosive attacks. After the armor has been deployed,
|
||
it will attempt to recharge itself to full capacity with the energy reserves from the battery.
|
||
It takes the armor N seconds to fully charge.
|
||
|
||
Notification (via the HUD)
|
||
|
||
x Health
|
||
x Ammo
|
||
x Automatic Health Care
|
||
Notifies the player when automatic healing has been engaged.
|
||
x Geiger counter
|
||
Classic Geiger counter sound and status bar at top of HUD
|
||
alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal.
|
||
x Poison
|
||
Armor
|
||
Displays the current level of armor.
|
||
|
||
Augmentation
|
||
|
||
Reanimation (w/adrenaline)
|
||
Causes the player to come back to life after he has been dead for 3 seconds.
|
||
Will not work if player was gibbed. Single use.
|
||
Long Jump
|
||
Used by hitting the ??? key(s). Caused the player to further than normal.
|
||
SCUBA
|
||
Used automatically after picked up and after player enters the water.
|
||
Works for N seconds. Single use.
|
||
|
||
Things powered by the battery
|
||
|
||
Armor
|
||
Uses N watts for every M units of damage.
|
||
Heat/Cool
|
||
Uses N watts for every second in hot/cold area.
|
||
Long Jump
|
||
Uses N watts for every jump.
|
||
Alien Cloak
|
||
Uses N watts for each use. Each use lasts M seconds.
|
||
Alien Shield
|
||
Augments armor. Reduces Armor drain by one half
|
||
|
||
*/
|
||
|
||
// if in range of radiation source, ping geiger counter
|
||
|
||
#define GEIGERDELAY 0.25
|
||
|
||
void CBasePlayer::UpdateGeigerCounter(void)
|
||
{
|
||
byte range;
|
||
|
||
// delay per update ie: don't flood net with these msgs
|
||
if (gpGlobals->curtime < m_flgeigerDelay)
|
||
return;
|
||
|
||
m_flgeigerDelay = gpGlobals->curtime + GEIGERDELAY;
|
||
|
||
// send range to radition source to client
|
||
range = (byte)clamp(Floor2Int(m_flgeigerRange / 4), 0, 255);
|
||
|
||
// This is to make sure you aren't driven crazy by geiger while in the airboat
|
||
if (IsInAVehicle())
|
||
{
|
||
range = clamp((int)range * 4, 0, 255);
|
||
}
|
||
|
||
if (range != m_igeigerRangePrev)
|
||
{
|
||
m_igeigerRangePrev = range;
|
||
|
||
CSingleUserRecipientFilter user(this);
|
||
user.MakeReliable();
|
||
UserMessageBegin(user, "Geiger");
|
||
WRITE_BYTE(range);
|
||
MessageEnd();
|
||
}
|
||
|
||
// reset counter and semaphore
|
||
if (!random->RandomInt(0, 3))
|
||
{
|
||
m_flgeigerRange = 1000;
|
||
}
|
||
}
|
||
|
||
/*
|
||
================
|
||
CheckSuitUpdate
|
||
|
||
Play suit update if it's time
|
||
================
|
||
*/
|
||
|
||
#define SUITUPDATETIME 3.5
|
||
#define SUITFIRSTUPDATETIME 0.1
|
||
|
||
void CBasePlayer::CheckSuitUpdate()
|
||
{
|
||
int i;
|
||
int isentence = 0;
|
||
int isearch = m_iSuitPlayNext;
|
||
|
||
// Ignore suit updates if no suit
|
||
if (!IsSuitEquipped())
|
||
return;
|
||
|
||
// if in range of radiation source, ping geiger counter
|
||
UpdateGeigerCounter();
|
||
|
||
if (g_pGameRules->IsMultiplayer())
|
||
{
|
||
// don't bother updating HEV voice in multiplayer.
|
||
return;
|
||
}
|
||
|
||
if (gpGlobals->curtime >= m_flSuitUpdate && m_flSuitUpdate > 0)
|
||
{
|
||
// play a sentence off of the end of the queue
|
||
for (i = 0; i < CSUITPLAYLIST; i++)
|
||
{
|
||
if ((isentence = m_rgSuitPlayList[isearch]) != 0)
|
||
break;
|
||
|
||
if (++isearch == CSUITPLAYLIST)
|
||
isearch = 0;
|
||
}
|
||
|
||
if (isentence)
|
||
{
|
||
m_rgSuitPlayList[isearch] = 0;
|
||
if (isentence > 0)
|
||
{
|
||
// play sentence number
|
||
|
||
char sentence[512];
|
||
Q_snprintf(sentence, sizeof(sentence), "!%s", engine->SentenceNameFromIndex(isentence));
|
||
UTIL_EmitSoundSuit(edict(), sentence);
|
||
}
|
||
else
|
||
{
|
||
// play sentence group
|
||
UTIL_EmitGroupIDSuit(edict(), -isentence);
|
||
}
|
||
m_flSuitUpdate = gpGlobals->curtime + SUITUPDATETIME;
|
||
}
|
||
else
|
||
// queue is empty, don't check
|
||
m_flSuitUpdate = 0;
|
||
}
|
||
}
|
||
|
||
// add sentence to suit playlist queue. if fgroup is true, then
|
||
// name is a sentence group (HEV_AA), otherwise name is a specific
|
||
// sentence name ie: !HEV_AA0. If iNoRepeat is specified in
|
||
// seconds, then we won't repeat playback of this word or sentence
|
||
// for at least that number of seconds.
|
||
|
||
void CBasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeatTime)
|
||
{
|
||
int i;
|
||
int isentence;
|
||
int iempty = -1;
|
||
|
||
|
||
// Ignore suit updates if no suit
|
||
if (!IsSuitEquipped())
|
||
return;
|
||
|
||
if (g_pGameRules->IsMultiplayer())
|
||
{
|
||
// due to static channel design, etc. We don't play HEV sounds in multiplayer right now.
|
||
return;
|
||
}
|
||
|
||
// if name == NULL, then clear out the queue
|
||
|
||
if (!name)
|
||
{
|
||
for (i = 0; i < CSUITPLAYLIST; i++)
|
||
m_rgSuitPlayList[i] = 0;
|
||
return;
|
||
}
|
||
// get sentence or group number
|
||
if (!fgroup)
|
||
{
|
||
isentence = SENTENCEG_Lookup(name); // Lookup sentence index (not group) by name
|
||
if (isentence < 0)
|
||
return;
|
||
}
|
||
else
|
||
// mark group number as negative
|
||
isentence = -SENTENCEG_GetIndex(name); // Lookup group index by name
|
||
|
||
// check norepeat list - this list lets us cancel
|
||
// the playback of words or sentences that have already
|
||
// been played within a certain time.
|
||
|
||
for (i = 0; i < CSUITNOREPEAT; i++)
|
||
{
|
||
if (isentence == m_rgiSuitNoRepeat[i])
|
||
{
|
||
// this sentence or group is already in
|
||
// the norepeat list
|
||
|
||
if (m_rgflSuitNoRepeatTime[i] < gpGlobals->curtime)
|
||
{
|
||
// norepeat time has expired, clear it out
|
||
m_rgiSuitNoRepeat[i] = 0;
|
||
m_rgflSuitNoRepeatTime[i] = 0.0;
|
||
iempty = i;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
// don't play, still marked as norepeat
|
||
return;
|
||
}
|
||
}
|
||
// keep track of empty slot
|
||
if (!m_rgiSuitNoRepeat[i])
|
||
iempty = i;
|
||
}
|
||
|
||
// sentence is not in norepeat list, save if norepeat time was given
|
||
|
||
if (iNoRepeatTime)
|
||
{
|
||
if (iempty < 0)
|
||
iempty = random->RandomInt(0, CSUITNOREPEAT - 1); // pick random slot to take over
|
||
m_rgiSuitNoRepeat[iempty] = isentence;
|
||
m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->curtime;
|
||
}
|
||
|
||
// find empty spot in queue, or overwrite last spot
|
||
|
||
m_rgSuitPlayList[m_iSuitPlayNext++] = isentence;
|
||
if (m_iSuitPlayNext == CSUITPLAYLIST)
|
||
m_iSuitPlayNext = 0;
|
||
|
||
if (m_flSuitUpdate <= gpGlobals->curtime)
|
||
{
|
||
if (m_flSuitUpdate == 0)
|
||
// play queue is empty, don't delay too long before playback
|
||
m_flSuitUpdate = gpGlobals->curtime + SUITFIRSTUPDATETIME;
|
||
else
|
||
m_flSuitUpdate = gpGlobals->curtime + SUITUPDATETIME;
|
||
}
|
||
|
||
}
|
||
|
||
//=========================================================
|
||
// UpdatePlayerSound - updates the position of the player's
|
||
// reserved sound slot in the sound list.
|
||
//=========================================================
|
||
void CBasePlayer::UpdatePlayerSound(void)
|
||
{
|
||
int iBodyVolume;
|
||
int iVolume;
|
||
CSound *pSound;
|
||
|
||
pSound = CSoundEnt::SoundPointerForIndex(CSoundEnt::ClientSoundIndex(edict()));
|
||
|
||
if (!pSound)
|
||
{
|
||
Msg("Client lost reserved sound!\n");
|
||
return;
|
||
}
|
||
|
||
if (GetFlags() & FL_NOTARGET)
|
||
{
|
||
pSound->m_iVolume = 0;
|
||
return;
|
||
}
|
||
|
||
// now figure out how loud the player's movement is.
|
||
if (GetFlags() & FL_ONGROUND)
|
||
{
|
||
iBodyVolume = GetAbsVelocity().Length();
|
||
|
||
// clamp the noise that can be made by the body, in case a push trigger,
|
||
// weapon recoil, or anything shoves the player abnormally fast.
|
||
// NOTE: 512 units is a pretty large radius for a sound made by the player's body.
|
||
// then again, I think some materials are pretty loud.
|
||
if (iBodyVolume > 512)
|
||
{
|
||
iBodyVolume = 512;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
iBodyVolume = 0;
|
||
}
|
||
|
||
if (m_nButtons & IN_JUMP)
|
||
{
|
||
// Jumping is a little louder.
|
||
iBodyVolume += 100;
|
||
}
|
||
|
||
m_iTargetVolume = iBodyVolume;
|
||
|
||
// if target volume is greater than the player sound's current volume, we paste the new volume in
|
||
// immediately. If target is less than the current volume, current volume is not set immediately to the
|
||
// lower volume, rather works itself towards target volume over time. This gives NPCs a much better chance
|
||
// to hear a sound, especially if they don't listen every frame.
|
||
iVolume = pSound->Volume();
|
||
|
||
if (m_iTargetVolume > iVolume)
|
||
{
|
||
iVolume = m_iTargetVolume;
|
||
}
|
||
else if (iVolume > m_iTargetVolume)
|
||
{
|
||
iVolume -= 250 * gpGlobals->frametime;
|
||
|
||
if (iVolume < m_iTargetVolume)
|
||
{
|
||
iVolume = 0;
|
||
}
|
||
}
|
||
|
||
if (pSound)
|
||
{
|
||
pSound->SetSoundOrigin(GetAbsOrigin());
|
||
pSound->m_iType = SOUND_PLAYER;
|
||
pSound->m_iVolume = iVolume;
|
||
}
|
||
|
||
|
||
//CSoundPatch *m_sndCharge = enginesound->GetActiveSounds(CUtlVector< SndInfo_t >& sndlist);
|
||
/*CPASAttenuationFilter filter(this);
|
||
CSoundPatch *m_sndCharge;*/
|
||
|
||
/*SndInfo_t pitch;// = SndInfo_t::m_nPitch;
|
||
//CSoundEnvelopeController &pController = CSoundEnvelopeController::GetController();
|
||
|
||
//m_sndCharge = pController.SoundCreate(filter, entindex(), UTIL_RestartAmbientSounds);
|
||
//m_sndCharge = pController.SoundCreate()
|
||
CSoundEnvelopeController *Controller = &CSoundEnvelopeController::GetController();
|
||
Controller->SoundChangePitch(m_sndCharge, pitch.m_nPitch * cvar->FindVar("host_timescale")->GetFloat(), 0);*/
|
||
//float flVolume = pController->SoundGetVolume(m_pGunFiringSound);
|
||
// Below are a couple of useful little bits that make it easier to visualize just how much noise the
|
||
// player is making.
|
||
//Vector forward = UTIL_YawToVector( pl.v_angle.y );
|
||
//UTIL_Sparks( GetAbsOrigin() + forward * iVolume );
|
||
//Msg( "%d/%d\n", iVolume, m_iTargetVolume );
|
||
}
|
||
|
||
// This is a glorious hack to find free space when you've crouched into some solid space
|
||
// Our crouching collisions do not work correctly for some reason and this is easier
|
||
// than fixing the problem :(
|
||
void FixPlayerCrouchStuck(CBasePlayer *pPlayer)
|
||
{
|
||
trace_t trace;
|
||
|
||
// Move up as many as 18 pixels if the player is stuck.
|
||
int i;
|
||
Vector org = pPlayer->GetAbsOrigin();
|
||
for (i = 0; i < 18; i++)
|
||
{
|
||
UTIL_TraceHull(pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(),
|
||
VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (trace.startsolid)
|
||
{
|
||
Vector origin = pPlayer->GetAbsOrigin();
|
||
origin.z += 1.0f;
|
||
pPlayer->SetLocalOrigin(origin);
|
||
}
|
||
else
|
||
return;
|
||
}
|
||
|
||
pPlayer->SetAbsOrigin(org);
|
||
|
||
for (i = 0; i < 18; i++)
|
||
{
|
||
UTIL_TraceHull(pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(),
|
||
VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (trace.startsolid)
|
||
{
|
||
Vector origin = pPlayer->GetAbsOrigin();
|
||
origin.z -= 1.0f;
|
||
pPlayer->SetLocalOrigin(origin);
|
||
}
|
||
else
|
||
return;
|
||
}
|
||
}
|
||
#define SMOOTHING_FACTOR 0.9
|
||
extern CMoveData *g_pMoveData;
|
||
|
||
// UNDONE: Look and see if the ground entity is in hierarchy with a MOVETYPE_VPHYSICS?
|
||
// Behavior in that case is not as good currently when the parent is rideable
|
||
bool CBasePlayer::IsRideablePhysics(IPhysicsObject *pPhysics)
|
||
{
|
||
if (pPhysics)
|
||
{
|
||
if (pPhysics->GetMass() > (VPhysicsGetObject()->GetMass() * 2))
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
IPhysicsObject *CBasePlayer::GetGroundVPhysics()
|
||
{
|
||
CBaseEntity *pGroundEntity = GetGroundEntity();
|
||
if (pGroundEntity && pGroundEntity->GetMoveType() == MOVETYPE_VPHYSICS)
|
||
{
|
||
IPhysicsObject *pPhysGround = pGroundEntity->VPhysicsGetObject();
|
||
if (pPhysGround && pPhysGround->IsMoveable())
|
||
return pPhysGround;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// For debugging...
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ForceOrigin(const Vector &vecOrigin)
|
||
{
|
||
m_bForceOrigin = true;
|
||
m_vForcedOrigin = vecOrigin;
|
||
}
|
||
|
||
|
||
bool m_bBobWasInAir = false;
|
||
float m_flLastFallVelocity(0.0f);
|
||
float m_flLandBobDynamicScale(0.0f);
|
||
float m_flLandBobTime(0.0f);
|
||
|
||
|
||
ConVar oc_player_garbage_velocity_x("oc_player_garbage_velocity_x", "150");
|
||
ConVar oc_player_garbage_velocity_y("oc_player_garbage_velocity_y", "-125");
|
||
ConVar oc_player_garbage_velocity_z("oc_player_garbage_velocity_z", "0");
|
||
|
||
ConVar oc_player_garbage_pos_x("oc_player_garbage_pos_x", "-10");
|
||
ConVar oc_player_garbage_pos_y("oc_player_garbage_pos_y", "4");
|
||
ConVar oc_player_garbage_pos_z("oc_player_garbage_pos_z", "-10");
|
||
|
||
ConVar oc_player_garbage_drop_delay("oc_player_garbage_drop_delay", "1", FCVAR_ARCHIVE);
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::PostThink()
|
||
{
|
||
m_vecSmoothedVelocity = m_vecSmoothedVelocity * SMOOTHING_FACTOR + GetAbsVelocity() * (1 - SMOOTHING_FACTOR);
|
||
|
||
if (!g_fGameOver && !m_iPlayerLocked)
|
||
{
|
||
if (IsAlive())
|
||
{
|
||
// set correct collision bounds (may have changed in player movement code)
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-Bounds");
|
||
if (GetFlags() & FL_DUCKING)
|
||
{
|
||
SetCollisionBounds(VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
|
||
}
|
||
else
|
||
{
|
||
SetCollisionBounds(VEC_HULL_MIN, VEC_HULL_MAX);
|
||
}
|
||
VPROF_SCOPE_END();
|
||
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-Use");
|
||
// Handle controlling an entity
|
||
if (m_hUseEntity != NULL)
|
||
{
|
||
// if they've moved too far from the gun, or deployed another weapon, unuse the gun
|
||
if (m_hUseEntity->OnControls(this) &&
|
||
(!GetActiveWeapon() || GetActiveWeapon()->IsEffectActive(EF_NODRAW) ||
|
||
(GetActiveWeapon()->GetActivity() == ACT_VM_HOLSTER) || (GetActiveWeapon()->GetActivity() == ACT_VM_HOLSTER_SILENCED) // BriJee OVR: Silenced weapons bug fix
|
||
#ifdef PORTAL // Portalgun view model stays up when holding an object -Jeep
|
||
|| FClassnameIs(GetActiveWeapon(), "weapon_portalgun")
|
||
#endif //#ifdef PORTAL
|
||
))
|
||
{
|
||
m_hUseEntity->Use(this, this, USE_SET, 2); // try fire the gun
|
||
}
|
||
else
|
||
{
|
||
// they've moved off the controls
|
||
ClearUseEntity();
|
||
}
|
||
}
|
||
VPROF_SCOPE_END();
|
||
|
||
// do weapon stuff
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-ItemPostFrame");
|
||
ItemPostFrame();
|
||
VPROF_SCOPE_END();
|
||
|
||
if (GetFlags() & FL_ONGROUND)
|
||
{
|
||
if (m_Local.m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer())
|
||
{
|
||
CSoundEnt::InsertSound(SOUND_PLAYER, GetAbsOrigin(), m_Local.m_flFallVelocity, 0.2, this);
|
||
// Msg( "fall %f\n", m_Local.m_flFallVelocity );
|
||
}
|
||
m_Local.m_flFallVelocity = 0;
|
||
}
|
||
|
||
// select the proper animation for the player character
|
||
VPROF("CBasePlayer::PostThink-Animation");
|
||
// If he's in a vehicle, sit down
|
||
if (IsInAVehicle())
|
||
SetAnimation(PLAYER_IN_VEHICLE);
|
||
else if (!GetAbsVelocity().x && !GetAbsVelocity().y)
|
||
SetAnimation(PLAYER_IDLE);
|
||
else if ((GetAbsVelocity().x || GetAbsVelocity().y) && (GetFlags() & FL_ONGROUND))
|
||
SetAnimation(PLAYER_WALK);
|
||
else if (GetWaterLevel() > 1)
|
||
SetAnimation(PLAYER_WALK);
|
||
}
|
||
|
||
// Don't allow bogus sequence on player
|
||
if (GetSequence() == -1)
|
||
{
|
||
SetSequence(0);
|
||
}
|
||
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-StudioFrameAdvance");
|
||
StudioFrameAdvance();
|
||
VPROF_SCOPE_END();
|
||
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-DispatchAnimEvents");
|
||
DispatchAnimEvents(this);
|
||
VPROF_SCOPE_END();
|
||
|
||
SetSimulationTime(gpGlobals->curtime);
|
||
|
||
//Let the weapon update as well
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-Weapon_FrameUpdate");
|
||
Weapon_FrameUpdate();
|
||
VPROF_SCOPE_END();
|
||
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-UpdatePlayerSound");
|
||
UpdatePlayerSound();
|
||
VPROF_SCOPE_END();
|
||
|
||
if (m_bForceOrigin)
|
||
{
|
||
SetLocalOrigin(m_vForcedOrigin);
|
||
SetLocalAngles(m_Local.m_vecPunchAngle);
|
||
m_Local.m_vecPunchAngle = RandomAngle(-25, 25);
|
||
m_Local.m_vecPunchAngleVel.Init();
|
||
}
|
||
|
||
VPROF_SCOPE_BEGIN("CBasePlayer::PostThink-PostThinkVPhysics");
|
||
PostThinkVPhysics();
|
||
VPROF_SCOPE_END();
|
||
}
|
||
|
||
|
||
#if !defined( NO_ENTITY_PREDICTION )
|
||
// Even if dead simulate entities
|
||
SimulatePlayerSimulatedEntities();
|
||
#endif
|
||
|
||
//Blood overlay
|
||
if (m_bShouldDrawBloodOverlay)
|
||
{
|
||
if (m_flNextBloodDryDisappear < gpGlobals->curtime)
|
||
{
|
||
SetupBloodOverlayDelay(0.0f);
|
||
SetupBloodOverlay(false);
|
||
SetupWeaponBloodOverlay(false, true);
|
||
}
|
||
}
|
||
if (m_bCleanUpWeapons)
|
||
{
|
||
if (m_flNextBloodDryDisappear < gpGlobals->curtime)
|
||
SetupWeaponBloodOverlay(false, true);
|
||
}
|
||
|
||
//MikeD SlowMo
|
||
SlowMoHandle(); //ConColorMsg(m_bIsInSelectionMode ? Color(255, 0, 0, 255) : Color(0, 255, 0, 255), "m_bIsInSelectionMode: %i \n", m_bIsInSelectionMode);
|
||
|
||
bool dropUsedPerks = cvar->FindVar("oc_player_allow_drop_used_perks")->GetInt() ? true : false;
|
||
bool fastGrenThrow = cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt() ? true : false;
|
||
|
||
if (!engine->IsPaused() && !g_fGameOver && !IsPlayerLockedInPlace() && IsAlive())
|
||
{
|
||
bool sprintLower = cvar->FindVar("oc_weapons_allow_sprint_lower")->GetInt() ? true : false;
|
||
|
||
Vector velocity; int speed;
|
||
if (this->GetFlags() & FL_ONGROUND)
|
||
{
|
||
//this->EstimateAbsVelocity(velocity);
|
||
velocity = this->GetAbsVelocity();
|
||
speed = velocity.NormalizeInPlace();
|
||
}
|
||
else
|
||
{
|
||
speed = cvar->FindVar("hl2_normspeed")->GetInt();
|
||
}
|
||
|
||
if (sprintLower /*&& !pWeapon->IsIronSighted() && !pWeapon->IsScopeSighted()*/)
|
||
{
|
||
if (speed >= cvar->FindVar("hl2_sprintspeed")->GetInt() - 10)
|
||
{
|
||
m_bIsRunning = true;
|
||
}
|
||
if (speed < cvar->FindVar("hl2_sprintspeed")->GetInt() - 10)
|
||
{
|
||
m_bIsRunning = false;
|
||
}
|
||
}
|
||
else
|
||
m_bIsRunning = false;
|
||
|
||
if (dropUsedPerks && CanDropGarbage)
|
||
{
|
||
if (garbage.Count() > 0 && garbageIndex.Count() > 0)
|
||
{
|
||
if (gpGlobals->curtime > garbageIndex.Element(garbageIndex.Count() - 1))
|
||
{
|
||
DropGarbage();
|
||
}
|
||
}
|
||
}
|
||
|
||
//MikeN/OVR - Grenade throwing
|
||
if (!IsInAVehicle())
|
||
{
|
||
CheckCamAttachment();
|
||
|
||
if (fastGrenThrow)
|
||
CheckGrenadeThrow();
|
||
}
|
||
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
|
||
//MikeN/OVR - Weapon drop
|
||
if (m_afButtonPressed & IN_DROP)
|
||
{
|
||
if (pWeapon != NULL && pWeapon->CanDrop() && (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt() ? pWeapon->thisType != TYPE_GRENADE : true))
|
||
{
|
||
this->Weapon_Drop(pWeapon, NULL, NULL);
|
||
}
|
||
}
|
||
|
||
//MikeN/OVR - Ironsight toggle
|
||
if (pWeapon)
|
||
{
|
||
//m_bIsSighted = pWeapon->IsScopeSighted() || pWeapon->IsIronSighted();
|
||
|
||
//bool wallBump = cvar->FindVar("oc_weapons_allow_wall_bump")->GetInt() ? cvar->FindVar("oc_state_near_wall_standing")->GetInt() == 0 : true;
|
||
//bool wallBump2 = cvar->FindVar("oc_weapons_allow_wall_bump")->GetInt() ? pWeapon->IsNearWall() : true;
|
||
//bool wallBump3 = cvar->FindVar("oc_weapons_allow_wall_bump")->GetInt() ? pWeapon->IsNearWall() : false;
|
||
|
||
if (pWeapon->IsScopeSighted() &&
|
||
(/*wallBump3 ||*/
|
||
pWeapon->IsNearWall() ||
|
||
IsRunning() ||
|
||
pWeapon->IsInReload() ||
|
||
IsInAVehicle() ||
|
||
pWeapon->m_flNextSilencer > gpGlobals->curtime))
|
||
{
|
||
pWeapon->OffScopeSight();
|
||
}
|
||
|
||
if (cvar->FindVar("oc_ironsight_type")->GetInt() == 0)
|
||
{
|
||
if (m_afButtonPressed & IN_ATTACK3)
|
||
{
|
||
if (!pWeapon->IsIronSighted() &&
|
||
!pWeapon->wasInIronSighted &&
|
||
!pWeapon->IsScopeSighted() &&
|
||
pWeapon->GetWpnData().AllowIronSight)
|
||
{
|
||
if (!IsInAVehicle() &&
|
||
!pWeapon->m_bInReload &&
|
||
!pWeapon->m_bReloadComplete &&
|
||
!pWeapon->IsNearWall() &&
|
||
//!wallBump2 &&
|
||
!IsRunning() &&
|
||
!pWeapon->IsInReload())
|
||
pWeapon->OnIronSight();
|
||
}
|
||
else
|
||
{
|
||
pWeapon->OffIronSight();
|
||
pWeapon->wasInIronSighted = false;
|
||
}
|
||
}
|
||
|
||
bool shotgunState
|
||
(
|
||
pWeapon->m_iShotgunReloadState && pWeapon->m_iShotgunReloadState != 4 ?
|
||
true :
|
||
false
|
||
);
|
||
|
||
if (pWeapon->IsIronSighted() &&
|
||
(//wallBump3 ||
|
||
pWeapon->IsNearWall() ||
|
||
IsRunning() ||
|
||
IsInAVehicle() ||
|
||
pWeapon->IsInReload() ||
|
||
pWeapon->m_flNextSilencer > gpGlobals->curtime ||
|
||
//pWeapon->m_flNextInspectAnimation > gpGlobals->curtime ||
|
||
shotgunState))//<2F><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
{
|
||
if (!IsInAVehicle())//<2F><><EFBFBD><EFBFBD> <20><> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
pWeapon->wasInIronSighted = true;
|
||
|
||
pWeapon->OffIronSight();
|
||
|
||
}
|
||
else if (!pWeapon->IsIronSighted() &&
|
||
pWeapon->wasInIronSighted &&
|
||
!pWeapon->IsNearWall() &&
|
||
//!wallBump2 &&
|
||
!IsRunning() &&
|
||
!IsInAVehicle() &&
|
||
!pWeapon->IsInReload() &&
|
||
pWeapon->m_flNextSilencer <= gpGlobals->curtime &&
|
||
//pWeapon->m_flNextInspectAnimation <= gpGlobals->curtime &&
|
||
!shotgunState)
|
||
{
|
||
pWeapon->wasInIronSighted = false;
|
||
|
||
if (pWeapon->GetWpnData().AllowIronSight && !pWeapon->IsScopeSighted() && pWeapon->GetWpnData().AllowIronSight)
|
||
pWeapon->OnIronSight();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((m_nButtons & IN_ATTACK3) &&
|
||
!IsInAVehicle() &&
|
||
!pWeapon->m_bInReload &&
|
||
!pWeapon->m_bReloadComplete &&
|
||
!pWeapon->IsNearWall() &&
|
||
//!wallBump2 &&
|
||
!IsRunning() &&
|
||
!pWeapon->IsInReload())
|
||
{
|
||
if (!pWeapon->IsIronSighted() && !pWeapon->IsScopeSighted() && pWeapon->GetWpnData().AllowIronSight)
|
||
pWeapon->OnIronSight();
|
||
}
|
||
else
|
||
{
|
||
if (pWeapon->IsIronSighted())
|
||
pWeapon->OffIronSight();
|
||
}
|
||
}
|
||
}
|
||
//else
|
||
//m_bIsSighted = false;
|
||
}
|
||
|
||
//if (engine->IsPaused() || g_fGameOver || !IsAlive())
|
||
//m_bIsSighted = false;
|
||
|
||
//DevMsg("Server: m_bIsSighted: %i \n", m_bIsSighted);
|
||
|
||
if (this && GetActiveWeapon() && GetActiveWeapon()->GetWpnData().AllowFreeAim == 1)
|
||
{
|
||
if (this->m_hUseEntity)
|
||
{
|
||
cvar->FindVar("oc_using_entity")->SetValue(1);
|
||
}
|
||
else
|
||
{
|
||
if (cvar->FindVar("oc_using_entity")->GetInt() == 1)
|
||
cvar->FindVar("oc_using_entity")->SetValue(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool CBasePlayer::IsSighted()
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if (pWeapon)
|
||
return pWeapon->IsIronSighted() || pWeapon->IsScopeSighted();
|
||
|
||
return false;
|
||
}
|
||
|
||
void CBasePlayer::OffSights()
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if (pWeapon)
|
||
{
|
||
if (pWeapon->IsIronSighted())
|
||
{
|
||
pWeapon->OffIronSight();
|
||
}
|
||
if (pWeapon->IsScopeSighted())
|
||
{
|
||
pWeapon->OffScopeSight();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::DropGarbage(void)
|
||
{
|
||
string_t classname = garbage.Element(garbage.Count() - 1);
|
||
garbage.Remove(garbage.Count() - 1);
|
||
garbageIndex.Remove(garbageIndex.Count() - 1);
|
||
|
||
Vector attachOrigin;
|
||
QAngle attachAngles;
|
||
|
||
Vector vForward, vRight, vUp, vThrowPos;
|
||
|
||
EyeVectors(&vForward, &vRight, &vUp);
|
||
|
||
vThrowPos = EyePosition();
|
||
|
||
vThrowPos += vForward * oc_player_garbage_pos_x.GetFloat(); //2.f;
|
||
vThrowPos += vRight * oc_player_garbage_pos_y.GetFloat(); //-1.7f;// *1.0f;
|
||
vThrowPos += vUp * oc_player_garbage_pos_z.GetFloat(); //-4.f;
|
||
|
||
QAngle Ang;
|
||
|
||
VectorAngles(vThrowPos, Ang);
|
||
|
||
CBaseEntity *pVial = NULL;
|
||
pVial = CBaseEntity::Create("item_empty_perk", vThrowPos, Ang, this);
|
||
|
||
if (FStrEq(STRING(classname), "item_battery"))
|
||
{
|
||
//pVial->PrecacheModel("models/battery_empty.mdl");
|
||
pVial->SetModel("models/battery_empty.mdl");
|
||
}
|
||
else if (FStrEq(STRING(classname), "item_healthkit"))
|
||
{
|
||
//pVial->PrecacheModel("models/healthkit_empty.mdl");
|
||
pVial->SetModel("models/healthkit_empty.mdl");
|
||
}
|
||
else if (FStrEq(STRING(classname), "item_healthvial"))
|
||
{
|
||
//pVial->PrecacheModel("models/healthvial_empty.mdl");
|
||
pVial->SetModel("models/healthvial_empty.mdl");
|
||
}
|
||
|
||
pVial->SetSolid(SOLID_VPHYSICS);
|
||
pVial->SetCollisionGroup(COLLISION_GROUP_DEBRIS);
|
||
pVial->SetMoveType(MOVETYPE_VPHYSICS);
|
||
pVial->AddSpawnFlags(SF_PHYSBOX_ASLEEP);
|
||
|
||
pVial->SetAbsOrigin(vThrowPos);
|
||
pVial->SetAbsAngles(Ang);
|
||
pVial->Spawn();
|
||
|
||
Vector vel;
|
||
|
||
AngleVectors(EyeAngles(), &vel);
|
||
//VectorNormalize(vel);
|
||
|
||
vel += vForward * oc_player_garbage_velocity_x.GetFloat();
|
||
vel += vRight * oc_player_garbage_velocity_y.GetFloat();
|
||
vel += vUp * oc_player_garbage_velocity_z.GetFloat();
|
||
|
||
IPhysicsObject *pPhysics = pVial->VPhysicsGetObject();
|
||
if (pPhysics != NULL)
|
||
{
|
||
AngularImpulse angImp(vel);
|
||
pPhysics->AddVelocity(&vel, &angImp);
|
||
}
|
||
|
||
pVial->SUB_StartFadeOut(15, false);
|
||
}
|
||
|
||
bool CBasePlayer::GetIsInSwing()
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if (pWeapon && pWeapon->GetActivity() == pWeapon->GetWpnData().animData[pWeapon->m_bFireMode].SwingAnim)
|
||
return true;
|
||
|
||
return m_flSwingEventAnimTime > gpGlobals->curtime;
|
||
}
|
||
|
||
void CBasePlayer::CheckCamAttachment(void)
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
|
||
if (pWeapon)
|
||
{
|
||
if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt() ? pWeapon->thisType == TYPE_GRENADE : false)
|
||
{
|
||
if (grenadeState > 0 && grenadeState < 3)
|
||
{
|
||
//cvar->FindVar("oc_enable_cam_attachment")->SetValue(1);
|
||
AllowCamAttachment = true;
|
||
}
|
||
else
|
||
AllowCamAttachment = false;
|
||
}
|
||
else
|
||
{
|
||
if (!IsRunning() && !IsInAVehicle())
|
||
{
|
||
|
||
//int weaponMode = pWeapon->m_bFireMode; !(pOwner->m_nButtons & IN_ATTACK)
|
||
AllowCamAttachment = (
|
||
!pWeapon->IsNearWall() &&
|
||
!pWeapon->IsScopeSighted() &&
|
||
!pWeapon->IsIronSighted() &&
|
||
!pWeapon->WeaponShouldBeLowered() &&
|
||
!GetIsInSwing());
|
||
|
||
if (pWeapon->IsNonAttachmentActivity(pWeapon->GetActivity()))
|
||
AllowCamAttachment = false;
|
||
|
||
}
|
||
else
|
||
{
|
||
if (IsRunning() && pWeapon->IsInReload())
|
||
AllowCamAttachment = true;
|
||
else
|
||
AllowCamAttachment = false;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
AllowCamAttachment = false;
|
||
}
|
||
|
||
|
||
void CBasePlayer::CheckGrenadeThrow(void)
|
||
{
|
||
/*if (!pCurGrenade)
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}
|
||
else*/
|
||
UpdateGrenadeInfo();
|
||
|
||
if ((m_afButtonPressed & IN_GRENADESWITCH) &&
|
||
GetGrenadesCount() && //pAllGrenades.Count() > 1 &&
|
||
grenadeState == 0)
|
||
{
|
||
//SelectGrenadeSlot(&pAllGrenades, NextGrenadeSlot());
|
||
|
||
//NextGrenadeInSlot(NextGrenadeSlot());
|
||
SwitchNextGrenade(NextGrenadeSlot());
|
||
}
|
||
|
||
if (!pCurGrenade)
|
||
return;
|
||
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
//if (!pWeapon)
|
||
//return;
|
||
if (pWeapon)
|
||
{
|
||
if (pWeapon->m_bInReload ||
|
||
pWeapon->m_bReloadComplete ||
|
||
pWeapon->m_iShotgunReloadState ||
|
||
gpGlobals->curtime < m_flNextGrenadeThrow ||
|
||
gpGlobals->curtime < pWeapon->m_flNextSwitchTime ||
|
||
gpGlobals->curtime < pWeapon->m_flNextSilencer ||
|
||
gpGlobals->curtime < pWeapon->m_flNextShotgunReload ||
|
||
//gpGlobals->curtime < pWeapon->m_flNextInspectAnimation ||
|
||
IsRunning() ||
|
||
pWeapon->IsScopeSighted() ||
|
||
pWeapon->IsIronSighted())
|
||
return;
|
||
}
|
||
|
||
if (IsInAVehicle())
|
||
{
|
||
if (grenadeState > 0)
|
||
{
|
||
throwingState = 0;
|
||
|
||
grenadeState = 0;
|
||
|
||
pCurGrenade->Holster(pCurWeapon);
|
||
Weapon_Switch(pCurWeapon);
|
||
|
||
pCurWeapon->EnableLaserInterrupt = true;
|
||
|
||
m_flNextGrenadeThrow = 0.f;
|
||
|
||
if (!GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType) && GetGrenadesCount())// pAllGrenades.Count() > 0)
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
|
||
//SelectGrenadeSlot(&pAllGrenades, NextGrenadeSlot());
|
||
|
||
NextGrenadeInSlot(NextGrenadeSlot());
|
||
}
|
||
}
|
||
}
|
||
|
||
/*if (pCurGrenade != NULL)// && pCurGrenade->m_iPrimaryAmmoType)
|
||
{
|
||
if (cvar->FindVar("oc_gren1ammo")->GetInt() != GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType))
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType));
|
||
if (pCurGrenade->GetWpnData().szAnimationPrefix)
|
||
{
|
||
auto grenName = pCurGrenade->GetWpnData().szAnimationPrefix;
|
||
if (Q_strcmp(cvar->FindVar("oc_grenadetype")->GetString(), grenName) != 0)
|
||
cvar->FindVar("oc_grenadetype")->SetValue(grenName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (cvar->FindVar("oc_gren1ammo")->GetInt() != 0)
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}*/
|
||
|
||
if ((m_afButtonPressed & IN_THROWGRENADE) &&
|
||
pCurGrenade != NULL &&
|
||
GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType))
|
||
{
|
||
if (GetWaterLevel() == 3 && (pCurGrenade->m_bFiresUnderwater == false || pCurGrenade->m_bAltFiresUnderwater == false))
|
||
return;
|
||
|
||
if (grenadeState == 0)
|
||
{
|
||
throwingState = 0;
|
||
|
||
if (GetActiveWeapon())
|
||
{
|
||
pCurWeapon = GetActiveWeapon();
|
||
|
||
pCurWeapon->m_flNextInspectAnimation = gpGlobals->curtime;
|
||
|
||
CHL2_Player *pChildPlayer = (CHL2_Player*)this;
|
||
|
||
if (pChildPlayer)
|
||
{
|
||
//pChildPlayer->ChangeBodyGroupState(true, true);
|
||
pChildPlayer->SetHandsVisible(false);
|
||
}
|
||
|
||
if (pCurGrenade->entindex() != GetActiveWeapon()->entindex())
|
||
{
|
||
if (GetActiveWeapon()->GetWpnData().enableLaser)
|
||
{
|
||
GetActiveWeapon()->EnableLaserInterrupt = true;
|
||
GetActiveWeapon()->StopLaserEffects(this);
|
||
}
|
||
|
||
GetActiveWeapon()->Holster();
|
||
}
|
||
|
||
if (GetActiveWeapon()->GetActivity() == GetActiveWeapon()->GetHolsterActivity())
|
||
sequenceDuration = gpGlobals->curtime + GetActiveWeapon()->SequenceDuration();
|
||
else
|
||
sequenceDuration = gpGlobals->curtime + 0.1f;
|
||
|
||
if (pCurWeapon->GetWpnData().animData[0].HolsterAnimation == ACT_RESET)
|
||
sequenceDuration = gpGlobals->curtime;
|
||
}
|
||
else
|
||
{
|
||
pCurWeapon = pCurGrenade;
|
||
|
||
CHL2_Player *pChildPlayer = (CHL2_Player*)this;
|
||
|
||
if (pChildPlayer)
|
||
{
|
||
//pChildPlayer->ChangeBodyGroupState(true, true);
|
||
pChildPlayer->SetHandsVisible(false);
|
||
}
|
||
}
|
||
|
||
grenadeState = 1;
|
||
|
||
throwingStateGate = false;
|
||
|
||
throwingState++;
|
||
}
|
||
else
|
||
{
|
||
//throwingStateGate = true;
|
||
throwingState++;
|
||
}
|
||
}
|
||
|
||
/*if (m_afButtonReleased & IN_THROWGRENADE)
|
||
{
|
||
throwingStateGate = true;
|
||
}*/
|
||
|
||
if (grenadeState == 1 && gpGlobals->curtime > sequenceDuration)
|
||
{
|
||
grenadeState = 2;
|
||
|
||
pCurGrenade->DeployGrenade();//Deploy();
|
||
|
||
sequenceDuration = gpGlobals->curtime + pCurGrenade->SequenceDuration()*0.55f;
|
||
}
|
||
if (grenadeState == 2 && gpGlobals->curtime > sequenceDuration)
|
||
{
|
||
grenadeState = 3;
|
||
|
||
bool down = throwingState < 2 ? false : true;
|
||
|
||
pCurGrenade->PullUpGrenade(down);
|
||
|
||
sequenceDuration = gpGlobals->curtime + pCurGrenade->SequenceDuration()*1.5f;
|
||
|
||
if (GetActiveWeapon()->GetWpnData().enableLaser)
|
||
{
|
||
GetActiveWeapon()->EnableLaserInterrupt = true;
|
||
GetActiveWeapon()->StopLaserEffects(this);
|
||
}
|
||
}
|
||
if ((grenadeState == 3 && gpGlobals->curtime > sequenceDuration /*&& throwingStateGate*/) && (!(m_nButtons & IN_THROWGRENADE)))
|
||
{
|
||
grenadeState = 4;
|
||
|
||
bool down = throwingState < 2 ? false : true;
|
||
|
||
pCurGrenade->ReleaseGrenade(down);
|
||
|
||
sequenceDuration = gpGlobals->curtime + pCurGrenade->SequenceDuration();
|
||
|
||
m_flNextGrenadeThrow = gpGlobals->curtime + pCurGrenade->SequenceDuration();
|
||
}
|
||
if (grenadeState == 4 && gpGlobals->curtime > m_flNextGrenadeThrow && gpGlobals->curtime > sequenceDuration)
|
||
{
|
||
throwingState = 0;
|
||
|
||
grenadeState = 0;
|
||
|
||
pCurGrenade->Holster(pCurWeapon);
|
||
|
||
if (pCurGrenade->entindex() != pCurWeapon->entindex())
|
||
{
|
||
Weapon_Switch(pCurWeapon);
|
||
|
||
pCurWeapon->EnableLaserInterrupt = true;
|
||
}
|
||
else
|
||
{
|
||
CHL2_Player *pChildPlayer = (CHL2_Player*)this;
|
||
|
||
if (pChildPlayer)
|
||
{
|
||
//pChildPlayer->ChangeBodyGroupState(true, false);
|
||
pChildPlayer->SetHandsVisible(false);
|
||
}
|
||
}
|
||
|
||
m_flNextGrenadeThrow = 0.f;
|
||
|
||
if (!GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType) && GetGrenadesCount())//pAllGrenades.Count() > 0)
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
|
||
//SelectGrenadeSlot(&pAllGrenades, NextGrenadeSlot(true));
|
||
|
||
NextGrenadeInSlot(NextGrenadeSlot(true));
|
||
}
|
||
else
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
|
||
}
|
||
/*if ((m_afButtonPressed & IN_GRENADESWITCH) &&
|
||
pAllGrenades.Count() > 1 &&
|
||
//gpGlobals->curtime > m_flNextGrenadeSelect &&
|
||
grenadeState == 0)
|
||
{
|
||
SelectGrenadeSlot(&pAllGrenades, NextGrenadeSlot());
|
||
}*/
|
||
}
|
||
|
||
bool CBasePlayer::HasGrenade(CBaseCombatWeapon *pGren)
|
||
{
|
||
bool bHas = false;
|
||
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
//if (pGren == pAllGrenades[i])
|
||
if (FStrEq(pGren->GetClassname(), /*pAllGrenades[i]*/pAllGrenades.Element(i)->GetClassname()))
|
||
bHas = true;
|
||
}
|
||
|
||
return bHas;
|
||
}
|
||
|
||
int CBasePlayer::GetGrenadesCount()
|
||
{
|
||
int count = 0;
|
||
for (int i = 0; i < pAllGrenades.Count(); i++)
|
||
{
|
||
if (/*pAllGrenades[i]*/pAllGrenades.Element(i) != NULL)
|
||
count++;
|
||
}
|
||
|
||
return count;
|
||
}
|
||
|
||
void CBasePlayer::AddGrenade(CBaseCombatWeapon *pGren)
|
||
{
|
||
//int i = GetGrenadesCount();
|
||
//i = Clamp(i, 0, MAX_WEAPONS);
|
||
|
||
if (!HasGrenade(pGren))
|
||
pAllGrenades.AddToTail(pGren);
|
||
//pAllGrenades.Set(i, pGren);
|
||
}
|
||
|
||
CBaseCombatWeapon* CBasePlayer::GetGrenade(CBaseCombatWeapon *pGren)
|
||
{
|
||
CBaseCombatWeapon *pGrenade = NULL;
|
||
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
//if (pGren == pAllGrenades[i])
|
||
//pGrenade = pAllGrenades[i].Get();
|
||
|
||
CBaseCombatWeapon *pNewGrenade = pAllGrenades.Element(i);
|
||
if (pGren == pNewGrenade)
|
||
pGrenade = pNewGrenade;
|
||
}
|
||
|
||
return pGrenade;
|
||
}
|
||
|
||
bool CBasePlayer::GetAndRemoveGrenade(CBaseCombatWeapon *pGren)
|
||
{
|
||
if (GetGrenadesCount() < 1)
|
||
return false;
|
||
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
//if (pGren == pAllGrenades[i])
|
||
if (pGren == pAllGrenades.Element(i))
|
||
{
|
||
//UTIL_Remove(pGren);
|
||
//pAllGrenades.Set(i, NULL);
|
||
UTIL_Remove(pGren);
|
||
pAllGrenades.Remove(i);
|
||
//pAllGrenades.FastRemove(i);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
int CBasePlayer::NextGrenadeSlot(bool removeFromSlot)
|
||
{
|
||
if (!GetGrenadesCount())//(pAllGrenades.Count() < 1)
|
||
return 0;
|
||
|
||
if (removeFromSlot)
|
||
{
|
||
|
||
//pAllGrenades.FindAndRemove(pCurGrenade);
|
||
|
||
GetAndRemoveGrenade(pCurGrenade);
|
||
|
||
CBaseCombatWeapon *pGrenade = (CBaseCombatWeapon*)pCurGrenade;
|
||
|
||
OnBaseCombatWeaponDestroyed(pGrenade);
|
||
UTIL_Remove(pCurGrenade);
|
||
pCurGrenade = NULL;
|
||
}
|
||
|
||
int count = GetGrenadesCount();// pAllGrenades.Count();
|
||
if (grenType < count - 1)
|
||
grenType++;
|
||
else
|
||
grenType = 0;
|
||
|
||
return grenType;
|
||
}
|
||
|
||
void CBasePlayer::SelectGrenadeSlot(CUtlVector<CBaseCombatWeapon*> *pGrenadesArray, int slot)
|
||
{
|
||
int newSlot = slot;
|
||
|
||
if (GetGrenadesCount())//(pAllGrenades.Count())
|
||
pCurGrenade = /*pAllGrenades[newSlot].Get();*/pAllGrenades.Element(newSlot);
|
||
|
||
if (pCurGrenade && pCurGrenade->m_iPrimaryAmmoType)
|
||
{
|
||
if (!GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType))
|
||
{
|
||
newSlot = NextGrenadeSlot();
|
||
|
||
pCurGrenade = /*pAllGrenades[newSlot].Get();*/pAllGrenades.Element(newSlot);
|
||
}
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::SwitchNextGrenade(int iSlot)
|
||
{
|
||
if (GetGrenadesCount() <= 1)
|
||
return;
|
||
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
if (/*pAllGrenades[i]*/pAllGrenades.Element(i) != NULL)
|
||
{
|
||
if (i == iSlot)
|
||
{
|
||
pCurGrenade = pAllGrenades.Element(i);//pAllGrenades[i].Get();
|
||
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::NextGrenadeInSlot(int iSlot)
|
||
{
|
||
if (!GetGrenadesCount())
|
||
{
|
||
pCurGrenade = NULL;
|
||
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
|
||
return;
|
||
}
|
||
|
||
if (!pCurGrenade)// && pCurGrenade->m_iPrimaryAmmoType)
|
||
{
|
||
int idx = 0;
|
||
|
||
if (!iSlot)
|
||
{
|
||
if (/*pAllGrenades[0]*/pAllGrenades.Head() != NULL)
|
||
{
|
||
if (idx == iSlot)
|
||
{
|
||
pCurGrenade = pAllGrenades.Element(idx);//pAllGrenades[idx].Get();
|
||
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
if (/*pAllGrenades[i]*/pAllGrenades.Element(i) != NULL)
|
||
{
|
||
if (idx == iSlot)
|
||
{
|
||
pCurGrenade = pAllGrenades.Element(i);//pAllGrenades[i].Get();
|
||
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
idx++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (pCurGrenade && pCurGrenade->m_iPrimaryAmmoType)
|
||
{
|
||
if (!GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType))
|
||
{
|
||
iSlot = NextGrenadeSlot();
|
||
|
||
int idx = 0;
|
||
|
||
if (!iSlot)
|
||
{
|
||
if (/*pAllGrenades[0]*/pAllGrenades.Head() != NULL)
|
||
{
|
||
if (idx == iSlot)
|
||
{
|
||
pCurGrenade = pAllGrenades.Element(idx);//pAllGrenades[idx].Get();
|
||
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < GetGrenadesCount(); i++)
|
||
{
|
||
if (/*pAllGrenades[i]*/pAllGrenades.Element(i) != NULL)
|
||
{
|
||
if (idx == iSlot)
|
||
{
|
||
pCurGrenade = pAllGrenades.Element(i);//pAllGrenades[i].Get();
|
||
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
idx++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}
|
||
|
||
|
||
|
||
/*if (GetGrenadesCount())//(pAllGrenades.Count())
|
||
pCurGrenade = pAllGrenades[iSlot].Get();
|
||
|
||
if (pCurGrenade && pCurGrenade->m_iPrimaryAmmoType)
|
||
{
|
||
if (!GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType))
|
||
{
|
||
iSlot = NextGrenadeSlot();
|
||
|
||
pCurGrenade = pAllGrenades[iSlot].Get();
|
||
}
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}*/
|
||
}
|
||
|
||
void CBasePlayer::RemoveGrenadeFromSlot(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
if (HasGrenade(pWeapon))//(pAllGrenades.HasElement(pWeapon))
|
||
{
|
||
if (pCurGrenade == pWeapon)
|
||
{
|
||
pCurGrenade = NULL;
|
||
}
|
||
//pAllGrenades.FindAndRemove(pWeapon);
|
||
GetAndRemoveGrenade(pWeapon);
|
||
UpdateGrenadeInfo();
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::AddGrenadeToSlot(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
//Weapon_EquipAmmoOnly!!!!!!
|
||
if (pWeapon->thisType == TYPE_GRENADE && !HasGrenade(pWeapon))
|
||
//!pAllGrenades.HasElement(pWeapon))
|
||
{
|
||
//pAllGrenades.AddToTail(pWeapon);
|
||
|
||
AddGrenade(pWeapon);
|
||
|
||
//SelectGrenadeSlot(&pAllGrenades);
|
||
|
||
NextGrenadeInSlot();
|
||
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
else
|
||
{
|
||
if (pCurGrenade)
|
||
{
|
||
RefreshGrenadeNameInSlot(pCurGrenade);
|
||
|
||
RefreshGrenadeAmmoInSlot(pCurGrenade);
|
||
}
|
||
else
|
||
{
|
||
cvar->FindVar("oc_grenadetype")->SetValue("");
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::UpdateGrenadeInfo(void)
|
||
{
|
||
const char *grenName = "Empty";
|
||
|
||
if (pCurGrenade && GetGrenadesCount())
|
||
{
|
||
grenName = pCurGrenade->GetWpnData().szAnimationPrefix;
|
||
|
||
cvar->FindVar("oc_grenadetype")->SetValue(grenName);
|
||
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(GetAmmoCount(pCurGrenade->m_iPrimaryAmmoType));
|
||
|
||
//DevMsg("oc_gren1ammo: %i\n", cvar->FindVar("oc_gren1ammo")->GetInt());
|
||
}
|
||
else
|
||
{
|
||
pCurGrenade = NULL;
|
||
|
||
cvar->FindVar("oc_grenadetype")->SetValue(grenName);
|
||
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(0);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::RefreshGrenadeNameInSlot(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
auto grenName = pWeapon->GetWpnData().szAnimationPrefix;
|
||
|
||
cvar->FindVar("oc_grenadetype")->SetValue(grenName);
|
||
}
|
||
|
||
void CBasePlayer::RefreshGrenadeAmmoInSlot(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
cvar->FindVar("oc_gren1ammo")->SetValue(GetAmmoCount(pWeapon->m_iPrimaryAmmoType));
|
||
}
|
||
|
||
// handles touching physics objects
|
||
void CBasePlayer::Touch(CBaseEntity *pOther)
|
||
{
|
||
if (pOther == GetGroundEntity())
|
||
return;
|
||
|
||
if (pOther->GetMoveType() != MOVETYPE_VPHYSICS || pOther->GetSolid() != SOLID_VPHYSICS || (pOther->GetSolidFlags() & FSOLID_TRIGGER))
|
||
return;
|
||
|
||
IPhysicsObject *pPhys = pOther->VPhysicsGetObject();
|
||
if (!pPhys || !pPhys->IsMoveable())
|
||
return;
|
||
|
||
SetTouchedPhysics(true);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::PostThinkVPhysics(void)
|
||
{
|
||
// Check to see if things are initialized!
|
||
if (!m_pPhysicsController)
|
||
return;
|
||
|
||
Vector newPosition = GetAbsOrigin();
|
||
float frametime = gpGlobals->frametime;
|
||
if (frametime <= 0 || frametime > 0.1f)
|
||
frametime = 0.1f;
|
||
|
||
IPhysicsObject *pPhysGround = GetGroundVPhysics();
|
||
|
||
if (!pPhysGround && m_touchedPhysObject && g_pMoveData->m_outStepHeight <= 0.f && (GetFlags() & FL_ONGROUND))
|
||
{
|
||
newPosition = m_oldOrigin + frametime * g_pMoveData->m_outWishVel;
|
||
newPosition = (GetAbsOrigin() * 0.5f) + (newPosition * 0.5f);
|
||
}
|
||
|
||
int collisionState = VPHYS_WALK;
|
||
if (GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER)
|
||
{
|
||
collisionState = VPHYS_NOCLIP;
|
||
}
|
||
else if (GetFlags() & FL_DUCKING)
|
||
{
|
||
collisionState = VPHYS_CROUCH;
|
||
}
|
||
|
||
if (collisionState != m_vphysicsCollisionState)
|
||
{
|
||
SetVCollisionState(GetAbsOrigin(), GetAbsVelocity(), collisionState);
|
||
}
|
||
|
||
if (!(TouchedPhysics() || pPhysGround))
|
||
{
|
||
float maxSpeed = m_flMaxspeed > 0.0f ? m_flMaxspeed : sv_maxspeed.GetFloat();
|
||
g_pMoveData->m_outWishVel.Init(maxSpeed, maxSpeed, maxSpeed);
|
||
}
|
||
|
||
// teleport the physics object up by stepheight (game code does this - reflect in the physics)
|
||
if (g_pMoveData->m_outStepHeight > 0.1f)
|
||
{
|
||
if (g_pMoveData->m_outStepHeight > 4.0f)
|
||
{
|
||
VPhysicsGetObject()->SetPosition(GetAbsOrigin(), vec3_angle, true);
|
||
}
|
||
else
|
||
{
|
||
// don't ever teleport into solid
|
||
Vector position, end;
|
||
VPhysicsGetObject()->GetPosition(&position, NULL);
|
||
end = position;
|
||
end.z += g_pMoveData->m_outStepHeight;
|
||
trace_t trace;
|
||
UTIL_TraceEntity(this, position, end, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (trace.DidHit())
|
||
{
|
||
g_pMoveData->m_outStepHeight = trace.endpos.z - position.z;
|
||
}
|
||
m_pPhysicsController->StepUp(g_pMoveData->m_outStepHeight);
|
||
}
|
||
m_pPhysicsController->Jump();
|
||
}
|
||
g_pMoveData->m_outStepHeight = 0.0f;
|
||
|
||
// Store these off because after running the usercmds, it'll pass them
|
||
// to UpdateVPhysicsPosition.
|
||
m_vNewVPhysicsPosition = newPosition;
|
||
m_vNewVPhysicsVelocity = g_pMoveData->m_outWishVel;
|
||
|
||
m_oldOrigin = GetAbsOrigin();
|
||
}
|
||
|
||
void CBasePlayer::UpdateVPhysicsPosition(const Vector &position, const Vector &velocity, float secondsToArrival)
|
||
{
|
||
bool onground = (GetFlags() & FL_ONGROUND) ? true : false;
|
||
IPhysicsObject *pPhysGround = GetGroundVPhysics();
|
||
|
||
// if the object is much heavier than the player, treat it as a local coordinate system
|
||
// the player controller will solve movement differently in this case.
|
||
if (!IsRideablePhysics(pPhysGround))
|
||
{
|
||
pPhysGround = NULL;
|
||
}
|
||
|
||
m_pPhysicsController->Update(position, velocity, secondsToArrival, onground, pPhysGround);
|
||
}
|
||
|
||
void CBasePlayer::UpdatePhysicsShadowToCurrentPosition()
|
||
{
|
||
UpdateVPhysicsPosition(GetAbsOrigin(), vec3_origin, gpGlobals->frametime);
|
||
}
|
||
|
||
void CBasePlayer::UpdatePhysicsShadowToPosition(const Vector &vecAbsOrigin)
|
||
{
|
||
UpdateVPhysicsPosition(vecAbsOrigin, vec3_origin, gpGlobals->frametime);
|
||
}
|
||
|
||
Vector CBasePlayer::GetSmoothedVelocity(void)
|
||
{
|
||
if (IsInAVehicle())
|
||
{
|
||
return GetVehicle()->GetVehicleEnt()->GetSmoothedVelocity();
|
||
}
|
||
return m_vecSmoothedVelocity;
|
||
}
|
||
|
||
|
||
CBaseEntity *g_pLastSpawn = NULL;
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Finds a player start entity of the given classname. If any entity of
|
||
// of the given classname has the SF_PLAYER_START_MASTER flag set, that
|
||
// is the entity that will be returned. Otherwise, the first entity of
|
||
// the given classname is returned.
|
||
// Input : pszClassName - should be "info_player_start", "info_player_coop", or
|
||
// "info_player_deathmatch"
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *FindPlayerStart(const char *pszClassName)
|
||
{
|
||
#define SF_PLAYER_START_MASTER 1
|
||
|
||
CBaseEntity *pStart = gEntList.FindEntityByClassname(NULL, pszClassName);
|
||
CBaseEntity *pStartFirst = pStart;
|
||
while (pStart != NULL)
|
||
{
|
||
if (pStart->HasSpawnFlags(SF_PLAYER_START_MASTER))
|
||
{
|
||
return pStart;
|
||
}
|
||
|
||
pStart = gEntList.FindEntityByClassname(pStart, pszClassName);
|
||
}
|
||
|
||
return pStartFirst;
|
||
}
|
||
|
||
/*
|
||
============
|
||
EntSelectSpawnPoint
|
||
|
||
Returns the entity to spawn at
|
||
|
||
USES AND SETS GLOBAL g_pLastSpawn
|
||
============
|
||
*/
|
||
CBaseEntity *CBasePlayer::EntSelectSpawnPoint()
|
||
{
|
||
CBaseEntity *pSpot;
|
||
edict_t *player;
|
||
|
||
player = edict();
|
||
|
||
// choose a info_player_deathmatch point
|
||
if (g_pGameRules->IsCoOp())
|
||
{
|
||
pSpot = gEntList.FindEntityByClassname(g_pLastSpawn, "info_player_coop");
|
||
if (pSpot)
|
||
goto ReturnSpot;
|
||
pSpot = gEntList.FindEntityByClassname(g_pLastSpawn, "info_player_start");
|
||
if (pSpot)
|
||
goto ReturnSpot;
|
||
}
|
||
else if (g_pGameRules->IsDeathmatch())
|
||
{
|
||
pSpot = g_pLastSpawn;
|
||
// Randomize the start spot
|
||
for (int i = random->RandomInt(1, 5); i > 0; i--)
|
||
pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_deathmatch");
|
||
if (!pSpot) // skip over the null point
|
||
pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_deathmatch");
|
||
|
||
CBaseEntity *pFirstSpot = pSpot;
|
||
|
||
do
|
||
{
|
||
if (pSpot)
|
||
{
|
||
// check if pSpot is valid
|
||
if (g_pGameRules->IsSpawnPointValid(pSpot, this))
|
||
{
|
||
if (pSpot->GetLocalOrigin() == vec3_origin)
|
||
{
|
||
pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_deathmatch");
|
||
continue;
|
||
}
|
||
|
||
// if so, go to pSpot
|
||
goto ReturnSpot;
|
||
}
|
||
}
|
||
// increment pSpot
|
||
pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_deathmatch");
|
||
} while (pSpot != pFirstSpot); // loop if we're not back to the start
|
||
|
||
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
|
||
if (pSpot)
|
||
{
|
||
CBaseEntity *ent = NULL;
|
||
for (CEntitySphereQuery sphere(pSpot->GetAbsOrigin(), 128); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity())
|
||
{
|
||
// if ent is a client, kill em (unless they are ourselves)
|
||
if (ent->IsPlayer() && !(ent->edict() == player))
|
||
ent->TakeDamage(CTakeDamageInfo(GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), 300, DMG_GENERIC));
|
||
}
|
||
goto ReturnSpot;
|
||
}
|
||
}
|
||
|
||
// If startspot is set, (re)spawn there.
|
||
if (!gpGlobals->startspot || !strlen(STRING(gpGlobals->startspot)))
|
||
{
|
||
pSpot = FindPlayerStart("info_player_start");
|
||
if (pSpot)
|
||
goto ReturnSpot;
|
||
}
|
||
else
|
||
{
|
||
pSpot = gEntList.FindEntityByName(NULL, gpGlobals->startspot);
|
||
if (pSpot)
|
||
goto ReturnSpot;
|
||
}
|
||
|
||
ReturnSpot:
|
||
if (!pSpot)
|
||
{
|
||
Warning("PutClientInServer: no info_player_start on level\n");
|
||
return CBaseEntity::Instance(INDEXENT(0));
|
||
}
|
||
|
||
g_pLastSpawn = pSpot;
|
||
return pSpot;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Called the first time the player's created
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InitialSpawn(void)
|
||
{
|
||
m_iConnected = PlayerConnected;
|
||
gamestats->Event_PlayerConnected(this);
|
||
|
||
/*SetupBloodOverlay(false);
|
||
SetupBloodOverlayDelay(0.0f);*/
|
||
}
|
||
|
||
void CBasePlayer::ReadDataFromFile(IFileSystem* filesystem)
|
||
{
|
||
KeyValues *pkvProperties = new KeyValues("player");
|
||
char script[256];
|
||
Q_snprintf(script, sizeof(script), "scripts/entities/%s.txt", "player");
|
||
if (pkvProperties->LoadFromFile(filesystem, "scripts/entities/player.txt", "GAME"))
|
||
{
|
||
if (pkvProperties)
|
||
{
|
||
KeyValues *pMain = pkvProperties->FindKey("Particles");
|
||
if (pMain)
|
||
{
|
||
/*Q_snprintf(pExplode, sizeof(pExplode), "%s", AllocPooledString(pMain->GetString("ParticleExplosion", "")));
|
||
Q_snprintf(pTrail, sizeof(pTrail), "%s", AllocPooledString(pMain->GetString("ParticleTrail", "")));
|
||
PrecacheParticleSystem(pExplode);
|
||
PrecacheParticleSystem(pTrail);*/
|
||
}
|
||
}
|
||
}
|
||
pkvProperties->deleteThis();
|
||
}
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Called everytime the player respawns
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::Spawn(void)
|
||
{
|
||
//ReadDataFromFile(filesystem);
|
||
|
||
// Needs to be done before weapons are given
|
||
if (Hints())
|
||
{
|
||
Hints()->ResetHints();
|
||
}
|
||
|
||
SetClassname("player");
|
||
|
||
// Shared spawning code..
|
||
SharedSpawn();
|
||
|
||
SetSimulatedEveryTick(true);
|
||
SetAnimatedEveryTick(true);
|
||
|
||
m_ArmorValue = SpawnArmorValue();
|
||
SetBlocksLOS(false);
|
||
m_iMaxHealth = m_iHealth;
|
||
|
||
// Clear all flags except for FL_FULLEDICT
|
||
if (GetFlags() & FL_FAKECLIENT)
|
||
{
|
||
ClearFlags();
|
||
AddFlag(FL_CLIENT | FL_FAKECLIENT);
|
||
}
|
||
else
|
||
{
|
||
ClearFlags();
|
||
AddFlag(FL_CLIENT);
|
||
}
|
||
|
||
AddFlag(FL_AIMTARGET);
|
||
|
||
m_AirFinished = gpGlobals->curtime + AIRTIME;
|
||
m_nDrownDmgRate = DROWNING_DAMAGE_INITIAL;
|
||
|
||
// only preserve the shadow flag
|
||
int effects = GetEffects() & EF_NOSHADOW;
|
||
SetEffects(effects);
|
||
|
||
IncrementInterpolationFrame();
|
||
|
||
// Initialize the fog and postprocess controllers.
|
||
InitFogController();
|
||
|
||
m_DmgTake = 0;
|
||
m_DmgSave = 0;
|
||
m_bitsHUDDamage = -1;
|
||
m_bitsDamageType = 0;
|
||
m_afPhysicsFlags = 0;
|
||
|
||
m_idrownrestored = m_idrowndmg;
|
||
|
||
SetFOV(this, 0);
|
||
|
||
m_flNextDecalTime = 0;// let this player decal as soon as he spawns.
|
||
|
||
m_flgeigerDelay = gpGlobals->curtime + 2.0; // wait a few seconds until user-defined message registrations
|
||
// are recieved by all clients
|
||
|
||
m_flFieldOfView = 0.766;// some NPCs use this to determine whether or not the player is looking at them.
|
||
|
||
m_vecAdditionalPVSOrigin = vec3_origin;
|
||
m_vecCameraPVSOrigin = vec3_origin;
|
||
|
||
if (!m_fGameHUDInitialized)
|
||
g_pGameRules->SetDefaultPlayerTeam(this);
|
||
|
||
g_pGameRules->GetPlayerSpawnSpot(this);
|
||
|
||
m_Local.m_bDucked = false;// This will persist over round restart if you hold duck otherwise.
|
||
m_Local.m_bDucking = false;
|
||
SetViewOffset(VEC_VIEW_SCALED(this));
|
||
Precache();
|
||
|
||
/*SetupBloodOverlay(false);
|
||
SetupBloodOverlayFrame(0);
|
||
SetupBloodOverlayDelay(0.0f);*/
|
||
|
||
m_bitsDamageType = 0;
|
||
m_bitsHUDDamage = -1;
|
||
SetPlayerUnderwater(false);
|
||
|
||
m_iTrain = TRAIN_NEW;
|
||
|
||
m_HackedGunPos = Vector(0, 32, 0);
|
||
|
||
m_iBonusChallenge = sv_bonus_challenge.GetInt();
|
||
sv_bonus_challenge.SetValue(0);
|
||
|
||
if (m_iPlayerSound == SOUNDLIST_EMPTY)
|
||
{
|
||
Msg("Couldn't alloc player sound slot!\n");
|
||
}
|
||
|
||
SetThink(NULL);
|
||
m_fInitHUD = true;
|
||
m_fWeapon = false;
|
||
m_iClientBattery = -1;
|
||
|
||
m_lastx = m_lasty = 0;
|
||
|
||
Q_strncpy(m_szLastPlaceName.GetForModify(), "", MAX_PLACE_NAME_LENGTH);
|
||
|
||
CSingleUserRecipientFilter user(this);
|
||
enginesound->SetPlayerDSP(user, 0, false);
|
||
|
||
CreateViewModel();
|
||
|
||
SetCollisionGroup(COLLISION_GROUP_PLAYER);
|
||
|
||
// if the player is locked, make sure he stays locked
|
||
if (m_iPlayerLocked)
|
||
{
|
||
m_iPlayerLocked = false;
|
||
LockPlayerInPlace();
|
||
}
|
||
|
||
if (GetTeamNumber() != TEAM_SPECTATOR)
|
||
{
|
||
StopObserverMode();
|
||
}
|
||
else
|
||
{
|
||
StartObserverMode(m_iObserverLastMode);
|
||
}
|
||
|
||
StopReplayMode();
|
||
|
||
// Clear any screenfade
|
||
color32 nothing = { 0, 0, 0, 255 };
|
||
UTIL_ScreenFade(this, nothing, 0, 0, FFADE_IN | FFADE_PURGE);
|
||
|
||
g_pGameRules->PlayerSpawn(this);
|
||
|
||
m_flLaggedMovementValue = 1.0f;
|
||
m_vecSmoothedVelocity = vec3_origin;
|
||
InitVCollision(GetAbsOrigin(), GetAbsVelocity());
|
||
|
||
#if !defined( TF_DLL )
|
||
IGameEvent *event = gameeventmanager->CreateEvent("player_spawn");
|
||
|
||
if (event)
|
||
{
|
||
event->SetInt("userid", GetUserID());
|
||
gameeventmanager->FireEvent(event);
|
||
}
|
||
#endif
|
||
|
||
RumbleEffect(RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE);
|
||
|
||
// Calculate this immediately
|
||
m_nVehicleViewSavedFrame = 0;
|
||
|
||
// track where we are in the nav mesh
|
||
UpdateLastKnownArea();
|
||
|
||
BaseClass::Spawn();
|
||
|
||
if (cvar->FindVar("oc_playerview_attach_deathcam")->GetInt() != 0)
|
||
m_bSpawnNoRagdoll = true;
|
||
|
||
// track where we are in the nav mesh
|
||
UpdateLastKnownArea();
|
||
|
||
m_weaponFiredTimer.Invalidate();
|
||
|
||
//===================================== Overcharged on player spawn functions
|
||
if (cvar->FindVar("oc_state_InSecondFire")->GetInt() == 1)
|
||
{
|
||
CSingleUserRecipientFilter filter(this);
|
||
UserMessageBegin(filter, "ShowScope");
|
||
WRITE_BYTE(0);
|
||
MessageEnd();
|
||
|
||
DevMsg("Hud scope cleanup");
|
||
cvar->FindVar("oc_state_InSecondFire")->SetValue(0);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::SetupBloodOverlay(bool bVal)
|
||
{
|
||
m_bShouldDrawBloodOverlay = bVal;
|
||
|
||
if (bVal)
|
||
m_bCleanUpWeapons = !bVal;
|
||
}
|
||
|
||
void CBasePlayer::SetupBloodOverlayFrame(int iFrame)
|
||
{
|
||
m_iBloodOverlayDetailFrame = iFrame;
|
||
}
|
||
|
||
void CBasePlayer::SetupBloodOverlayDelay(float flDelay)
|
||
{
|
||
m_flNextBloodDryDisappear = gpGlobals->curtime + flDelay;
|
||
}
|
||
|
||
void CBasePlayer::SetupWeaponBloodOverlay(bool bVal, bool bAllWeapons)
|
||
{
|
||
if (bAllWeapons)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < WeaponCount(); i++)
|
||
{
|
||
if (GetWeapon(i))
|
||
{
|
||
GetWeapon(i)->m_bShouldDrawWeaponBloodOverlay = bVal;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (GetActiveWeapon())
|
||
GetActiveWeapon()->m_bShouldDrawWeaponBloodOverlay = bVal;
|
||
}
|
||
|
||
m_bCleanUpWeapons = bVal;
|
||
}
|
||
|
||
CBaseCombatWeapon *CBasePlayer::GetWeaponByClassName(const char *sClassName)
|
||
{
|
||
for (int i = 0; i < WeaponCount(); i++)
|
||
{
|
||
if (GetWeapon(i) != NULL)
|
||
{
|
||
if (GetWeapon(i)->ClassMatches(sClassName))
|
||
{
|
||
return GetWeapon(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void CBasePlayer::SetupWeaponBloodOverlayFrame(int iFrame)
|
||
{
|
||
if (GetActiveWeapon())
|
||
GetActiveWeapon()->m_iWeaponBloodOverlayDetailFrame = iFrame;
|
||
}
|
||
|
||
void CBasePlayer::Activate(void)
|
||
{
|
||
BaseClass::Activate();
|
||
|
||
AimTarget_ForceRepopulateList();
|
||
|
||
RumbleEffect(RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE);
|
||
|
||
// Reset the analog bias. If the player is in a vehicle when the game
|
||
// reloads, it will autosense and apply the correct bias.
|
||
m_iVehicleAnalogBias = VEHICLE_ANALOG_BIAS_NONE;
|
||
}
|
||
|
||
void CBasePlayer::Precache(void)
|
||
{
|
||
BaseClass::Precache();
|
||
|
||
PrecacheModel("models/battery_empty.mdl");
|
||
PrecacheModel("models/healthkit_empty.mdl");
|
||
PrecacheModel("models/healthvial_empty.mdl");
|
||
PrecacheModel("models/blackout.mdl");
|
||
PrecacheModel("models/ballsphere.mdl");
|
||
|
||
PrecacheMaterial("effects/shaders/blurx");
|
||
PrecacheMaterial("effects/shaders/blury");
|
||
PrecacheMaterial("effects/shaders/sunshaft_base");
|
||
PrecacheMaterial("effects/shaders/sunshaft_final");
|
||
PrecacheMaterial("effects/shaders/dust");
|
||
PrecacheMaterial("effects/shaders/cross_processing_new");
|
||
PrecacheMaterial("effects/shaders/cross_processing");
|
||
PrecacheMaterial("effects/shaders/postproc_bokeh");
|
||
PrecacheMaterial("effects/shaders/colorgrading_simple");
|
||
PrecacheMaterial("effects/shaders/scope_sniper");
|
||
PrecacheMaterial("effects/shaders/scope_crossbow");
|
||
PrecacheMaterial("effects/shaders/scope_oicw");
|
||
PrecacheMaterial("effects/shaders/scope_sg552");
|
||
PrecacheMaterial("effects/shaders/postproc_cinematic_overlay");
|
||
PrecacheMaterial("effects/shaders/postproc_cinematic_overlay_saturation");
|
||
PrecacheMaterial("effects/shaders/postprocess_filmgrain");
|
||
PrecacheMaterial("effects/shaders/postproc_dragonborn");
|
||
PrecacheMaterial("effects/shaders/postproc_chromatic_abberations");
|
||
PrecacheMaterial("effects/shaders/postproc_desaturation");
|
||
PrecacheMaterial("effects/shaders/anamorphic_bloom");
|
||
PrecacheMaterial("effects/shaders/glass_effect_01");
|
||
PrecacheMaterial("effects/shaders/postproc_fxaa");
|
||
PrecacheMaterial("effects/shaders/postproc_gears_bloom");
|
||
PrecacheMaterial("shadereditor/_rt_framebuffer_prev");
|
||
PrecacheMaterial("shadereditor/_rt_ppe");
|
||
PrecacheMaterial("effects/shaders/sunrays_texture");
|
||
PrecacheMaterial("effects/shaders/postproc_bokeh_for_ssao2");
|
||
PrecacheMaterial("effects/shaders/Effects from CITY 17/anamorphic_bloom");
|
||
PrecacheMaterial("effects/shaders/Effects from CITY 17/anamorphic_bloom_final");
|
||
|
||
PrecacheMaterial("effects/shaders/sunrays/blurx");
|
||
PrecacheMaterial("effects/shaders/sunrays/blury");
|
||
PrecacheMaterial("effects/shaders/sunrays/sunshaft_base");
|
||
PrecacheMaterial("effects/shaders/sunrays/sunshaft_final");
|
||
PrecacheMaterial("effects/shaders/sunrays/sunshaft_debug");
|
||
PrecacheMaterial("effects/shaders/downsample_4");
|
||
|
||
PrecacheMaterial("effects/shaders/postproc_natural");
|
||
PrecacheMaterial("effects/shaders/postproc_bloom");
|
||
PrecacheMaterial("effects/shaders/postproc_colorgrading");
|
||
PrecacheMaterial("effects/shaders/postproc_flare_naive");
|
||
PrecacheMaterial("effects/shaders/postproc_flare_naive_eyes");
|
||
PrecacheMaterial("effects/shaders/postproc_flare_naive_eyes2");
|
||
PrecacheMaterial("effects/shaders/postproc_hurt");
|
||
PrecacheMaterial("effects/shaders/postproc_pain");
|
||
PrecacheMaterial("effects/shaders/postproc_wet");
|
||
PrecacheMaterial("effects/shaders/postproc_energy");
|
||
PrecacheMaterial("effects/shaders/postproc_energy_grain");
|
||
PrecacheMaterial("effects/shaders/postproc_battery");
|
||
PrecacheMaterial("effects/shaders/postproc_health");
|
||
PrecacheMaterial("effects/shaders/postproc_health_regenerate");
|
||
PrecacheMaterial("effects/shaders/postproc_toon");
|
||
PrecacheMaterial("effects/shaders/postproc_bullettime");
|
||
PrecacheMaterial("effects/shaders/postproc_bullettime2");
|
||
PrecacheMaterial("effects/shaders/postproc_sunrays");
|
||
PrecacheMaterial("effects/shaders/postproc_sunrays2");
|
||
PrecacheMaterial("effects/shaders/postproc_bokeh_for_ssao2");
|
||
//SSAO
|
||
PrecacheMaterial("effects/shaders/ssao/ssao");//OverCharged
|
||
PrecacheMaterial("effects/shaders/ssao/ssaoblur");//OverCharged
|
||
PrecacheMaterial("effects/shaders/ssao/ssao_combine");//OverCharged
|
||
|
||
PrecacheMaterial("texture_samples/noise_3d");
|
||
PrecacheMaterial("texture_samples/noise_2d");
|
||
PrecacheMaterial("texture_samples/fx_clouds_0");
|
||
PrecacheMaterial("texture_samples/fx_clouds_0_normal");
|
||
PrecacheMaterial("texture_samples/fx_clouds_1");
|
||
PrecacheMaterial("texture_samples/fx_clouds_2");
|
||
PrecacheMaterial("texture_samples/fx_clouds_3");
|
||
PrecacheMaterial("texture_samples/fx_clouds_4");
|
||
|
||
PrecacheMaterial("effects/shaders/postproc_deferred_lightning");
|
||
|
||
#if !defined( TF_DLL )
|
||
// Anything derived from this class can potentially burn - true, but do we want it to!
|
||
PrecacheParticleSystem("burning_character");
|
||
#endif
|
||
|
||
// These are always needed
|
||
#ifndef TF_DLL
|
||
PrecacheParticleSystem("slime_splash_01");
|
||
PrecacheParticleSystem("slime_splash_02");
|
||
PrecacheParticleSystem("slime_splash_03");
|
||
PrecacheParticleSystem("water_splash_01");
|
||
PrecacheParticleSystem("water_splash_explosion");
|
||
#endif
|
||
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_helibomb_explosion_effect_name")->GetString())); // heli bomb // Heli_Bomb
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_main_explosion_effect1_name")->GetString())); // main expl effects 1-5 // Explosion_01
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_main_explosion_effect2_name")->GetString()));
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_main_explosion_effect3_name")->GetString()));
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_main_explosion_effect4_name")->GetString()));
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_main_explosion_effect5_name")->GetString()));
|
||
PrecacheParticleSystem((cvar->FindVar("oc_fx_particle_crossbowbolt_explosion_effect_name")->GetString())); // crossbow bolt unique explosion // XBowBolt_Explosion
|
||
|
||
PrecacheParticleSystem("impact_metal_sparks_gauss");
|
||
PrecacheParticleSystem("gauss_penetration_glow");
|
||
PrecacheParticleSystem("rain_puddle");
|
||
PrecacheParticleSystem("water_splash_explosion");
|
||
PrecacheParticleSystem("pd2_muzzle_normal_oicw");
|
||
PrecacheParticleSystem("muzzle_sparks_ar2_npc");
|
||
PrecacheParticleSystem("muzzle_sparks_ar2_360_npc");
|
||
PrecacheParticleSystem("ar2_normal_npc");
|
||
PrecacheParticleSystem("abgun_normal2");
|
||
PrecacheParticleSystem("slime_splash_01");
|
||
PrecacheParticleSystem("dissolve_egon_warp");
|
||
PrecacheParticleSystem("dissolve_egon");
|
||
PrecacheParticleSystem("weapon_muzzle_flash_pistol_FP_cheap");
|
||
PrecacheParticleSystem("he_crystal_explode");
|
||
PrecacheParticleSystem("he_crystal_beams");
|
||
PrecacheParticleSystem("explosion_turret_break_pre_flash");
|
||
PrecacheParticleSystem("gauss_muzzle_flash");
|
||
PrecacheParticleSystem("gauss_normal2");
|
||
PrecacheParticleSystem("gauss_smoke");
|
||
PrecacheParticleSystem("striderbuster_break_c");
|
||
PrecacheParticleSystem("Gauss_impact_round_sparks");
|
||
PrecacheParticleSystem("gauss_balls01");
|
||
PrecacheParticleSystem("hopwire_vortex");
|
||
PrecacheParticleSystem("weapon_molotov_flame_world");
|
||
PrecacheParticleSystem("hunter_flechette_trail");
|
||
PrecacheParticleSystem("Spore_launcher_acid_glow");
|
||
PrecacheParticleSystem("grenade_spit");
|
||
PrecacheParticleSystem("grenade_spit_player");
|
||
PrecacheParticleSystem("Shockrifle_projectile");
|
||
PrecacheParticleSystem("grenade_spit_trail");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke2");
|
||
PrecacheParticleSystem("advisor_object_charge");
|
||
PrecacheParticleSystem("blood_impact_yellow_01");
|
||
PrecacheParticleSystem("charge_npc");
|
||
PrecacheParticleSystem("CombineGuard_Outer_impact");
|
||
PrecacheParticleSystem("weapon_tracer_cguard");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke_cguard1");
|
||
PrecacheParticleSystem("Immolator_explodeMain");
|
||
PrecacheParticleSystem("immolator_sparks01");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke_immolator");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke_immolator1");
|
||
PrecacheParticleSystem("gargantua_stomp1");
|
||
PrecacheParticleSystem("flamethrower");
|
||
PrecacheParticleSystem("CombineGuard_Attack_Laser");
|
||
PrecacheParticleSystem("CombineGuard_Muzzle_Flash");
|
||
PrecacheParticleSystem("Spore_launcher_muzzle_flash_main");
|
||
PrecacheParticleSystem("shock_trooper_eye_glow");
|
||
PrecacheParticleSystem("weapon_muzzle_flash_shock_npc");
|
||
PrecacheParticleSystem("GrubSquashBlood");
|
||
PrecacheParticleSystem("volt_sphere_longfire");
|
||
PrecacheParticleSystem("volt_sphere_particles");
|
||
PrecacheParticleSystem("voltigore_baby_beam_closeattack");
|
||
PrecacheParticleSystem("voltigore_baby_paw_charge_preshot");
|
||
PrecacheParticleSystem("voltigore_baby_middle_charge_preshot");
|
||
PrecacheParticleSystem("voltigore_paw_charge_preshot");
|
||
PrecacheParticleSystem("voltigore_middle_charge_preshot");
|
||
PrecacheParticleSystem("voltigore_big_explode_pre");
|
||
PrecacheParticleSystem("Weapon_cguard_Cannon");
|
||
PrecacheParticleSystem("charge");
|
||
PrecacheParticleSystem("CombineGuard_Attack_Laser");
|
||
PrecacheParticleSystem("Weapon_Combine_cguard_Cannon");
|
||
PrecacheParticleSystem("weapon_tracer_cguard");
|
||
PrecacheParticleSystem("CombineGuard_Outer_plr");
|
||
PrecacheParticleSystem("CombineGuard_Outer");
|
||
PrecacheParticleSystem("CombineGuard_Outer_impact");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke_cguard");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke_cguard1");
|
||
PrecacheParticleSystem("DispBall_exhaust");
|
||
PrecacheParticleSystem("Xen_teleport_idle");
|
||
PrecacheParticleSystem("Xen_portal_big2");
|
||
PrecacheParticleSystem("houndeye_wave_01");
|
||
PrecacheParticleSystem("Xen_portal_big1");
|
||
PrecacheParticleSystem("xelectrical_arc_01_parent");
|
||
PrecacheParticleSystem("Disp_muzzle_in");
|
||
PrecacheParticleSystem("Disp_muzzle_root");
|
||
PrecacheParticleSystem("gluon_beam_startup");
|
||
PrecacheParticleSystem("gluon_beam_burst");
|
||
PrecacheParticleSystem("gluon_beam_end_inst");
|
||
PrecacheParticleSystem("flamethrower");
|
||
PrecacheParticleSystem("gauss_tik");
|
||
PrecacheParticleSystem("Immolator_line01");
|
||
PrecacheParticleSystem("Immolator_explodeMain");
|
||
PrecacheParticleSystem("Immolator_start");
|
||
PrecacheParticleSystem("immolator_normal");
|
||
PrecacheParticleSystem("immolator_sparks01");
|
||
PrecacheParticleSystem("Weapon_Combine_Ion_Cannon");
|
||
PrecacheParticleSystem("ion_laser_dot");
|
||
PrecacheParticleSystem("ion_laser_dot2");
|
||
PrecacheParticleSystem("ion_laser");
|
||
PrecacheParticleSystem("ion_laser_stop");
|
||
PrecacheParticleSystem("ball");
|
||
PrecacheParticleSystem("Shock_rifle_main_ball");
|
||
PrecacheParticleSystem("Shock_rifle_main_glow");
|
||
PrecacheParticleSystem("hunter_flechette_trail");
|
||
PrecacheParticleSystem("Shockrifle_projectile");
|
||
PrecacheParticleSystem("Shockrifle_sparks");
|
||
PrecacheParticleSystem("laser_pointer");
|
||
PrecacheParticleSystem("sniper_laser");
|
||
PrecacheParticleSystem("shell_eject_smoke_flash");
|
||
PrecacheParticleSystem("weapon_dust_stream");
|
||
PrecacheParticleSystem("weapon_stunstick_rays");
|
||
PrecacheParticleSystem("weapon_stunstick_el_sparks");
|
||
PrecacheParticleSystem("weapon_stunstick_rays");
|
||
PrecacheParticleSystem("gauss_muzzle_flash");
|
||
PrecacheParticleSystem("gauss_smoke");
|
||
PrecacheParticleSystem("Gauss_impact_round_sparks");
|
||
PrecacheParticleSystem("gauss_charge");
|
||
PrecacheParticleSystem("gauss_zap02");
|
||
PrecacheParticleSystem("gauss_tik");
|
||
PrecacheParticleSystem("gauss_zap");
|
||
PrecacheParticleSystem("ar2_normal_npc");
|
||
PrecacheParticleSystem("abgun_normal3");
|
||
PrecacheParticleSystem("shell_exhaust_smoke");
|
||
PrecacheParticleSystem("advisor_object_charge");
|
||
PrecacheParticleSystem("Heli_Bomb");
|
||
PrecacheParticleSystem("abgun_normal2");
|
||
PrecacheParticleSystem("gauss_normal2_vehicle");
|
||
PrecacheParticleSystem("gauss_normal");
|
||
PrecacheParticleSystem("gauss_vehicle");
|
||
PrecacheParticleSystem("gauss_sparks01");
|
||
PrecacheParticleSystem("muzzle_sparks01");
|
||
PrecacheParticleSystem("gauss_zap01");
|
||
PrecacheParticleSystem("gauss_normal2");
|
||
PrecacheParticleSystem("gauss_vehicle2");
|
||
PrecacheParticleSystem("gauss_zap_vehicle");
|
||
PrecacheParticleSystem("gauss_charge_jeep");
|
||
PrecacheParticleSystem("weapon_muzzle_smoke2");
|
||
PrecacheParticleSystem("bugbait_puff");
|
||
PrecacheParticleSystem("bolt_exhaust");
|
||
PrecacheParticleSystem("Explosion_2");
|
||
PrecacheParticleSystem("ExplosionCore");
|
||
PrecacheParticleSystem("Blood_explosion_shower");
|
||
PrecacheParticleSystem("explosion_turret_break");
|
||
PrecacheParticleSystem("Explosion_2");
|
||
PrecacheParticleSystem("ExplosionCore");
|
||
PrecacheParticleSystem("explosion_turret_break");
|
||
PrecacheParticleSystem("weapon_megaphyscannon_core");
|
||
PrecacheParticleSystem("weapon_physcannon_core");
|
||
PrecacheParticleSystem("weapon_rpg_fireSmoke");
|
||
PrecacheParticleSystem("weapon_rpg_fireJet");
|
||
PrecacheParticleSystem("blood_trail");
|
||
PrecacheParticleSystem("blood_spit_trail");
|
||
PrecacheParticleSystem("blood_trail_alien");
|
||
PrecacheParticleSystem("blood_drip_green_trail");
|
||
PrecacheParticleSystem("blood_impact_green_01");
|
||
PrecacheParticleSystem("blood_green_normal_smoke");
|
||
PrecacheParticleSystem("blood_spit_trail_green");
|
||
PrecacheParticleSystem("blood_impact_red_01");
|
||
PrecacheParticleSystem("weapon_grenade_attachments");
|
||
PrecacheParticleSystem("grenade_explosion_01");
|
||
PrecacheParticleSystem("c17_waterfx_barrel-explosion");
|
||
PrecacheParticleSystem("Bullet_glow");
|
||
PrecacheParticleSystem("Bullet_exhaust");
|
||
PrecacheParticleSystem("weapon_dust_stream");
|
||
PrecacheParticleSystem("shell_exhaust_smoke");
|
||
PrecacheParticleSystem("Shockrifle_sparks");
|
||
|
||
PrecacheModel("models/weapons/MAGS/w_mach_m249_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_mach_negev_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_223_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_cz_75_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_deagle_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_elite_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_fiveseven_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_glock18_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_hkp2000_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_p250_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_pist_tec9_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_ak47_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_ar2_big_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_ar2_small_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_aug_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_famas_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_galilar_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_m4a1_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_sg556_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_rif_m4a1_s_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_shot_mag7_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_shot_nova_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_shot_sawedoff_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_shot_xm1014_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_bizon_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_mac10_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_mp5sd_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_mp7_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_mp9_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_p90_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_smg_ump45_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_snip_awp_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_snip_g3sg1_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_snip_scar20_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/w_snip_ssg08_mag.mdl");
|
||
PrecacheModel("models/weapons/MAGS/irifle_empty_mag.mdl");
|
||
|
||
PrecacheScriptSound("HL2Player.SlowIn");
|
||
PrecacheScriptSound("HL2Player.SlowOut");
|
||
PrecacheScriptSound("Player.FallGib");
|
||
PrecacheScriptSound("Player.Death");
|
||
PrecacheScriptSound("Player.PlasmaDamage");
|
||
PrecacheScriptSound("Player.SonicDamage");
|
||
PrecacheScriptSound("Player.DrownStart");
|
||
PrecacheScriptSound("Player.DrownContinue");
|
||
PrecacheScriptSound("Player.Wade");
|
||
PrecacheScriptSound("Player.AmbientUnderWater");
|
||
enginesound->PrecacheSentenceGroup("HEV");
|
||
|
||
|
||
// in the event that the player JUST spawned, and the level node graph
|
||
// was loaded, fix all of the node graph pointers before the game starts.
|
||
|
||
// !!!BUGBUG - now that we have multiplayer, this needs to be moved!
|
||
/* todo - put in better spot and use new ainetowrk stuff
|
||
if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet )
|
||
{
|
||
if ( !WorldGraph.FSetGraphPointers() )
|
||
{
|
||
Msg( "**Graph pointers were not set!\n");
|
||
}
|
||
else
|
||
{
|
||
Msg( "**Graph Pointers Set!\n" );
|
||
}
|
||
}
|
||
*/
|
||
|
||
// SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific)
|
||
// because they need to precache before any clients have connected
|
||
|
||
// init geiger counter vars during spawn and each time
|
||
// we cross a level transition
|
||
m_flgeigerRange = 1000;
|
||
m_igeigerRangePrev = 1000;
|
||
|
||
#if 0
|
||
// @Note (toml 04-19-04): These are saved, used to be slammed here
|
||
m_bitsDamageType = 0;
|
||
m_bitsHUDDamage = -1;
|
||
SetPlayerUnderwter(false);
|
||
|
||
m_iTrain = TRAIN_NEW;
|
||
#endif
|
||
|
||
m_iClientBattery = -1;
|
||
|
||
m_iUpdateTime = 5; // won't update for 1/2 a second
|
||
|
||
if (gInitHUD)
|
||
m_fInitHUD = true;
|
||
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Force this player to immediately respawn
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ForceRespawn(void)
|
||
{
|
||
RemoveAllItems(true);
|
||
|
||
// Reset ground state for airwalk animations
|
||
SetGroundEntity(NULL);
|
||
|
||
// Stop any firing that was taking place before respawn.
|
||
m_nButtons = 0;
|
||
|
||
Spawn();
|
||
}
|
||
|
||
int CBasePlayer::Save(ISave &save)
|
||
{
|
||
if (!BaseClass::Save(save))
|
||
return 0;
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
// Friend class of CBaseEntity to access private member data.
|
||
class CPlayerRestoreHelper
|
||
{
|
||
public:
|
||
|
||
const Vector &GetAbsOrigin(CBaseEntity *pent)
|
||
{
|
||
return pent->m_vecAbsOrigin;
|
||
}
|
||
|
||
const Vector &GetAbsVelocity(CBaseEntity *pent)
|
||
{
|
||
return pent->m_vecAbsVelocity;
|
||
}
|
||
};
|
||
|
||
|
||
int CBasePlayer::Restore(IRestore &restore)
|
||
{
|
||
int status = BaseClass::Restore(restore);
|
||
if (!status)
|
||
return 0;
|
||
|
||
CSaveRestoreData *pSaveData = gpGlobals->pSaveData;
|
||
// landmark isn't present.
|
||
if (!pSaveData->levelInfo.fUseLandmark)
|
||
{
|
||
Msg("No Landmark:%s\n", pSaveData->levelInfo.szLandmarkName);
|
||
|
||
// default to normal spawn
|
||
CBaseEntity *pSpawnSpot = EntSelectSpawnPoint();
|
||
SetLocalOrigin(pSpawnSpot->GetLocalOrigin() + Vector(0, 0, 1));
|
||
SetLocalAngles(pSpawnSpot->GetLocalAngles());
|
||
}
|
||
|
||
QAngle newViewAngles = pl.v_angle;
|
||
newViewAngles.z = 0; // Clear out roll
|
||
SetLocalAngles(newViewAngles);
|
||
SnapEyeAngles(newViewAngles);
|
||
|
||
// Copied from spawn() for now
|
||
SetBloodColor(BLOOD_COLOR_RED);
|
||
|
||
// clear this - it will get reset by touching the trigger again
|
||
m_afPhysicsFlags &= ~PFLAG_VPHYSICS_MOTIONCONTROLLER;
|
||
|
||
if (GetFlags() & FL_DUCKING)
|
||
{
|
||
// Use the crouch HACK
|
||
FixPlayerCrouchStuck(this);
|
||
UTIL_SetSize(this, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
|
||
m_Local.m_bDucked = true;
|
||
}
|
||
else
|
||
{
|
||
m_Local.m_bDucked = false;
|
||
UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
|
||
}
|
||
|
||
// We need to get at m_vecAbsOrigin as it was restored but can't let it be
|
||
// recalculated by a call to GetAbsOrigin because hierarchy isn't fully restored yet,
|
||
// so we use this backdoor to get at the private data in CBaseEntity.
|
||
CPlayerRestoreHelper helper;
|
||
InitVCollision(helper.GetAbsOrigin(this), helper.GetAbsVelocity(this));
|
||
|
||
if (!GetSlowMoIsEnabled())
|
||
DisableSlowMo(true);
|
||
else
|
||
{
|
||
if (GetSlowMoIsEnabled() != m_bSlowMoIsEnabledTemp)
|
||
EnableSlowMo(true);
|
||
}
|
||
|
||
// success
|
||
return 1;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::OnRestore(void)
|
||
{
|
||
BaseClass::OnRestore();
|
||
|
||
|
||
SetViewEntity(m_hViewEntity);
|
||
SetDefaultFOV(m_iDefaultFOV); // force this to reset if zero
|
||
|
||
// Calculate this immediately
|
||
m_nVehicleViewSavedFrame = 0;
|
||
|
||
m_nBodyPitchPoseParam = LookupPoseParameter("body_pitch");
|
||
}
|
||
|
||
void CBasePlayer::EnableCheats(bool &cheatsWasEnabled)
|
||
{
|
||
if (!sv_cheats->GetInt())
|
||
{
|
||
cheatsWasEnabled = true;
|
||
sv_cheats->SetValue(1);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::DisableCheats(bool &cheatsWasEnabled)
|
||
{
|
||
if (cheatsWasEnabled)
|
||
{
|
||
sv_cheats->SetValue(0);
|
||
cheatsWasEnabled = false;
|
||
}
|
||
}
|
||
|
||
//void StateUpdateInSelection();
|
||
ConVar oc_player_state_inselection("oc_player_state_inselection", "0", FCVAR_HIDDEN, "");// , (FnChangeCallback_t)StateUpdateInSelection);
|
||
|
||
void CBasePlayer::SelectionSlowMoHandle()
|
||
{
|
||
switch (oc_player_state_inselection.GetBool())
|
||
{
|
||
case 0:
|
||
{
|
||
if (m_bIsInSelectionMode)
|
||
{
|
||
m_bIsInSelectionMode = false;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
}
|
||
break;
|
||
case 1:
|
||
{
|
||
if (!m_bIsInSelectionMode)
|
||
{
|
||
m_bIsInSelectionMode = true;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
return;
|
||
|
||
//DevMsg("host_timescale: %.2f \n", cvar->FindVar("host_timescale")->GetFloat());
|
||
//DevMsg("m_flSelectionAlpha: %.2f \n", m_flSelectionAlpha);
|
||
|
||
if (!cvar->FindVar("oc_player_weap_selection_enable_fade")->GetBool())
|
||
{
|
||
if (IsInSelectionSlowMo())
|
||
{
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
m_bIsInSelectionMode = false;
|
||
//m_flSelectionAlpha = 0;
|
||
|
||
host_timescale->SetValue(1);
|
||
|
||
DisableCheats(CheatsWasEnabled);
|
||
}
|
||
return;
|
||
}
|
||
|
||
//DevMsg("CheatsWasEnabled: %i \n", CheatsWasEnabled);
|
||
//DevMsg("sv_cheats: %i \n", sv_cheats->GetInt());
|
||
|
||
if (IsInSelectionSlowMo())
|
||
{
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
float threshold = cvar->FindVar("oc_player_weap_selection_time_threshold")->GetFloat();
|
||
threshold = Clamp(threshold, 0.1f, 0.95f);
|
||
|
||
host_timescale->SetValue(1 - threshold);
|
||
|
||
//DisableCheats(CheatsWasEnabled);
|
||
}
|
||
else
|
||
{
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
host_timescale->SetValue(1);
|
||
|
||
m_bIsInSelectionMode = false;
|
||
|
||
DisableCheats(CheatsWasEnabled);
|
||
}
|
||
}
|
||
|
||
bool CBasePlayer::IsInSelectionSlowMo()
|
||
{
|
||
return m_bIsInSelectionMode;// && m_flSelectionAlpha == 0;
|
||
}
|
||
|
||
void CBasePlayer::SlowMoHandle()
|
||
{
|
||
SelectionSlowMoHandle();
|
||
|
||
if (!IsAlive() || !IsSuitEquipped())
|
||
{
|
||
if (GetSlowMoIsEnabled())
|
||
{
|
||
DisableSlowMo();
|
||
}
|
||
}
|
||
|
||
/*if (GetSlowMoIsEnabled() != m_bSlowMoIsEnabledTemp)
|
||
{
|
||
switch ((int)GetSlowMoIsEnabled())
|
||
{
|
||
case 0:
|
||
{
|
||
DisableSlowMo(true);
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
{
|
||
EnableSlowMo(true);
|
||
}
|
||
break;
|
||
}
|
||
}*/
|
||
|
||
/*DevMsg("interval_per_tick: %.2f \n", gpGlobals->interval_per_tick);
|
||
DevMsg("frametime: %.2f \n", gpGlobals->frametime);*/
|
||
|
||
/*if (GetSlowMoIsEnabled() && !(host_timescale->GetFloat() < 1.f))
|
||
EnableSlowMo(true);
|
||
if (!GetSlowMoIsEnabled() && (host_timescale->GetFloat() < 1.f))*/
|
||
//DisableSlowMo(true);
|
||
|
||
/*if (!GetSlowMoIsEnabled() && IsNotInSelectionSlowMo())
|
||
{
|
||
DisableSlowMo();
|
||
}*/
|
||
if (GetSlowMoIsEnabled())
|
||
{
|
||
if (m_flNextSlowMoTick < gpGlobals->curtime)
|
||
{
|
||
m_flNextSlowMoTick = gpGlobals->curtime + cvar->FindVar("oc_player_slowmo_decrease_delay")->GetFloat();//delay
|
||
DecreaseSlowMoPercentage();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_iSlowMoPercentage < 100)
|
||
{
|
||
if (m_flNextSlowMoTick < gpGlobals->curtime)
|
||
{
|
||
m_flNextSlowMoTick = gpGlobals->curtime + cvar->FindVar("oc_player_slowmo_increase_delay")->GetFloat();//delay
|
||
IncreaseSlowMoPercentage();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::EnableSlowMo(bool forced)
|
||
{
|
||
if (forced)
|
||
{
|
||
SetSlowMoIsEnabled(true);
|
||
|
||
UTIL_RestartAmbientSounds();
|
||
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
ConVarRef oc_player_slowmo_timescale("oc_player_slowmo_timescale");
|
||
|
||
host_timescale->SetValue(oc_player_slowmo_timescale.GetFloat());
|
||
|
||
if ((ChangedBulletsStatment == 1) && (cvar->FindVar("oc_weapons_enable_dynamic_bullets")->GetInt() == 1))
|
||
{
|
||
(cvar->FindVar("oc_weapons_enable_dynamic_bullets")->SetValue(2));
|
||
ChangedBulletsStatment = 2;
|
||
}
|
||
else
|
||
{
|
||
ChangedBulletsStatment = 0;
|
||
}
|
||
|
||
//DisableCheats(CheatsWasEnabled);
|
||
|
||
CEffectData data;
|
||
data.m_flScale = host_timescale->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
|
||
return;
|
||
}
|
||
|
||
if (!IsSuitEquipped())
|
||
return;
|
||
|
||
if (m_bIsInSelectionMode)
|
||
return;
|
||
|
||
float flFadeTime = 0.4f;
|
||
|
||
UTIL_RestartAmbientSounds();
|
||
|
||
SetSlowMoIsEnabled(true);
|
||
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
EmitSound("HL2Player.SlowIn");
|
||
|
||
ConVarRef oc_player_slowmo_timescale("oc_player_slowmo_timescale");
|
||
|
||
host_timescale->SetValue(oc_player_slowmo_timescale.GetFloat());
|
||
|
||
|
||
color32 white = { 55, 55, 155, 25 };
|
||
|
||
UTIL_ScreenFade(this, white, flFadeTime, 0.1, FFADE_IN);
|
||
|
||
if ((cvar->FindVar("oc_weapons_enable_dynamic_bullets")->GetInt() == 2))
|
||
{
|
||
(cvar->FindVar("oc_weapons_enable_dynamic_bullets")->SetValue(1));
|
||
ChangedBulletsStatment = 1;
|
||
}
|
||
|
||
//DisableCheats(CheatsWasEnabled);
|
||
|
||
CEffectData data;
|
||
data.m_flScale = host_timescale->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
|
||
void CBasePlayer::IncreaseSlowMoPercentage()
|
||
{
|
||
if (m_iSlowMoPercentage < 100)
|
||
m_iSlowMoPercentage++;
|
||
}
|
||
|
||
void CBasePlayer::DecreaseSlowMoPercentage()
|
||
{
|
||
if (m_iSlowMoPercentage > 0)
|
||
m_iSlowMoPercentage--;
|
||
else
|
||
{
|
||
if (GetSlowMoIsEnabled())
|
||
DisableSlowMo();
|
||
}
|
||
}
|
||
void CBasePlayer::DisableSlowMo(bool forced)
|
||
{
|
||
if (forced)
|
||
{
|
||
SetSlowMoIsEnabled(false);
|
||
|
||
UTIL_RestartAmbientSounds();
|
||
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
host_timescale->SetValue(1.f);
|
||
|
||
if ((ChangedBulletsStatment == 1) && (cvar->FindVar("oc_weapons_enable_dynamic_bullets")->GetInt() == 1))
|
||
{
|
||
(cvar->FindVar("oc_weapons_enable_dynamic_bullets")->SetValue(2));
|
||
ChangedBulletsStatment = 2;
|
||
}
|
||
else
|
||
{
|
||
ChangedBulletsStatment = 0;
|
||
}
|
||
|
||
DisableCheats(CheatsWasEnabled);
|
||
|
||
CEffectData data;
|
||
data.m_flScale = host_timescale->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
|
||
return;
|
||
}
|
||
|
||
float flFadeTime = 1.0f;
|
||
|
||
SetSlowMoIsEnabled(false);
|
||
|
||
UTIL_RestartAmbientSounds();
|
||
|
||
//bool CheatsWasEnabled = false;
|
||
|
||
EnableCheats(CheatsWasEnabled);
|
||
|
||
host_timescale->SetValue(1.f);
|
||
|
||
color32 white = { 55, 55, 155, 25 };
|
||
|
||
UTIL_ScreenFade(this, white, flFadeTime, 0.2, FFADE_IN);
|
||
|
||
if ((ChangedBulletsStatment == 1) && (cvar->FindVar("oc_weapons_enable_dynamic_bullets")->GetInt() == 1))
|
||
{
|
||
(cvar->FindVar("oc_weapons_enable_dynamic_bullets")->SetValue(2));
|
||
ChangedBulletsStatment = 2;
|
||
}
|
||
else
|
||
{
|
||
ChangedBulletsStatment = 0;
|
||
}
|
||
|
||
DisableCheats(CheatsWasEnabled);
|
||
|
||
EmitSound("HL2Player.SlowOut");
|
||
|
||
//engine->ServerCommand("oc_update_all_sounds\n");
|
||
|
||
CEffectData data;
|
||
data.m_flScale = host_timescale->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
|
||
|
||
/*void StateUpdateInSelection()
|
||
{
|
||
switch (oc_player_state_inselection.GetBool())
|
||
{
|
||
case 0:
|
||
{
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
pPlayer->m_bIsInSelectionMode = false;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
break;
|
||
case 1:
|
||
{
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
pPlayer->m_bIsInSelectionMode = true;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
CON_COMMAND(Server_OpenSelection, "toggle Weapon Menu Open")
|
||
{
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
pPlayer->m_bIsInSelectionMode = true;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
|
||
/*CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
if (pPlayer->GetSlowMoIsEnabled())
|
||
return;
|
||
|
||
if (pPlayer->IsSuitEquipped() && pPlayer->WeaponCount())
|
||
{
|
||
pPlayer->m_bIsInSelectionMode = true;
|
||
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}*/
|
||
//engine->ServerCommand("oc_updateLooping_sounds\n");
|
||
|
||
//IGameSystem::OnRestoreAllSystems();
|
||
/*}
|
||
|
||
CON_COMMAND(Server_HideSelection, "toggle Weapon Menu Hide")
|
||
{
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
pPlayer->m_bIsInSelectionMode = false;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
|
||
/*if (pPlayer->GetSlowMoIsEnabled())
|
||
return;
|
||
|
||
if (cvar->FindVar("host_timescale")->GetFloat() != 1.f)
|
||
{
|
||
pPlayer->m_bIsInSelectionMode = false;
|
||
|
||
CEffectData data;
|
||
data.m_flScale = cvar->FindVar("host_timescale")->GetFloat();
|
||
DispatchEffect("UpdateAllSounds", data);
|
||
}*/
|
||
|
||
//engine->ServerCommand("oc_updateLooping_sounds\n");
|
||
|
||
//IGameSystem::OnRestoreAllSystems();
|
||
//}
|
||
|
||
CON_COMMAND(oc_slo_mo, "toggle Slo-Mo mode")
|
||
{
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL)
|
||
return;
|
||
|
||
if (pPlayer->IsInSelectionSlowMo())
|
||
return;
|
||
|
||
if (!pPlayer->GetSlowMoIsEnabled())
|
||
{
|
||
pPlayer->EnableSlowMo();
|
||
}
|
||
else
|
||
{
|
||
pPlayer->DisableSlowMo();
|
||
}
|
||
|
||
//engine->ServerCommand("oc_updateLooping_sounds\n");
|
||
}
|
||
|
||
CON_COMMAND(oc_nightvision, "toggle Nightvision")
|
||
{
|
||
ConVarRef NV("oc_player_allow_nightvision");
|
||
|
||
if (!NV.GetBool())
|
||
return;
|
||
|
||
CBasePlayer* pPlayer = UTIL_GetLocalPlayer();
|
||
if (pPlayer == NULL) return;
|
||
|
||
if (!pPlayer->IsSuitEquipped() /*|| pPlayer->FlashlightIsOn()*/) return;
|
||
|
||
pPlayer->m_bNightvisionEnabled ^= true;
|
||
|
||
//engine->ClientCommand(UTIL_GetCommandClient()->edict(), "oc_enable_nightvision");
|
||
}
|
||
|
||
|
||
void CBasePlayer::SetArmorValue(int value)
|
||
{
|
||
m_ArmorValue = value;
|
||
}
|
||
|
||
void CBasePlayer::IncrementArmorValue(int nCount, int nMaxValue)
|
||
{
|
||
m_ArmorValue += nCount;
|
||
if (nMaxValue > 0)
|
||
{
|
||
if (m_ArmorValue > nMaxValue)
|
||
m_ArmorValue = nMaxValue;
|
||
}
|
||
}
|
||
|
||
// used by the physics gun and game physics... is there a better interface?
|
||
void CBasePlayer::SetPhysicsFlag(int nFlag, bool bSet)
|
||
{
|
||
if (bSet)
|
||
m_afPhysicsFlags |= nFlag;
|
||
else
|
||
m_afPhysicsFlags &= ~nFlag;
|
||
}
|
||
|
||
|
||
void CBasePlayer::NotifyNearbyRadiationSource(float flRange)
|
||
{
|
||
// if player's current geiger counter range is larger
|
||
// than range to this trigger hurt, reset player's
|
||
// geiger counter range
|
||
|
||
if (m_flgeigerRange >= flRange)
|
||
m_flgeigerRange = flRange;
|
||
}
|
||
|
||
void CBasePlayer::AllowImmediateDecalPainting()
|
||
{
|
||
m_flNextDecalTime = gpGlobals->curtime;
|
||
}
|
||
|
||
// Suicide...
|
||
void CBasePlayer::CommitSuicide(bool bExplode /*= false*/, bool bForce /*= false*/)
|
||
{
|
||
MDLCACHE_CRITICAL_SECTION();
|
||
|
||
if (!IsAlive())
|
||
return;
|
||
|
||
// prevent suiciding too often
|
||
if (m_fNextSuicideTime > gpGlobals->curtime && !bForce)
|
||
return;
|
||
|
||
// don't let them suicide for 5 seconds after suiciding
|
||
m_fNextSuicideTime = gpGlobals->curtime + 5;
|
||
|
||
int fDamage = DMG_PREVENT_PHYSICS_FORCE | (bExplode ? (DMG_BLAST | DMG_ALWAYSGIB) : DMG_NEVERGIB);
|
||
|
||
// have the player kill themself
|
||
m_iHealth = 0;
|
||
CTakeDamageInfo info(this, this, 0, fDamage, m_iSuicideCustomKillFlags);
|
||
Event_Killed(info);
|
||
Event_Dying(info);
|
||
m_iSuicideCustomKillFlags = 0;
|
||
}
|
||
|
||
// Suicide with style...
|
||
void CBasePlayer::CommitSuicide(const Vector &vecForce, bool bExplode /*= false*/, bool bForce /*= false*/)
|
||
{
|
||
MDLCACHE_CRITICAL_SECTION();
|
||
|
||
// Already dead.
|
||
if (!IsAlive())
|
||
return;
|
||
|
||
// Prevent suicides for a time.
|
||
if (m_fNextSuicideTime > gpGlobals->curtime && !bForce)
|
||
return;
|
||
|
||
m_fNextSuicideTime = gpGlobals->curtime + 5;
|
||
|
||
// Apply the force.
|
||
int nHealth = GetHealth();
|
||
|
||
// Kill the player.
|
||
CTakeDamageInfo info;
|
||
info.SetDamage(nHealth + 10);
|
||
info.SetAttacker(this);
|
||
info.SetDamageType(bExplode ? DMG_ALWAYSGIB : DMG_GENERIC);
|
||
info.SetDamageForce(vecForce);
|
||
info.SetDamagePosition(WorldSpaceCenter());
|
||
TakeDamage(info);
|
||
}
|
||
|
||
//==============================================
|
||
// HasWeapons - do I have any weapons at all?
|
||
//==============================================
|
||
bool CBasePlayer::HasWeapons(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < WeaponCount(); i++)
|
||
{
|
||
if (GetWeapon(i))
|
||
{
|
||
if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt() ? grenadeState <= 0 && GetWeapon(i)->thisType == TYPE_GRENADE : false)
|
||
return false;
|
||
|
||
if (!GetWeapon(i)->IsWeaponVisible())
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &vecForce -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::VelocityPunch(const Vector &vecForce)
|
||
{
|
||
// Clear onground and add velocity.
|
||
SetGroundEntity(NULL);
|
||
ApplyAbsVelocityImpulse(vecForce);
|
||
}
|
||
|
||
|
||
//--------------------------------------------------------------------------------------------------------------
|
||
// VEHICLES
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Whether or not the player is currently able to enter the vehicle
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::CanEnterVehicle(IServerVehicle *pVehicle, int nRole)
|
||
{
|
||
// Must not have a passenger there already
|
||
if (pVehicle->GetPassenger(nRole))
|
||
return false;
|
||
|
||
// Must be able to holster our current weapon (ie. grav gun!)
|
||
if (pVehicle->IsPassengerUsingStandardWeapons(nRole) == false)
|
||
{
|
||
//Must be able to stow our weapon
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if ((pWeapon != NULL) && (pWeapon->CanHolster() == false))
|
||
return false;
|
||
}
|
||
|
||
// Must be alive
|
||
if (IsAlive() == false)
|
||
return false;
|
||
|
||
// Can't be pulled by a barnacle
|
||
if (IsEFlagSet(EFL_IS_BEING_LIFTED_BY_BARNACLE))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Put this player in a vehicle
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::GetInVehicle(IServerVehicle *pVehicle, int nRole)
|
||
{
|
||
Assert(NULL == m_hVehicle.Get());
|
||
Assert(nRole >= 0);
|
||
|
||
// Make sure we can enter the vehicle
|
||
if (CanEnterVehicle(pVehicle, nRole) == false)
|
||
return false;
|
||
|
||
CBaseEntity *pEnt = pVehicle->GetVehicleEnt();
|
||
Assert(pEnt);
|
||
|
||
// Try to stow weapons
|
||
if (pVehicle->IsPassengerUsingStandardWeapons(nRole) == false)
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if (pWeapon != NULL)
|
||
{
|
||
pWeapon->Holster(NULL);
|
||
}
|
||
|
||
#ifndef HL2_DLL
|
||
m_Local.m_iHideHUD |= HIDEHUD_WEAPONSELECTION;
|
||
#endif
|
||
m_Local.m_iHideHUD |= HIDEHUD_INVEHICLE;
|
||
}
|
||
|
||
if (!pVehicle->IsPassengerVisible(nRole))
|
||
{
|
||
AddEffects(EF_NODRAW);
|
||
}
|
||
|
||
// Put us in the vehicle
|
||
pVehicle->SetPassenger(nRole, this);
|
||
|
||
ViewPunchReset();
|
||
|
||
// Setting the velocity to 0 will cause the IDLE animation to play
|
||
SetAbsVelocity(vec3_origin);
|
||
SetMoveType(MOVETYPE_NOCLIP);
|
||
|
||
// This is a hack to fixup the player's stats since they really didn't "cheat" and enter noclip from the console
|
||
gamestats->Event_DecrementPlayerEnteredNoClip(this);
|
||
|
||
// Get the seat position we'll be at in this vehicle
|
||
Vector vSeatOrigin;
|
||
QAngle qSeatAngles;
|
||
pVehicle->GetPassengerSeatPoint(nRole, &vSeatOrigin, &qSeatAngles);
|
||
|
||
// Set us to that position
|
||
SetAbsOrigin(vSeatOrigin);
|
||
SetAbsAngles(qSeatAngles);
|
||
|
||
// Parent to the vehicle
|
||
SetParent(pEnt);
|
||
|
||
SetCollisionGroup(COLLISION_GROUP_IN_VEHICLE);
|
||
|
||
// We cannot be ducking -- do all this before SetPassenger because it
|
||
// saves our view offset for restoration when we exit the vehicle.
|
||
RemoveFlag(FL_DUCKING);
|
||
SetViewOffset(VEC_VIEW_SCALED(this));
|
||
m_Local.m_bDucked = false;
|
||
m_Local.m_bDucking = false;
|
||
m_Local.m_flDucktime = 0.0f;
|
||
m_Local.m_flDuckJumpTime = 0.0f;
|
||
m_Local.m_flJumpTime = 0.0f;
|
||
|
||
// Turn our toggled duck off
|
||
if (GetToggledDuckState())
|
||
{
|
||
ToggleDuck();
|
||
}
|
||
|
||
m_hVehicle = pEnt;
|
||
|
||
// Throw an event indicating that the player entered the vehicle.
|
||
g_pNotify->ReportNamedEvent(this, "PlayerEnteredVehicle");
|
||
|
||
m_iVehicleAnalogBias = VEHICLE_ANALOG_BIAS_NONE;
|
||
|
||
OnVehicleStart();
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Remove this player from a vehicle
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::LeaveVehicle(const Vector &vecExitPoint, const QAngle &vecExitAngles)
|
||
{
|
||
if (NULL == m_hVehicle.Get())
|
||
return;
|
||
|
||
IServerVehicle *pVehicle = GetVehicle();
|
||
Assert(pVehicle);
|
||
|
||
int nRole = pVehicle->GetPassengerRole(this);
|
||
Assert(nRole >= 0);
|
||
|
||
SetParent(NULL);
|
||
|
||
// Find the first non-blocked exit point:
|
||
Vector vNewPos = GetAbsOrigin();
|
||
QAngle qAngles = GetAbsAngles();
|
||
if (vecExitPoint == vec3_origin)
|
||
{
|
||
// FIXME: this might fail to find a safe exit point!!
|
||
pVehicle->GetPassengerExitPoint(nRole, &vNewPos, &qAngles);
|
||
}
|
||
else
|
||
{
|
||
vNewPos = vecExitPoint;
|
||
qAngles = vecExitAngles;
|
||
}
|
||
OnVehicleEnd(vNewPos);
|
||
SetAbsOrigin(vNewPos);
|
||
SetAbsAngles(qAngles);
|
||
// Clear out any leftover velocity
|
||
SetAbsVelocity(vec3_origin);
|
||
|
||
qAngles[ROLL] = 0;
|
||
SnapEyeAngles(qAngles);
|
||
|
||
#ifndef HL2_DLL
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
|
||
#endif
|
||
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_INVEHICLE;
|
||
|
||
RemoveEffects(EF_NODRAW);
|
||
|
||
SetMoveType(MOVETYPE_WALK);
|
||
SetCollisionGroup(COLLISION_GROUP_PLAYER);
|
||
|
||
if (VPhysicsGetObject())
|
||
{
|
||
VPhysicsGetObject()->SetPosition(vNewPos, vec3_angle, true);
|
||
}
|
||
|
||
m_hVehicle = NULL;
|
||
pVehicle->SetPassenger(nRole, NULL);
|
||
|
||
// Re-deploy our weapon
|
||
if (IsAlive())
|
||
{
|
||
if (GetActiveWeapon() && GetActiveWeapon()->IsWeaponVisible() == false)
|
||
{
|
||
GetActiveWeapon()->Deploy();
|
||
ShowCrosshair(true);
|
||
}
|
||
}
|
||
|
||
// Just cut all of the rumble effects.
|
||
RumbleEffect(RUMBLE_STOP_ALL, 0, RUMBLE_FLAGS_NONE);
|
||
}
|
||
|
||
|
||
//==============================================
|
||
// !!!UNDONE:ultra temporary SprayCan entity to apply
|
||
// decal frame at a time. For PreAlpha CD
|
||
//==============================================
|
||
class CSprayCan : public CPointEntity
|
||
{
|
||
public:
|
||
DECLARE_CLASS(CSprayCan, CPointEntity);
|
||
|
||
void Spawn(CBasePlayer *pOwner);
|
||
void Think(void);
|
||
|
||
virtual void Precache();
|
||
|
||
virtual int ObjectCaps(void) { return FCAP_DONT_SAVE; }
|
||
};
|
||
|
||
LINK_ENTITY_TO_CLASS(spraycan, CSprayCan);
|
||
PRECACHE_REGISTER(spraycan);
|
||
|
||
void CSprayCan::Spawn(CBasePlayer *pOwner)
|
||
{
|
||
SetLocalOrigin(pOwner->WorldSpaceCenter() + Vector(0, 0, 32));
|
||
SetLocalAngles(pOwner->EyeAngles());
|
||
SetOwnerEntity(pOwner);
|
||
SetNextThink(gpGlobals->curtime);
|
||
EmitSound("SprayCan.Paint");
|
||
}
|
||
|
||
void CSprayCan::Precache()
|
||
{
|
||
BaseClass::Precache();
|
||
|
||
PrecacheScriptSound("SprayCan.Paint");
|
||
}
|
||
|
||
void CSprayCan::Think(void)
|
||
{
|
||
CBasePlayer *pPlayer = ToBasePlayer(GetOwnerEntity());
|
||
if (pPlayer)
|
||
{
|
||
int playernum = pPlayer->entindex();
|
||
|
||
Vector forward;
|
||
trace_t tr;
|
||
|
||
AngleVectors(GetAbsAngles(), &forward);
|
||
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + forward * 128,
|
||
MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr);
|
||
|
||
UTIL_PlayerDecalTrace(&tr, playernum);
|
||
}
|
||
|
||
// Just painted last custom frame.
|
||
UTIL_Remove(this);
|
||
}
|
||
|
||
class CBloodSplat : public CPointEntity
|
||
{
|
||
public:
|
||
DECLARE_CLASS(CBloodSplat, CPointEntity);
|
||
|
||
void Spawn(CBaseEntity *pOwner);
|
||
void Think(void);
|
||
};
|
||
|
||
void CBloodSplat::Spawn(CBaseEntity *pOwner)
|
||
{
|
||
SetLocalOrigin(pOwner->WorldSpaceCenter() + Vector(0, 0, 32));
|
||
SetLocalAngles(pOwner->GetLocalAngles());
|
||
SetOwnerEntity(pOwner);
|
||
|
||
SetNextThink(gpGlobals->curtime + 0.1f);
|
||
}
|
||
|
||
void CBloodSplat::Think(void)
|
||
{
|
||
trace_t tr;
|
||
|
||
if (g_Language.GetInt() != LANGUAGE_GERMAN)
|
||
{
|
||
CBasePlayer *pPlayer;
|
||
pPlayer = ToBasePlayer(GetOwnerEntity());
|
||
|
||
Vector forward;
|
||
AngleVectors(GetAbsAngles(), &forward);
|
||
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + forward * 128,
|
||
MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr);
|
||
|
||
UTIL_BloodDecalTrace(&tr, BLOOD_COLOR_RED);
|
||
}
|
||
UTIL_Remove(this);
|
||
}
|
||
|
||
//==============================================
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Create and give the named item to the player. Then return it.
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *CBasePlayer::GiveNamedItem(const char *pszName, int iSubType)
|
||
{
|
||
// If I already own this type don't create one
|
||
if (Weapon_OwnsThisType(pszName, iSubType))
|
||
return NULL;
|
||
|
||
// Msg( "giving %s\n", pszName );
|
||
|
||
EHANDLE pent;
|
||
|
||
pent = CreateEntityByName(pszName);
|
||
if (pent == NULL)
|
||
{
|
||
Msg("NULL Ent in GiveNamedItem!\n");
|
||
return NULL;
|
||
}
|
||
|
||
pent->SetLocalOrigin(GetLocalOrigin());
|
||
pent->AddSpawnFlags(SF_NORESPAWN);
|
||
|
||
CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon*>((CBaseEntity*)pent);
|
||
if (pWeapon)
|
||
{
|
||
pWeapon->SetSubType(iSubType);
|
||
}
|
||
|
||
DispatchSpawn(pent);
|
||
|
||
if (pent != NULL && !(pent->IsMarkedForDeletion()))
|
||
{
|
||
pent->Touch(this);
|
||
}
|
||
|
||
return pent;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Returns the nearest COLLIBALE entity in front of the player
|
||
// that has a clear line of sight with the given classname
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *FindEntityClassForward(CBasePlayer *pMe, char *classname)
|
||
{
|
||
trace_t tr;
|
||
|
||
Vector forward;
|
||
pMe->EyeVectors(&forward);
|
||
UTIL_TraceLine(pMe->EyePosition(),
|
||
pMe->EyePosition() + forward * MAX_COORD_RANGE,
|
||
MASK_SOLID, pMe, COLLISION_GROUP_NONE, &tr);
|
||
if (tr.fraction != 1.0 && tr.DidHitNonWorldEntity())
|
||
{
|
||
CBaseEntity *pHit = tr.m_pEnt;
|
||
if (FClassnameIs(pHit, classname))
|
||
{
|
||
return pHit;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Returns the nearest COLLIBALE entity in front of the player
|
||
// that has a clear line of sight. If HULL is true, the trace will
|
||
// hit the collision hull of entities. Otherwise, the trace will hit
|
||
// hitboxes.
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *FindEntityForward(CBasePlayer *pMe, bool fHull)
|
||
{
|
||
if (pMe)
|
||
{
|
||
trace_t tr;
|
||
Vector forward;
|
||
int mask;
|
||
|
||
if (fHull)
|
||
{
|
||
mask = MASK_SOLID;
|
||
}
|
||
else
|
||
{
|
||
mask = MASK_SHOT;
|
||
}
|
||
|
||
pMe->EyeVectors(&forward);
|
||
UTIL_TraceLine(pMe->EyePosition(),
|
||
pMe->EyePosition() + forward * MAX_COORD_RANGE,
|
||
mask, pMe, COLLISION_GROUP_NONE, &tr);
|
||
if (tr.fraction != 1.0 && tr.DidHitNonWorldEntity())
|
||
{
|
||
return tr.m_pEnt;
|
||
}
|
||
}
|
||
return NULL;
|
||
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Finds the nearest entity in front of the player of the given
|
||
// classname, preferring collidable entities, but allows selection of
|
||
// enities that are on the other side of walls or objects
|
||
//
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *FindPickerEntityClass(CBasePlayer *pPlayer, char *classname)
|
||
{
|
||
// First try to trace a hull to an entity
|
||
CBaseEntity *pEntity = FindEntityClassForward(pPlayer, classname);
|
||
|
||
// If that fails just look for the nearest facing entity
|
||
if (!pEntity)
|
||
{
|
||
Vector forward;
|
||
Vector origin;
|
||
pPlayer->EyeVectors(&forward);
|
||
origin = pPlayer->WorldSpaceCenter();
|
||
pEntity = gEntList.FindEntityClassNearestFacing(origin, forward, 0.95, classname);
|
||
}
|
||
return pEntity;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Finds the nearest entity in front of the player, preferring
|
||
// collidable entities, but allows selection of enities that are
|
||
// on the other side of walls or objects
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *FindPickerEntity(CBasePlayer *pPlayer)
|
||
{
|
||
MDLCACHE_CRITICAL_SECTION();
|
||
|
||
// First try to trace a hull to an entity
|
||
CBaseEntity *pEntity = FindEntityForward(pPlayer, true);
|
||
|
||
// If that fails just look for the nearest facing entity
|
||
if (!pEntity)
|
||
{
|
||
Vector forward;
|
||
Vector origin;
|
||
pPlayer->EyeVectors(&forward);
|
||
origin = pPlayer->WorldSpaceCenter();
|
||
pEntity = gEntList.FindEntityNearestFacing(origin, forward, 0.95);
|
||
}
|
||
return pEntity;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Finds the nearest node in front of the player
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CAI_Node *FindPickerAINode(CBasePlayer *pPlayer, NodeType_e nNodeType)
|
||
{
|
||
Vector forward;
|
||
Vector origin;
|
||
|
||
pPlayer->EyeVectors(&forward);
|
||
origin = pPlayer->EyePosition();
|
||
return g_pAINetworkManager->GetEditOps()->FindAINodeNearestFacing(origin, forward, 0.90, nNodeType);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Finds the nearest link in front of the player
|
||
// Input :
|
||
// Output :
|
||
//-----------------------------------------------------------------------------
|
||
CAI_Link *FindPickerAILink(CBasePlayer* pPlayer)
|
||
{
|
||
Vector forward;
|
||
Vector origin;
|
||
|
||
pPlayer->EyeVectors(&forward);
|
||
origin = pPlayer->EyePosition();
|
||
return g_pAINetworkManager->GetEditOps()->FindAILinkNearestFacing(origin, forward, 0.90);
|
||
}
|
||
|
||
/*
|
||
===============
|
||
ForceClientDllUpdate
|
||
|
||
When recording a demo, we need to have the server tell us the entire client state
|
||
so that the client side .dll can behave correctly.
|
||
Reset stuff so that the state is transmitted.
|
||
===============
|
||
*/
|
||
void CBasePlayer::ForceClientDllUpdate(void)
|
||
{
|
||
m_iClientBattery = -1;
|
||
m_iTrain |= TRAIN_NEW; // Force new train message.
|
||
m_fWeapon = false; // Force weapon send
|
||
|
||
// Force all HUD data to be resent to client
|
||
m_fInitHUD = true;
|
||
|
||
// Now force all the necessary messages
|
||
// to be sent.
|
||
UpdateClientData();
|
||
|
||
UTIL_RestartAmbientSounds(); // MOTODO that updates the sounds for everybody
|
||
}
|
||
|
||
/*
|
||
============
|
||
ImpulseCommands
|
||
============
|
||
*/
|
||
|
||
void CBasePlayer::ImpulseCommands()
|
||
{
|
||
trace_t tr;
|
||
|
||
int iImpulse = (int)m_nImpulse;
|
||
switch (iImpulse)
|
||
{
|
||
case 100:
|
||
// temporary flashlight for level designers
|
||
if (FlashlightIsOn())
|
||
{
|
||
FlashlightTurnOff();
|
||
}
|
||
else
|
||
{
|
||
FlashlightTurnOn();
|
||
}
|
||
break;
|
||
|
||
case 200:
|
||
if (sv_cheats->GetBool())
|
||
{
|
||
CBaseCombatWeapon *pWeapon;
|
||
|
||
pWeapon = GetActiveWeapon();
|
||
|
||
if (pWeapon->IsEffectActive(EF_NODRAW))
|
||
{
|
||
pWeapon->Deploy();
|
||
}
|
||
else
|
||
{
|
||
pWeapon->Holster();
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 201:// paint decal
|
||
|
||
if (gpGlobals->curtime < m_flNextDecalTime)
|
||
{
|
||
// too early!
|
||
break;
|
||
}
|
||
|
||
{
|
||
Vector forward;
|
||
EyeVectors(&forward);
|
||
UTIL_TraceLine(EyePosition(),
|
||
EyePosition() + forward * 128,
|
||
MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
|
||
}
|
||
|
||
if (tr.fraction != 1.0)
|
||
{// line hit something, so paint a decal
|
||
m_flNextDecalTime = gpGlobals->curtime + decalfrequency.GetFloat();
|
||
CSprayCan *pCan = CREATE_UNSAVED_ENTITY(CSprayCan, "spraycan");
|
||
pCan->Spawn(this);
|
||
|
||
#ifdef CSTRIKE_DLL
|
||
//=============================================================================
|
||
// HPE_BEGIN:
|
||
// [pfreese] Fire off a game event - the Counter-Strike stats manager listens
|
||
// to these achievements for one of the CS achievements.
|
||
//=============================================================================
|
||
|
||
IGameEvent * event = gameeventmanager->CreateEvent("player_decal");
|
||
if (event)
|
||
{
|
||
event->SetInt("userid", GetUserID());
|
||
gameeventmanager->FireEvent(event);
|
||
}
|
||
|
||
//=============================================================================
|
||
// HPE_END
|
||
//=============================================================================
|
||
#endif
|
||
}
|
||
|
||
break;
|
||
|
||
case 202:// player jungle sound
|
||
if (gpGlobals->curtime < m_flNextDecalTime)
|
||
{
|
||
// too early!
|
||
break;
|
||
|
||
}
|
||
|
||
EntityMessageBegin(this);
|
||
WRITE_BYTE(PLAY_PLAYER_JINGLE);
|
||
MessageEnd();
|
||
|
||
m_flNextDecalTime = gpGlobals->curtime + decalfrequency.GetFloat();
|
||
break;
|
||
|
||
default:
|
||
// check all of the cheat impulse commands now
|
||
CheatImpulseCommands(iImpulse);
|
||
break;
|
||
}
|
||
|
||
m_nImpulse = 0;
|
||
}
|
||
|
||
#ifdef HL2_EPISODIC
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
static void CreateJalopy(CBasePlayer *pPlayer)
|
||
{
|
||
// Cheat to create a jeep in front of the player
|
||
Vector vecForward;
|
||
AngleVectors(pPlayer->EyeAngles(), &vecForward);
|
||
CBaseEntity *pJeep = (CBaseEntity *)CreateEntityByName("prop_vehicle_jeep");
|
||
if (pJeep)
|
||
{
|
||
Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector(0, 0, 64);
|
||
QAngle vecAngles(0, pPlayer->GetAbsAngles().y - 90, 0);
|
||
pJeep->SetAbsOrigin(vecOrigin);
|
||
pJeep->SetAbsAngles(vecAngles);
|
||
pJeep->KeyValue("model", "models/vehicle.mdl");
|
||
pJeep->KeyValue("solid", "6");
|
||
pJeep->KeyValue("targetname", "jeep");
|
||
pJeep->KeyValue("vehiclescript", "scripts/vehicles/jalopy.txt");
|
||
DispatchSpawn(pJeep);
|
||
pJeep->Activate();
|
||
pJeep->Teleport(&vecOrigin, &vecAngles, NULL);
|
||
}
|
||
}
|
||
|
||
void CC_CH_CreateJalopy(void)
|
||
{
|
||
CBasePlayer *pPlayer = UTIL_GetCommandClient();
|
||
if (!pPlayer)
|
||
return;
|
||
CreateJalopy(pPlayer);
|
||
}
|
||
|
||
static ConCommand ch_createjalopy("ch_createjalopy", CC_CH_CreateJalopy, "Spawn jalopy in front of the player.", FCVAR_CHEAT);
|
||
|
||
#endif // HL2_EPISODIC
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
static void CreateJeep(CBasePlayer *pPlayer)
|
||
{
|
||
// Cheat to create a jeep in front of the player
|
||
Vector vecForward;
|
||
AngleVectors(pPlayer->EyeAngles(), &vecForward);
|
||
CBaseEntity *pJeep = (CBaseEntity *)CreateEntityByName("prop_vehicle_jeep");
|
||
if (pJeep)
|
||
{
|
||
Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector(0, 0, 64);
|
||
QAngle vecAngles(0, pPlayer->GetAbsAngles().y - 90, 0);
|
||
pJeep->SetAbsOrigin(vecOrigin);
|
||
pJeep->SetAbsAngles(vecAngles);
|
||
pJeep->KeyValue("model", "models/buggy.mdl");
|
||
pJeep->KeyValue("solid", "6");
|
||
pJeep->KeyValue("targetname", "jeep");
|
||
pJeep->KeyValue("vehiclescript", "scripts/vehicles/jeep_test.txt");
|
||
DispatchSpawn(pJeep);
|
||
pJeep->Activate();
|
||
pJeep->Teleport(&vecOrigin, &vecAngles, NULL);
|
||
}
|
||
}
|
||
|
||
|
||
void CC_CH_CreateJeep(void)
|
||
{
|
||
CBasePlayer *pPlayer = UTIL_GetCommandClient();
|
||
if (!pPlayer)
|
||
return;
|
||
CreateJeep(pPlayer);
|
||
}
|
||
|
||
static ConCommand ch_createjeep("ch_createjeep", CC_CH_CreateJeep, "Spawn jeep in front of the player.", FCVAR_CHEAT);
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Create an airboat in front of the specified player
|
||
//-----------------------------------------------------------------------------
|
||
static void CreateAirboat(CBasePlayer *pPlayer)
|
||
{
|
||
// Cheat to create a jeep in front of the player
|
||
Vector vecForward;
|
||
AngleVectors(pPlayer->EyeAngles(), &vecForward);
|
||
CBaseEntity *pBoat = (CBaseEntity*)CreateEntityByName("prop_vehicle_airboat");
|
||
if (pBoat)
|
||
{
|
||
Vector vecOrigin = pPlayer->GetAbsOrigin() + vecForward * 256 + Vector(0, 0, 64);
|
||
QAngle vecAngles(0, pPlayer->GetAbsAngles().y - 90, 0);
|
||
pBoat->SetAbsOrigin(vecOrigin);
|
||
pBoat->SetAbsAngles(vecAngles);
|
||
pBoat->KeyValue("model", "models/airboat.mdl");
|
||
pBoat->KeyValue("solid", "6");
|
||
pBoat->KeyValue("targetname", "airboat");
|
||
pBoat->KeyValue("vehiclescript", "scripts/vehicles/airboat.txt");
|
||
DispatchSpawn(pBoat);
|
||
pBoat->Activate();
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CC_CH_CreateAirboat(void)
|
||
{
|
||
CBasePlayer *pPlayer = UTIL_GetCommandClient();
|
||
if (!pPlayer)
|
||
return;
|
||
|
||
CreateAirboat(pPlayer);
|
||
|
||
}
|
||
|
||
static ConCommand ch_createairboat("ch_createairboat", CC_CH_CreateAirboat, "Spawn airboat in front of the player.", FCVAR_CHEAT);
|
||
|
||
|
||
//=========================================================
|
||
//=========================================================
|
||
void CBasePlayer::CheatImpulseCommands(int iImpulse)
|
||
{
|
||
#if !defined( HLDEMO_BUILD )
|
||
if (!sv_cheats->GetBool() || CheatsWasEnabled)
|
||
{
|
||
return;
|
||
}
|
||
|
||
CBaseEntity *pEntity;
|
||
trace_t tr;
|
||
|
||
switch (iImpulse)
|
||
{
|
||
case 76:
|
||
{
|
||
if (!giPrecacheGrunt)
|
||
{
|
||
giPrecacheGrunt = 1;
|
||
Msg("You must now restart to use Grunt-o-matic.\n");
|
||
}
|
||
else
|
||
{
|
||
Vector forward = UTIL_YawToVector(EyeAngles().y);
|
||
Create("NPC_human_grunt", GetLocalOrigin() + forward * 128, GetLocalAngles());
|
||
}
|
||
break;
|
||
}
|
||
|
||
case 81:
|
||
|
||
GiveNamedItem("weapon_cubemap");
|
||
break;
|
||
|
||
case 82:
|
||
// Cheat to create a jeep in front of the player
|
||
CreateJeep(this);
|
||
break;
|
||
|
||
case 83:
|
||
// Cheat to create a airboat in front of the player
|
||
CreateAirboat(this);
|
||
break;
|
||
|
||
case 101:
|
||
gEvilImpulse101 = true;
|
||
|
||
EquipSuit();
|
||
|
||
// Give the player everything!
|
||
/*GiveAmmo( 255, "Pistol");
|
||
GiveAmmo( 255, "AR2");
|
||
GiveAmmo( 5, "AR2AltFire");
|
||
GiveAmmo( 255, "SMG1");
|
||
GiveAmmo( 255, "Buckshot");
|
||
GiveAmmo( 30, "smg1_grenade");
|
||
GiveAmmo( 3, "rpg_round");
|
||
GiveAmmo( 5, "grenade");
|
||
GiveAmmo( 32, "357" );
|
||
GiveAmmo( 16, "XBowBolt" );*/
|
||
|
||
|
||
|
||
GiveAmmo(255, "Pistol");
|
||
GiveAmmo(255, "AlyxGun");
|
||
GiveAmmo(32, "357");
|
||
GiveAmmo(32, "FlareRound");
|
||
GiveAmmo(255, "Laserpistol");
|
||
|
||
GiveAmmo(255, "AR2");
|
||
GiveAmmo(255, "AR3");
|
||
GiveAmmo(255, "AK47");
|
||
GiveAmmo(255, "OICW");
|
||
GiveAmmo(255, "SporeAcid");
|
||
GiveAmmo(5, "AR2AltFire");
|
||
GiveAmmo(255, "SMG1");
|
||
GiveAmmo(3, "smg1_grenade");
|
||
|
||
GiveAmmo(255, "Buckshot");
|
||
GiveAmmo(16, "XBowBolt");
|
||
GiveAmmo(30, "SniperRound");
|
||
GiveAmmo(30, "CombineSniperRound");
|
||
GiveAmmo(3, "rpg_round");
|
||
GiveAmmo(150, "Uranium");
|
||
GiveAmmo(150, "GaussEnergy");
|
||
|
||
GiveAmmo(5, "grenade");
|
||
GiveAmmo(5, "SmokeGrenade");
|
||
GiveAmmo(5, "FlashGrenade");
|
||
GiveAmmo(5, "Hopwire");
|
||
GiveAmmo(5, "Molotov");
|
||
GiveAmmo(5, "Slam");
|
||
GiveAmmo(5, "HopMine");
|
||
GiveAmmo(3, "Tripwire");
|
||
GiveAmmo(3, "CombineCannon");
|
||
GiveAmmo(100, "Extinguisher");
|
||
#ifdef HL2_EPISODIC
|
||
GiveAmmo(5, "Hopwire");
|
||
#endif
|
||
GiveNamedItem("weapon_ar2");
|
||
GiveNamedItem("weapon_smg1");
|
||
GiveNamedItem("weapon_frag");
|
||
GiveNamedItem("weapon_crowbar");
|
||
GiveNamedItem("weapon_pistol");
|
||
GiveNamedItem("weapon_shotgun");
|
||
GiveNamedItem("weapon_physcannon");
|
||
GiveNamedItem("weapon_bugbait");
|
||
GiveNamedItem("weapon_rpg");
|
||
GiveNamedItem("weapon_357");
|
||
GiveNamedItem("weapon_crossbow");
|
||
|
||
|
||
#ifdef HL2_EPISODIC
|
||
// GiveNamedItem( "weapon_magnade" );
|
||
#endif
|
||
if (GetHealth() < 100)
|
||
{
|
||
TakeHealth(25, DMG_GENERIC);
|
||
}
|
||
|
||
gEvilImpulse101 = false;
|
||
|
||
break;
|
||
|
||
case 102:
|
||
// Gibbage!!!
|
||
CGib::SpawnRandomGibs(this, 1, GIB_HUMAN);
|
||
break;
|
||
|
||
case 103:
|
||
// What the hell are you doing?
|
||
pEntity = FindEntityForward(this, true);
|
||
if (pEntity)
|
||
{
|
||
CAI_BaseNPC *pNPC = pEntity->MyNPCPointer();
|
||
if (pNPC)
|
||
pNPC->ReportAIState();
|
||
}
|
||
break;
|
||
|
||
case 106:
|
||
// Give me the classname and targetname of this entity.
|
||
pEntity = FindEntityForward(this, true);
|
||
if (pEntity)
|
||
{
|
||
Msg("Classname: %s", pEntity->GetClassname());
|
||
|
||
if (pEntity->GetEntityName() != NULL_STRING)
|
||
{
|
||
Msg(" - Name: %s\n", STRING(pEntity->GetEntityName()));
|
||
}
|
||
else
|
||
{
|
||
Msg(" - Name: No Targetname\n");
|
||
}
|
||
|
||
if (pEntity->m_iParent != NULL_STRING)
|
||
Msg("Parent: %s\n", STRING(pEntity->m_iParent));
|
||
|
||
Msg("Model: %s\n", STRING(pEntity->GetModelName()));
|
||
if (pEntity->m_iGlobalname != NULL_STRING)
|
||
Msg("Globalname: %s\n", STRING(pEntity->m_iGlobalname));
|
||
}
|
||
break;
|
||
|
||
case 107:
|
||
{
|
||
trace_t tr;
|
||
|
||
edict_t *pWorld = engine->PEntityOfEntIndex(0);
|
||
|
||
Vector start = EyePosition();
|
||
Vector forward;
|
||
EyeVectors(&forward);
|
||
Vector end = start + forward * 1024;
|
||
UTIL_TraceLine(start, end, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
|
||
if (tr.m_pEnt)
|
||
pWorld = tr.m_pEnt->edict();
|
||
|
||
const char *pTextureName = tr.surface.name;
|
||
|
||
if (pTextureName)
|
||
Msg("Texture: %s\n", pTextureName);
|
||
}
|
||
break;
|
||
|
||
//
|
||
// Sets the debug NPC to be the NPC under the crosshair.
|
||
//
|
||
case 108:
|
||
{
|
||
pEntity = FindEntityForward(this, true);
|
||
if (pEntity)
|
||
{
|
||
CAI_BaseNPC *pNPC = pEntity->MyNPCPointer();
|
||
if (pNPC != NULL)
|
||
{
|
||
Msg("Debugging %s (0x%p)\n", pNPC->GetClassname(), pNPC);
|
||
CAI_BaseNPC::SetDebugNPC(pNPC);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
|
||
case 111: //====== OVERCHARGED - 28 jan 2022 update
|
||
gEvilImpulse101 = true;
|
||
|
||
EquipSuit();
|
||
|
||
//===========AMMO==============
|
||
GiveAmmo(255, "Pistol");
|
||
GiveAmmo(255, "AlyxGun");
|
||
GiveAmmo(32, "357");
|
||
GiveAmmo(32, "FlareRound");
|
||
GiveAmmo(255, "Laserpistol");
|
||
GiveAmmo(255, "AR2");
|
||
GiveAmmo(255, "AR3");
|
||
GiveAmmo(255, "AK47");
|
||
GiveAmmo(255, "OICW");
|
||
GiveAmmo(5, "AR2AltFire");
|
||
GiveAmmo(255, "SMG1");
|
||
GiveAmmo(3, "smg1_grenade");
|
||
|
||
GiveAmmo(255, "Buckshot");
|
||
GiveAmmo(16, "XBowBolt");
|
||
GiveAmmo(30, "SniperRound");
|
||
GiveAmmo(30, "CombineSniperRound");
|
||
GiveAmmo(3, "rpg_round");
|
||
GiveAmmo(150, "Uranium");
|
||
|
||
GiveAmmo(5, "grenade");
|
||
GiveAmmo(5, "Hopwire");
|
||
GiveAmmo(3, "Tripwire");
|
||
GiveAmmo(5, "SmokeGrenade");
|
||
GiveAmmo(5, "FlashGrenade");
|
||
GiveAmmo(5, "Molotov");
|
||
GiveAmmo(5, "Slam");
|
||
GiveAmmo(5, "HopMine");
|
||
|
||
GiveAmmo(3, "CombineCannon");
|
||
GiveAmmo(100, "Extinguisher");
|
||
|
||
GiveNamedItem("item_battery"); // Like in HL1, 1 more battery
|
||
|
||
//===========MELEE==============
|
||
//GiveNamedItem( "weapon_crowbar" );
|
||
GiveNamedItem("weapon_iceaxe");
|
||
GiveNamedItem("weapon_wrench");
|
||
GiveNamedItem("weapon_stunbaton");
|
||
GiveNamedItem("weapon_knife");
|
||
//===========PISTOLS==============
|
||
//GiveNamedItem( "weapon_pistol" );
|
||
GiveNamedItem("weapon_glock");
|
||
GiveNamedItem("weapon_beretta");
|
||
GiveNamedItem("weapon_usp");
|
||
GiveNamedItem("weapon_dual_pistols");
|
||
GiveNamedItem("weapon_alyxgun");
|
||
//GiveNamedItem( "weapon_357" );
|
||
GiveNamedItem("weapon_flaregun");
|
||
GiveNamedItem("weapon_deagle");
|
||
//===========DETACHABLE==============
|
||
GiveNamedItem("weapon_airboatgun");
|
||
GiveNamedItem("weapon_ar3");
|
||
//===========RIFLE==============
|
||
//GiveNamedItem( "weapon_smg1" );
|
||
GiveNamedItem("weapon_mp5");
|
||
GiveNamedItem("weapon_ak47");
|
||
GiveNamedItem("weapon_m4");
|
||
GiveNamedItem("weapon_m16");
|
||
GiveNamedItem("weapon_sg552");
|
||
GiveNamedItem("weapon_oicw");
|
||
GiveNamedItem("weapon_smg2");
|
||
GiveNamedItem("weapon_vector");
|
||
//GiveNamedItem( "weapon_ar2" );
|
||
//===========SHOTGUNS==============
|
||
//GiveNamedItem( "weapon_shotgun" );
|
||
GiveNamedItem("weapon_autoshotgun");
|
||
GiveNamedItem("weapon_annabelle");
|
||
//===========HEAVY==============
|
||
//GiveNamedItem( "weapon_rpg" );
|
||
GiveNamedItem("weapon_grenadelauncher");
|
||
GiveNamedItem("weapon_ionrifle");
|
||
GiveNamedItem("weapon_machinegun");
|
||
//===========SNIPER==============
|
||
//GiveNamedItem( "weapon_crossbow" );
|
||
GiveNamedItem("weapon_barnacle");
|
||
GiveNamedItem("weapon_combinesniper");
|
||
GiveNamedItem("weapon_sniper_m40a1");
|
||
GiveNamedItem("weapon_sniper");
|
||
//===========THROW==============
|
||
//GiveNamedItem( "weapon_bugbait" );
|
||
//GiveNamedItem( "weapon_frag" );
|
||
GiveNamedItem("weapon_hopwire");
|
||
GiveNamedItem("weapon_tripwire");
|
||
GiveNamedItem("weapon_smokegrenade");
|
||
GiveNamedItem("weapon_flashbang");
|
||
GiveNamedItem("weapon_slam");
|
||
GiveNamedItem("weapon_hopmine");
|
||
GiveNamedItem("weapon_molotov");
|
||
GiveNamedItem("weapon_snark");
|
||
//===========OTHER==============
|
||
//GiveNamedItem("weapon_adrenaline");
|
||
GiveNamedItem("weapon_gauss");
|
||
GiveNamedItem("weapon_tau");
|
||
//GiveNamedItem("weapon_gauss_overhaul"); // custom 3 firemodes gauss
|
||
GiveNamedItem("weapon_egon");
|
||
GiveNamedItem("weapon_displacer");
|
||
GiveNamedItem("weapon_immolator");
|
||
GiveNamedItem("weapon_cguard");
|
||
//GiveNamedItem( "weapon_physcannon" );
|
||
GiveNamedItem("weapon_physgun");
|
||
GiveNamedItem("weapon_shockrifle");
|
||
GiveNamedItem("weapon_spore_launcher");
|
||
GiveNamedItem("weapon_hornetgun");
|
||
GiveNamedItem("weapon_extinguisher");
|
||
GiveNamedItem("weapon_flamethrower");
|
||
GiveNamedItem("weapon_laser");
|
||
|
||
if (GetHealth() < 100)
|
||
{
|
||
TakeHealth(25, DMG_GENERIC);
|
||
}
|
||
|
||
gEvilImpulse101 = false;
|
||
|
||
break; //=========== End 111
|
||
|
||
case 112: //====== BJ: 112 for template weapons
|
||
gEvilImpulse101 = true;
|
||
|
||
EquipSuit();
|
||
|
||
GiveNamedItem("item_battery");
|
||
|
||
GiveNamedItem("weapon_citizensuitcase"); // Useable props
|
||
GiveNamedItem("weapon_citizenpackage");
|
||
GiveNamedItem("weapon_oldmanharpoon");
|
||
GiveNamedItem("weapon_objective");
|
||
|
||
GiveNamedItem("weapon_thumper"); // BJ: moved test-gameplay items here
|
||
GiveNamedItem("weapon_teleport");
|
||
GiveNamedItem("weapon_binoculars");
|
||
|
||
if (GetHealth() < 100)
|
||
{
|
||
TakeHealth(25, DMG_GENERIC);
|
||
}
|
||
|
||
gEvilImpulse101 = false;
|
||
|
||
break;
|
||
//=========== OVERCHARGED
|
||
|
||
case 195:// show shortest paths for entire level to nearest node
|
||
{
|
||
Create("node_viewer_fly", GetLocalOrigin(), GetLocalAngles());
|
||
}
|
||
break;
|
||
case 196:// show shortest paths for entire level to nearest node
|
||
{
|
||
Create("node_viewer_large", GetLocalOrigin(), GetLocalAngles());
|
||
}
|
||
break;
|
||
case 197:// show shortest paths for entire level to nearest node
|
||
{
|
||
Create("node_viewer_human", GetLocalOrigin(), GetLocalAngles());
|
||
}
|
||
break;
|
||
case 202:// Random blood splatter
|
||
{
|
||
Vector forward;
|
||
EyeVectors(&forward);
|
||
UTIL_TraceLine(EyePosition(),
|
||
EyePosition() + forward * 128,
|
||
MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
|
||
|
||
if (tr.fraction != 1.0)
|
||
{// line hit something, so paint a decal
|
||
CBloodSplat *pBlood = CREATE_UNSAVED_ENTITY(CBloodSplat, "bloodsplat");
|
||
pBlood->Spawn(this);
|
||
}
|
||
}
|
||
break;
|
||
case 203:// remove creature.
|
||
pEntity = FindEntityForward(this, true);
|
||
if (pEntity)
|
||
{
|
||
UTIL_Remove(pEntity);
|
||
// if ( pEntity->m_takedamage )
|
||
// pEntity->SetThink(SUB_Remove);
|
||
}
|
||
break;
|
||
}
|
||
#endif // HLDEMO_BUILD
|
||
}
|
||
|
||
|
||
bool CBasePlayer::ClientCommand(const CCommand &args)
|
||
{
|
||
const char *cmd = args[0];
|
||
#ifdef _DEBUG
|
||
if (stricmp(cmd, "test_SmokeGrenade") == 0)
|
||
{
|
||
if (sv_cheats && sv_cheats->GetBool())
|
||
{
|
||
ParticleSmokeGrenade *pSmoke = dynamic_cast<ParticleSmokeGrenade*>(CreateEntityByName(PARTICLESMOKEGRENADE_ENTITYNAME));
|
||
if (pSmoke)
|
||
{
|
||
Vector vForward;
|
||
AngleVectors(GetLocalAngles(), &vForward);
|
||
vForward.z = 0;
|
||
VectorNormalize(vForward);
|
||
|
||
pSmoke->SetLocalOrigin(GetLocalOrigin() + vForward * 100);
|
||
pSmoke->SetFadeTime(25, 30); // Fade out between 25 seconds and 30 seconds.
|
||
pSmoke->Activate();
|
||
pSmoke->SetLifetime(30);
|
||
pSmoke->FillVolume();
|
||
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
#endif // _DEBUG
|
||
/*if (stricmp(cmd, "MuzzleVectors") == 0)
|
||
{
|
||
CBaseCombatWeapon *pWeapon = this->GetActiveWeapon();
|
||
if (pWeapon)
|
||
{
|
||
auto arguments = args;
|
||
|
||
Vector trVect = Vector(atof(arguments[1]), atof(arguments[2]), atof(arguments[3]));
|
||
Vector muzVect = Vector(atof(arguments[4]), atof(arguments[5]), atof(arguments[6]));
|
||
|
||
pWeapon->SetClientVectors(trVect, muzVect);
|
||
arguments.Reset();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
if (stricmp(cmd, "MuzzleAngles") == 0)
|
||
{
|
||
CBaseCombatWeapon *pWeapon = this->GetActiveWeapon();
|
||
if (pWeapon)
|
||
{
|
||
auto arguments = args;
|
||
|
||
QAngle muzAngle = QAngle(atof(arguments[1]), atof(arguments[2]), atof(arguments[3]));
|
||
|
||
pWeapon->SetClientAngles(muzAngle);
|
||
}
|
||
|
||
return true;
|
||
}*/
|
||
if (stricmp(cmd, "vehicleRole") == 0)
|
||
{
|
||
// Get the vehicle role value.
|
||
if (args.ArgC() == 2)
|
||
{
|
||
// Check to see if a player is in a vehicle.
|
||
if (IsInAVehicle())
|
||
{
|
||
int nRole = atoi(args[1]);
|
||
IServerVehicle *pVehicle = GetVehicle();
|
||
if (pVehicle)
|
||
{
|
||
// Only switch roles if role is empty!
|
||
if (!pVehicle->GetPassenger(nRole))
|
||
{
|
||
LeaveVehicle();
|
||
GetInVehicle(pVehicle, nRole);
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
else if (HandleVoteCommands(args))
|
||
{
|
||
return true;
|
||
}
|
||
else if (stricmp(cmd, "spectate") == 0) // join spectator team & start observer mode
|
||
{
|
||
if (GetTeamNumber() == TEAM_SPECTATOR)
|
||
return true;
|
||
|
||
ConVarRef mp_allowspectators("mp_allowspectators");
|
||
if (mp_allowspectators.IsValid())
|
||
{
|
||
if ((mp_allowspectators.GetBool() == false) && !IsHLTV() && !IsReplay())
|
||
{
|
||
ClientPrint(this, HUD_PRINTCENTER, "#Cannot_Be_Spectator");
|
||
return true;
|
||
}
|
||
}
|
||
|
||
if (!IsDead())
|
||
{
|
||
CommitSuicide(); // kill player
|
||
}
|
||
|
||
RemoveAllItems(true);
|
||
|
||
ChangeTeam(TEAM_SPECTATOR);
|
||
|
||
StartObserverMode(OBS_MODE_ROAMING);
|
||
return true;
|
||
}
|
||
else if (stricmp(cmd, "spec_mode") == 0) // new observer mode
|
||
{
|
||
int mode;
|
||
|
||
if (GetObserverMode() == OBS_MODE_FREEZECAM)
|
||
{
|
||
AttemptToExitFreezeCam();
|
||
return true;
|
||
}
|
||
|
||
// not allowed to change spectator modes when mp_fadetoblack is being used
|
||
if (mp_fadetoblack.GetBool())
|
||
{
|
||
if (GetTeamNumber() > TEAM_SPECTATOR)
|
||
return true;
|
||
}
|
||
|
||
// check for parameters.
|
||
if (args.ArgC() >= 2)
|
||
{
|
||
mode = atoi(args[1]);
|
||
|
||
if (mode < OBS_MODE_IN_EYE || mode > LAST_PLAYER_OBSERVERMODE)
|
||
mode = OBS_MODE_IN_EYE;
|
||
}
|
||
else
|
||
{
|
||
// switch to next spec mode if no parameter given
|
||
mode = GetObserverMode() + 1;
|
||
|
||
if (mode > LAST_PLAYER_OBSERVERMODE)
|
||
{
|
||
mode = OBS_MODE_IN_EYE;
|
||
}
|
||
else if (mode < OBS_MODE_IN_EYE)
|
||
{
|
||
mode = OBS_MODE_ROAMING;
|
||
}
|
||
|
||
}
|
||
|
||
// don't allow input while player or death cam animation
|
||
if (GetObserverMode() > OBS_MODE_DEATHCAM)
|
||
{
|
||
// set new spectator mode, don't allow OBS_MODE_NONE
|
||
if (!SetObserverMode(mode))
|
||
ClientPrint(this, HUD_PRINTCONSOLE, "#Spectator_Mode_Unkown");
|
||
else
|
||
engine->ClientCommand(edict(), "cl_spec_mode %d", mode);
|
||
}
|
||
else
|
||
{
|
||
// remember spectator mode for later use
|
||
m_iObserverLastMode = mode;
|
||
engine->ClientCommand(edict(), "cl_spec_mode %d", mode);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
else if (stricmp(cmd, "spec_next") == 0) // chase next player
|
||
{
|
||
if (GetObserverMode() > OBS_MODE_FIXED)
|
||
{
|
||
// set new spectator mode
|
||
CBaseEntity * target = FindNextObserverTarget(false);
|
||
if (target)
|
||
{
|
||
SetObserverTarget(target);
|
||
}
|
||
}
|
||
else if (GetObserverMode() == OBS_MODE_FREEZECAM)
|
||
{
|
||
AttemptToExitFreezeCam();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
else if (stricmp(cmd, "spec_prev") == 0) // chase prevoius player
|
||
{
|
||
if (GetObserverMode() > OBS_MODE_FIXED)
|
||
{
|
||
// set new spectator mode
|
||
CBaseEntity * target = FindNextObserverTarget(true);
|
||
if (target)
|
||
{
|
||
SetObserverTarget(target);
|
||
}
|
||
}
|
||
else if (GetObserverMode() == OBS_MODE_FREEZECAM)
|
||
{
|
||
AttemptToExitFreezeCam();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
else if (stricmp(cmd, "spec_player") == 0) // chase next player
|
||
{
|
||
if (GetObserverMode() > OBS_MODE_FIXED && args.ArgC() == 2)
|
||
{
|
||
int index = atoi(args[1]);
|
||
|
||
CBasePlayer * target;
|
||
|
||
if (index == 0)
|
||
{
|
||
target = UTIL_PlayerByName(args[1]);
|
||
}
|
||
else
|
||
{
|
||
target = UTIL_PlayerByIndex(index);
|
||
}
|
||
|
||
if (IsValidObserverTarget(target))
|
||
{
|
||
SetObserverTarget(target);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
else if (stricmp(cmd, "spec_goto") == 0) // chase next player
|
||
{
|
||
if ((GetObserverMode() == OBS_MODE_FIXED ||
|
||
GetObserverMode() == OBS_MODE_ROAMING) &&
|
||
args.ArgC() == 6)
|
||
{
|
||
Vector origin;
|
||
origin.x = atof(args[1]);
|
||
origin.y = atof(args[2]);
|
||
origin.z = atof(args[3]);
|
||
|
||
QAngle angle;
|
||
angle.x = atof(args[4]);
|
||
angle.y = atof(args[5]);
|
||
angle.z = 0.0f;
|
||
|
||
JumptoPosition(origin, angle);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
else if (stricmp(cmd, "playerperf") == 0)
|
||
{
|
||
int nRecip = entindex();
|
||
if (args.ArgC() >= 2)
|
||
{
|
||
nRecip = clamp(Q_atoi(args.Arg(1)), 1, gpGlobals->maxClients);
|
||
}
|
||
int nRecords = -1; // all
|
||
if (args.ArgC() >= 3)
|
||
{
|
||
nRecords = MAX(Q_atoi(args.Arg(2)), 1);
|
||
}
|
||
|
||
CBasePlayer *pl = UTIL_PlayerByIndex(nRecip);
|
||
if (pl)
|
||
{
|
||
pl->DumpPerfToRecipient(this, nRecords);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
extern bool UTIL_ItemCanBeTouchedByPlayer(CBaseEntity *pItem, CBasePlayer *pPlayer);
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Player reacts to bumping a weapon.
|
||
// Input : pWeapon - the weapon that the player bumped into.
|
||
// Output : Returns true if player picked up the weapon
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::BumpWeapon(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
CBaseCombatCharacter *pOwner = pWeapon->GetOwner();
|
||
|
||
// Can I have this weapon type?
|
||
if (!IsAllowedToPickupWeapons())
|
||
return false;
|
||
|
||
if (pWeapon && !pWeapon->Pickable)
|
||
return false;
|
||
|
||
pWeapon->EnableHoldingFire(false);
|
||
|
||
if (pOwner || !Weapon_CanUse(pWeapon) || !g_pGameRules->CanHavePlayerItem(this, pWeapon))
|
||
{
|
||
if (gEvilImpulse101)
|
||
{
|
||
UTIL_Remove(pWeapon);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// Act differently in the episodes
|
||
if (hl2_episodic.GetBool())
|
||
{
|
||
// Don't let the player touch the item unless unobstructed
|
||
if (!UTIL_ItemCanBeTouchedByPlayer(pWeapon, this) && !gEvilImpulse101)
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
// Don't let the player fetch weapons through walls (use MASK_SOLID so that you can't pickup through windows)
|
||
if (pWeapon->FVisible(this, MASK_SOLID) == false && !(GetFlags() & FL_NOTARGET))
|
||
return false;
|
||
}
|
||
|
||
// ----------------------------------------
|
||
// If I already have it just take the ammo
|
||
// ----------------------------------------
|
||
if (Weapon_OwnsThisType(pWeapon->GetClassname(), pWeapon->GetSubType()))
|
||
{
|
||
//AddGrenadeToSlot(pWeapon);
|
||
if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt())
|
||
UpdateGrenadeInfo();
|
||
|
||
if (Weapon_EquipAmmoOnly(pWeapon))
|
||
{
|
||
// Only remove me if I have no ammo left
|
||
if (pWeapon->HasPrimaryAmmo())
|
||
return false;
|
||
|
||
UTIL_Remove(pWeapon);
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
// -------------------------
|
||
// Otherwise take the weapon
|
||
// -------------------------
|
||
else
|
||
{
|
||
//Weapons bucket check here:
|
||
if (!Owner_HasFreeSlots(pWeapon))
|
||
return false;
|
||
|
||
pWeapon->CheckRespawn();
|
||
|
||
pWeapon->AddSolidFlags(FSOLID_NOT_SOLID);
|
||
pWeapon->AddEffects(EF_NODRAW);
|
||
|
||
Weapon_Equip(pWeapon);
|
||
if (IsInAVehicle())
|
||
{
|
||
pWeapon->Holster();
|
||
}
|
||
else
|
||
{
|
||
#ifdef HL2_DLL
|
||
|
||
if (IsX360())
|
||
{
|
||
CFmtStr hint;
|
||
hint.sprintf("#valve_hint_select_%s", pWeapon->GetClassname());
|
||
UTIL_HudHintText(this, hint.Access());
|
||
}
|
||
|
||
// Always switch to a newly-picked up weapon
|
||
if (!PlayerHasMegaPhysCannon())
|
||
{
|
||
// If it uses clips, load it full. (this is the first time you've picked up this type of weapon)
|
||
if (pWeapon->UsesClipsForAmmo1())
|
||
{
|
||
if (!pWeapon->HasSpawnFlags(FL_GRAPHED))
|
||
pWeapon->m_iClip1 = pWeapon->GetMaxClip1();
|
||
}
|
||
|
||
Weapon_Switch(pWeapon);
|
||
}
|
||
#endif
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
|
||
bool CBasePlayer::RemovePlayerItem(CBaseCombatWeapon *pItem)
|
||
{
|
||
if (GetActiveWeapon() == pItem)
|
||
{
|
||
ResetAutoaim();
|
||
pItem->Holster();
|
||
pItem->SetNextThink(TICK_NEVER_THINK); // crowbar may be trying to swing again, etc
|
||
pItem->SetThink(NULL);
|
||
}
|
||
|
||
if (m_hLastWeapon.Get() == pItem)
|
||
{
|
||
Weapon_SetLast(NULL);
|
||
}
|
||
|
||
return Weapon_Detach(pItem);
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Hides or shows the player's view model. The "r_drawviewmodel" cvar
|
||
// can still hide the viewmodel even if this is set to true.
|
||
// Input : bShow - true to show, false to hide the view model.
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ShowViewModel(bool bShow)
|
||
{
|
||
m_Local.m_bDrawViewmodel = bShow;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : bDraw -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ShowCrosshair(bool bShow)
|
||
{
|
||
if (bShow)
|
||
{
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_CROSSHAIR;
|
||
}
|
||
else
|
||
{
|
||
m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
QAngle CBasePlayer::BodyAngles()
|
||
{
|
||
return EyeAngles();
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Purpose : Add noise to BodyTarget() to give enemy a better chance of
|
||
// getting a clear shot when the player is peeking above a hole
|
||
// or behind a ladder (eventually the randomly-picked point
|
||
// along the spine will be one that is exposed above the hole or
|
||
// between rungs of a ladder.)
|
||
// Input :
|
||
// Output :
|
||
//------------------------------------------------------------------------------
|
||
Vector CBasePlayer::BodyTarget(const Vector &posSrc, bool bNoisy)
|
||
{
|
||
if (IsInAVehicle())
|
||
{
|
||
return GetVehicle()->GetVehicleEnt()->BodyTarget(posSrc, bNoisy);
|
||
}
|
||
if (bNoisy)
|
||
{
|
||
return GetAbsOrigin() + (GetViewOffset() * random->RandomFloat(0.7, 1.0));
|
||
}
|
||
else
|
||
{
|
||
return EyePosition();
|
||
}
|
||
};
|
||
|
||
/*
|
||
=========================================================
|
||
UpdateClientData
|
||
|
||
resends any changed player HUD info to the client.
|
||
Called every frame by PlayerPreThink
|
||
Also called at start of demo recording and playback by
|
||
ForceClientDllUpdate to ensure the demo gets messages
|
||
reflecting all of the HUD state info.
|
||
=========================================================
|
||
*/
|
||
void CBasePlayer::UpdateClientData(void)
|
||
{
|
||
CSingleUserRecipientFilter user(this);
|
||
user.MakeReliable();
|
||
|
||
if (m_fInitHUD)
|
||
{
|
||
m_fInitHUD = false;
|
||
gInitHUD = false;
|
||
|
||
UserMessageBegin(user, "ResetHUD");
|
||
WRITE_BYTE(0);
|
||
MessageEnd();
|
||
|
||
if (!m_fGameHUDInitialized)
|
||
{
|
||
g_pGameRules->InitHUD(this);
|
||
InitHUD();
|
||
m_fGameHUDInitialized = true;
|
||
if (g_pGameRules->IsMultiplayer())
|
||
{
|
||
variant_t value;
|
||
g_EventQueue.AddEvent("game_player_manager", "OnPlayerJoin", value, 0, this, this);
|
||
}
|
||
}
|
||
|
||
variant_t value;
|
||
g_EventQueue.AddEvent("game_player_manager", "OnPlayerSpawn", value, 0, this, this);
|
||
}
|
||
|
||
// HACKHACK -- send the message to display the game title
|
||
CWorld *world = GetWorldEntity();
|
||
if (world && world->GetDisplayTitle())
|
||
{
|
||
UserMessageBegin(user, "GameTitle");
|
||
MessageEnd();
|
||
world->SetDisplayTitle(false);
|
||
}
|
||
|
||
if (m_ArmorValue != m_iClientBattery)
|
||
{
|
||
m_iClientBattery = m_ArmorValue;
|
||
|
||
// send "battery" update message
|
||
if (usermessages->LookupUserMessage("Battery") != -1)
|
||
{
|
||
UserMessageBegin(user, "Battery");
|
||
WRITE_SHORT((int)m_ArmorValue);
|
||
MessageEnd();
|
||
}
|
||
}
|
||
|
||
#if 0 // BYE BYE!!
|
||
// Update Flashlight
|
||
if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->curtime))
|
||
{
|
||
if (FlashlightIsOn())
|
||
{
|
||
if (m_iFlashBattery)
|
||
{
|
||
m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->curtime;
|
||
m_iFlashBattery--;
|
||
|
||
if (!m_iFlashBattery)
|
||
FlashlightTurnOff();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_iFlashBattery < 100)
|
||
{
|
||
m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->curtime;
|
||
m_iFlashBattery++;
|
||
}
|
||
else
|
||
m_flFlashLightTime = 0;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
CheckTrainUpdate();
|
||
|
||
// Update all the items
|
||
for (int i = 0; i < WeaponCount(); i++)
|
||
{
|
||
if (GetWeapon(i)) // each item updates it's successors
|
||
GetWeapon(i)->UpdateClientData(this);
|
||
}
|
||
|
||
// update the client with our poison state
|
||
m_Local.m_bPoisoned = (m_bitsDamageType & DMG_POISON)
|
||
&& (m_nPoisonDmg > m_nPoisonRestored)
|
||
&& (m_iHealth < 100);
|
||
|
||
// Check if the bonus progress HUD element should be displayed
|
||
if (m_iBonusChallenge == 0 && m_iBonusProgress == 0 && !(m_Local.m_iHideHUD & HIDEHUD_BONUS_PROGRESS))
|
||
m_Local.m_iHideHUD |= HIDEHUD_BONUS_PROGRESS;
|
||
if ((m_iBonusChallenge != 0) && (m_Local.m_iHideHUD & HIDEHUD_BONUS_PROGRESS))
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_BONUS_PROGRESS;
|
||
|
||
// Let any global rules update the HUD, too
|
||
g_pGameRules->UpdateClientData(this);
|
||
}
|
||
|
||
void CBasePlayer::RumbleEffect(unsigned char index, unsigned char rumbleData, unsigned char rumbleFlags)
|
||
{
|
||
if (!IsAlive())
|
||
return;
|
||
|
||
CSingleUserRecipientFilter filter(this);
|
||
filter.MakeReliable();
|
||
|
||
UserMessageBegin(filter, "Rumble");
|
||
WRITE_BYTE(index);
|
||
WRITE_BYTE(rumbleData);
|
||
WRITE_BYTE(rumbleFlags);
|
||
MessageEnd();
|
||
}
|
||
|
||
void CBasePlayer::EnableControl(bool fControl)
|
||
{
|
||
if (!fControl)
|
||
AddFlag(FL_FROZEN);
|
||
else
|
||
RemoveFlag(FL_FROZEN);
|
||
|
||
}
|
||
|
||
void CBasePlayer::CheckTrainUpdate(void)
|
||
{
|
||
if ((m_iTrain & TRAIN_NEW))
|
||
{
|
||
CSingleUserRecipientFilter user(this);
|
||
user.MakeReliable();
|
||
|
||
// send "Train" update message
|
||
UserMessageBegin(user, "Train");
|
||
WRITE_BYTE(m_iTrain & 0xF);
|
||
MessageEnd();
|
||
|
||
m_iTrain &= ~TRAIN_NEW;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Returns whether the player should autoaim or not
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::ShouldAutoaim(void)
|
||
{
|
||
// cannot be in multiplayer
|
||
if (gpGlobals->maxClients > 1)
|
||
return false;
|
||
|
||
// autoaiming is only for easy and medium skill
|
||
return (IsX360() || !g_pGameRules->IsSkillLevel(SKILL_HARD));
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
Vector CBasePlayer::GetAutoaimVector(float flScale)
|
||
{
|
||
autoaim_params_t params;
|
||
|
||
params.m_fScale = flScale;
|
||
params.m_fMaxDist = autoaim_max_dist.GetFloat();
|
||
|
||
GetAutoaimVector(params);
|
||
return params.m_vecAutoAimDir;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
Vector CBasePlayer::GetAutoaimVector(float flScale, float flMaxDist)
|
||
{
|
||
autoaim_params_t params;
|
||
|
||
params.m_fScale = flScale;
|
||
params.m_fMaxDist = flMaxDist;
|
||
|
||
GetAutoaimVector(params);
|
||
return params.m_vecAutoAimDir;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::GetAutoaimVector(autoaim_params_t ¶ms)
|
||
{
|
||
// Assume autoaim will not be assisting.
|
||
params.m_bAutoAimAssisting = false;
|
||
|
||
if ((ShouldAutoaim() == false) || (params.m_fScale == AUTOAIM_SCALE_DIRECT_ONLY))
|
||
{
|
||
Vector forward;
|
||
AngleVectors(EyeAngles() + m_Local.m_vecPunchAngle, &forward);
|
||
|
||
params.m_vecAutoAimDir = forward;
|
||
params.m_hAutoAimEntity.Set(NULL);
|
||
params.m_vecAutoAimPoint = vec3_invalid;
|
||
params.m_bAutoAimAssisting = false;
|
||
return;
|
||
}
|
||
|
||
Vector vecSrc = Weapon_ShootPosition();
|
||
|
||
m_vecAutoAim.Init(0.0f, 0.0f, 0.0f);
|
||
|
||
QAngle angles = AutoaimDeflection(vecSrc, params);
|
||
|
||
// update ontarget if changed
|
||
if (!g_pGameRules->AllowAutoTargetCrosshair())
|
||
m_fOnTarget = false;
|
||
|
||
if (angles.x > 180)
|
||
angles.x -= 360;
|
||
if (angles.x < -180)
|
||
angles.x += 360;
|
||
if (angles.y > 180)
|
||
angles.y -= 360;
|
||
if (angles.y < -180)
|
||
angles.y += 360;
|
||
|
||
if (angles.x > 25)
|
||
angles.x = 25;
|
||
if (angles.x < -25)
|
||
angles.x = -25;
|
||
if (angles.y > 12)
|
||
angles.y = 12;
|
||
if (angles.y < -12)
|
||
angles.y = -12;
|
||
|
||
Vector forward;
|
||
|
||
if (IsInAVehicle() && g_pGameRules->GetAutoAimMode() == AUTOAIM_ON_CONSOLE)
|
||
{
|
||
m_vecAutoAim = angles;
|
||
AngleVectors(EyeAngles() + m_vecAutoAim, &forward);
|
||
}
|
||
else
|
||
{
|
||
// always use non-sticky autoaim
|
||
m_vecAutoAim = angles * 0.9f;
|
||
AngleVectors(EyeAngles() + m_Local.m_vecPunchAngle + m_vecAutoAim, &forward);
|
||
}
|
||
|
||
params.m_vecAutoAimDir = forward;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Targets represent themselves to autoaim as a viewplane-parallel disc with
|
||
// a radius specified by the target. The player then modifies this radius
|
||
// to achieve more or less aggressive aiming assistance
|
||
//-----------------------------------------------------------------------------
|
||
float CBasePlayer::GetAutoaimScore(const Vector &eyePosition, const Vector &viewDir, const Vector &vecTarget, CBaseEntity *pTarget, float fScale, CBaseCombatWeapon *pActiveWeapon)
|
||
{
|
||
float radiusSqr;
|
||
float targetRadius = pTarget->GetAutoAimRadius() * fScale;
|
||
|
||
if (pActiveWeapon != NULL)
|
||
targetRadius *= pActiveWeapon->WeaponAutoAimScale();
|
||
|
||
float targetRadiusSqr = Square(targetRadius);
|
||
|
||
Vector vecNearestPoint = PointOnLineNearestPoint(eyePosition, eyePosition + viewDir * 8192, vecTarget);
|
||
Vector vecDiff = vecTarget - vecNearestPoint;
|
||
|
||
radiusSqr = vecDiff.LengthSqr();
|
||
|
||
if (radiusSqr <= targetRadiusSqr)
|
||
{
|
||
float score;
|
||
|
||
score = 1.0f - (radiusSqr / targetRadiusSqr);
|
||
|
||
Assert(score >= 0.0f && score <= 1.0f);
|
||
return score;
|
||
}
|
||
|
||
// 0 means no score- doesn't qualify for autoaim.
|
||
return 0.0f;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &vecSrc -
|
||
// flDist -
|
||
// flDelta -
|
||
// Output : Vector
|
||
//-----------------------------------------------------------------------------
|
||
QAngle CBasePlayer::AutoaimDeflection(Vector &vecSrc, autoaim_params_t ¶ms)
|
||
{
|
||
float bestscore;
|
||
float score;
|
||
QAngle eyeAngles;
|
||
Vector bestdir;
|
||
CBaseEntity *bestent;
|
||
trace_t tr;
|
||
Vector v_forward, v_right, v_up;
|
||
|
||
if (ShouldAutoaim() == false)
|
||
{
|
||
m_fOnTarget = false;
|
||
return vec3_angle;
|
||
}
|
||
|
||
eyeAngles = EyeAngles();
|
||
AngleVectors(eyeAngles + m_Local.m_vecPunchAngle + m_vecAutoAim, &v_forward, &v_right, &v_up);
|
||
|
||
// try all possible entities
|
||
bestdir = v_forward;
|
||
bestscore = 0.0f;
|
||
bestent = NULL;
|
||
|
||
//Reset this data
|
||
m_fOnTarget = false;
|
||
params.m_bOnTargetNatural = false;
|
||
|
||
CBaseEntity *pIgnore = NULL;
|
||
|
||
if (IsInAVehicle())
|
||
{
|
||
pIgnore = GetVehicleEntity();
|
||
}
|
||
|
||
CTraceFilterSkipTwoEntities traceFilter(this, pIgnore, COLLISION_GROUP_NONE);
|
||
|
||
UTIL_TraceLine(vecSrc, vecSrc + bestdir * MAX_COORD_FLOAT, MASK_SHOT, &traceFilter, &tr);
|
||
|
||
CBaseEntity *pEntHit = tr.m_pEnt;
|
||
|
||
if (pEntHit && pEntHit->m_takedamage != DAMAGE_NO && pEntHit->GetHealth() > 0)
|
||
{
|
||
// don't look through water
|
||
if (!((GetWaterLevel() != 3 && pEntHit->GetWaterLevel() == 3) || (GetWaterLevel() == 3 && pEntHit->GetWaterLevel() == 0)))
|
||
{
|
||
if (pEntHit->ShouldAttractAutoAim(this))
|
||
{
|
||
bool bAimAtThis = true;
|
||
|
||
if (pEntHit->IsNPC() && g_pGameRules->GetAutoAimMode() > AUTOAIM_NONE)
|
||
{
|
||
int iRelationType = GetDefaultRelationshipDisposition(pEntHit->Classify());
|
||
|
||
if (iRelationType != D_HT)
|
||
{
|
||
bAimAtThis = false;
|
||
}
|
||
}
|
||
|
||
if (bAimAtThis)
|
||
{
|
||
if (pEntHit->GetFlags() & FL_AIMTARGET)
|
||
{
|
||
m_fOnTarget = true;
|
||
}
|
||
|
||
// Player is already on target naturally, don't autoaim.
|
||
// Fill out the autoaim_params_t struct, though.
|
||
params.m_hAutoAimEntity.Set(pEntHit);
|
||
params.m_vecAutoAimDir = bestdir;
|
||
params.m_vecAutoAimPoint = tr.endpos;
|
||
params.m_bAutoAimAssisting = false;
|
||
params.m_bOnTargetNatural = true;
|
||
return vec3_angle;
|
||
}
|
||
}
|
||
|
||
//Fall through and look for an autoaim ent.
|
||
}
|
||
}
|
||
|
||
int count = AimTarget_ListCount();
|
||
if (count)
|
||
{
|
||
CBaseEntity **pList = (CBaseEntity **)stackalloc(sizeof(CBaseEntity *) * count);
|
||
AimTarget_ListCopy(pList, count);
|
||
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
Vector center;
|
||
Vector dir;
|
||
CBaseEntity *pEntity = pList[i];
|
||
|
||
// Don't autoaim at anything that doesn't want to be.
|
||
if (!pEntity->ShouldAttractAutoAim(this))
|
||
continue;
|
||
|
||
// Don't shoot yourself
|
||
if (pEntity == this)
|
||
continue;
|
||
|
||
if ((pEntity->IsNPC() && !pEntity->IsAlive()) || !pEntity->edict())
|
||
continue;
|
||
|
||
if (!g_pGameRules->ShouldAutoAim(this, pEntity->edict()))
|
||
continue;
|
||
|
||
// don't look through water
|
||
if ((GetWaterLevel() != 3 && pEntity->GetWaterLevel() == 3) || (GetWaterLevel() == 3 && pEntity->GetWaterLevel() == 0))
|
||
continue;
|
||
|
||
if (pEntity->MyNPCPointer())
|
||
{
|
||
// If this entity is an NPC, only aim if it is an enemy.
|
||
if (IRelationType(pEntity) != D_HT)
|
||
{
|
||
if (!pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch())
|
||
// Msg( "friend\n");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// Don't autoaim at the noisy bodytarget, this makes the autoaim crosshair wobble.
|
||
//center = pEntity->BodyTarget( vecSrc, false );
|
||
center = pEntity->WorldSpaceCenter();
|
||
|
||
dir = (center - vecSrc);
|
||
|
||
float dist = dir.Length2D();
|
||
VectorNormalize(dir);
|
||
|
||
// Skip if out of range.
|
||
if (dist > params.m_fMaxDist)
|
||
continue;
|
||
|
||
float dot = DotProduct(dir, v_forward);
|
||
|
||
// make sure it's in front of the player
|
||
if (dot < 0)
|
||
continue;
|
||
|
||
if (!(pEntity->GetFlags() & FL_FLY))
|
||
{
|
||
// Refuse to take wild shots at targets far from reticle.
|
||
if (GetActiveWeapon() != NULL && dot < GetActiveWeapon()->GetMaxAutoAimDeflection())
|
||
{
|
||
// Be lenient if the player is looking down, though. 30 degrees through 90 degrees of pitch.
|
||
// (90 degrees is looking down at player's own 'feet'. Looking straight ahead is 0 degrees pitch.
|
||
// This was done for XBox to make it easier to fight headcrabs around the player's feet.
|
||
if (eyeAngles.x < 30.0f || eyeAngles.x > 90.0f || g_pGameRules->GetAutoAimMode() != AUTOAIM_ON_CONSOLE)
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
score = GetAutoaimScore(vecSrc, v_forward, pEntity->GetAutoAimCenter(), pEntity, params.m_fScale, GetActiveWeapon());
|
||
|
||
if (score <= bestscore)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
UTIL_TraceLine(vecSrc, center, MASK_SHOT, &traceFilter, &tr);
|
||
|
||
if (tr.fraction != 1.0 && tr.m_pEnt != pEntity)
|
||
{
|
||
// Msg( "hit %s, can't see %s\n", STRING( tr.u.ent->classname ), STRING( pEdict->classname ) );
|
||
continue;
|
||
}
|
||
|
||
// This is the best candidate so far.
|
||
bestscore = score;
|
||
bestent = pEntity;
|
||
bestdir = dir;
|
||
}
|
||
if (bestent)
|
||
{
|
||
QAngle bestang;
|
||
|
||
VectorAngles(bestdir, bestang);
|
||
|
||
if (IsInAVehicle())
|
||
{
|
||
bestang -= EyeAngles();
|
||
}
|
||
else
|
||
{
|
||
bestang -= EyeAngles() - m_Local.m_vecPunchAngle;
|
||
}
|
||
|
||
m_fOnTarget = true;
|
||
|
||
// Autoaim detected a target for us. Aim automatically at its bodytarget.
|
||
params.m_hAutoAimEntity.Set(bestent);
|
||
params.m_vecAutoAimDir = bestdir;
|
||
params.m_vecAutoAimPoint = bestent->BodyTarget(vecSrc, false);
|
||
params.m_bAutoAimAssisting = true;
|
||
|
||
return bestang;
|
||
}
|
||
}
|
||
|
||
return vec3_angle;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ResetAutoaim(void)
|
||
{
|
||
if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0)
|
||
{
|
||
m_vecAutoAim = QAngle(0, 0, 0);
|
||
engine->CrosshairAngle(edict(), 0, 0);
|
||
}
|
||
m_fOnTarget = false;
|
||
}
|
||
|
||
// ==========================================================================
|
||
// > Weapon stuff
|
||
// ==========================================================================
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Override base class, player can always use weapon
|
||
// Input : A weapon
|
||
// Output : true or false
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::Weapon_CanUse(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Override to clear dropped weapon from the hud
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::Weapon_Drop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget /* = NULL */, const Vector *pVelocity /* = NULL */)
|
||
{
|
||
/*if (!pWeapon->CanDrop())
|
||
return;*/
|
||
if (pWeapon->IsIronSighted())
|
||
pWeapon->OffIronSight();
|
||
|
||
if (pWeapon->IsScopeSighted())
|
||
pWeapon->OffScopeSight();
|
||
|
||
/*if (cvar->FindVar("oc_state_IRsight_on")->GetInt() == 1)
|
||
{
|
||
engine->ServerCommand("ironsight_toggle\n");
|
||
cvar->FindVar("oc_state_IRsight_on")->SetValue(0);
|
||
}
|
||
if (cvar->FindVar("oc_state_InSecondFire")->GetInt())
|
||
cvar->FindVar("oc_state_InSecondFire")->SetValue(0);
|
||
if (cvar->FindVar("oc_state_IRsight_on")->GetInt())
|
||
cvar->FindVar("oc_state_IRsight_on")->SetValue(0);*/
|
||
|
||
bool bWasActiveWeapon = false;
|
||
if (pWeapon == GetActiveWeapon())
|
||
{
|
||
bWasActiveWeapon = true;
|
||
}
|
||
|
||
if (pWeapon->allWeapons.HasElement(MAKE_STRING(pWeapon->GetClassname())))
|
||
pWeapon->allWeapons.FindAndRemove(MAKE_STRING(pWeapon->GetClassname()));
|
||
|
||
if (pWeapon->allObjectWeapons.HasElement(pWeapon))
|
||
pWeapon->allObjectWeapons.FindAndRemove(pWeapon);
|
||
|
||
if (pWeapon)
|
||
{
|
||
pWeapon->m_bFirstEquip = true;
|
||
if (bWasActiveWeapon)
|
||
{
|
||
pWeapon->SendWeaponAnim(ACT_VM_IDLE);
|
||
}
|
||
}
|
||
StopParticleEffects(this);
|
||
StopParticleEffects(this->GetViewModel());
|
||
|
||
if (Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_frag")
|
||
|| Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_hopwire")
|
||
|| Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_tripwire")
|
||
|| Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_molotov")
|
||
|| Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_smokegrenade")
|
||
|| Q_strstr(STRING(MAKE_STRING(pWeapon->GetClassname())), "weapon_flashbang"))
|
||
{
|
||
RemoveGrenadeFromSlot(pWeapon);
|
||
}
|
||
|
||
BaseClass::Weapon_Drop(pWeapon, pvecTarget, pVelocity);
|
||
|
||
if (bWasActiveWeapon)
|
||
{
|
||
if (!SwitchToNextBestWeapon(NULL))
|
||
{
|
||
CBaseViewModel *vm = GetViewModel();
|
||
if (vm)
|
||
{
|
||
vm->AddEffects(EF_NODRAW);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : weaponSlot -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::Weapon_DropSlot(int weaponSlot)
|
||
{
|
||
CBaseCombatWeapon *pWeapon;
|
||
|
||
// Check for that slot being occupied already
|
||
for (int i = 0; i < MAX_WEAPONS; i++)
|
||
{
|
||
pWeapon = GetWeapon(i);
|
||
|
||
if (pWeapon != NULL)
|
||
{
|
||
// If the slots match, it's already occupied
|
||
if (pWeapon->GetSlot() == weaponSlot)
|
||
{
|
||
//if (!(m_nButtons & IN_ATTACK) && !(m_nButtons & IN_ATTACK2))
|
||
Weapon_Drop(pWeapon, NULL, NULL);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Override to add weapon to the hud
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::Weapon_Equip(CBaseCombatWeapon *pWeapon)
|
||
{
|
||
BaseClass::Weapon_Equip(pWeapon);
|
||
|
||
bool bShouldSwitch = g_pGameRules->FShouldSwitchWeapon(this, pWeapon);
|
||
|
||
EmitSound("HL2Player.PickupWeapon");
|
||
|
||
#ifdef HL2_DLL
|
||
if (bShouldSwitch == false && PhysCannonGetHeldEntity(GetActiveWeapon()) == pWeapon &&
|
||
Weapon_OwnsThisType(pWeapon->GetClassname(), pWeapon->GetSubType()))
|
||
{
|
||
bShouldSwitch = true;
|
||
}
|
||
#endif//HL2_DLL
|
||
|
||
// should we switch to this item?
|
||
if (bShouldSwitch)
|
||
{
|
||
Weapon_Switch(pWeapon);
|
||
}
|
||
|
||
if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt())
|
||
AddGrenadeToSlot(pWeapon);
|
||
}
|
||
|
||
|
||
//=========================================================
|
||
// HasNamedPlayerItem Does the player already have this item?
|
||
//=========================================================
|
||
CBaseEntity *CBasePlayer::HasNamedPlayerItem(const char *pszItemName)
|
||
{
|
||
for (int i = 0; i < WeaponCount(); i++)
|
||
{
|
||
if (!GetWeapon(i))
|
||
continue;
|
||
|
||
if (FStrEq(pszItemName, GetWeapon(i)->GetClassname()))
|
||
{
|
||
return GetWeapon(i);
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
#if defined USES_ECON_ITEMS
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Add this wearable to the players' equipment list.
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::EquipWearable(CEconWearable *pItem)
|
||
{
|
||
Assert(pItem);
|
||
|
||
if (pItem)
|
||
{
|
||
m_hMyWearables.AddToHead(pItem);
|
||
pItem->Equip(this);
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
// Double check list integrity.
|
||
for (int i = m_hMyWearables.Count() - 1; i >= 0; --i)
|
||
{
|
||
Assert(m_hMyWearables[i] != NULL);
|
||
}
|
||
// Networked Vector has a max size of MAX_WEARABLES_SENT_FROM_SERVER, should never have more then 7 wearables
|
||
// in public
|
||
// Search for : RecvPropUtlVector( RECVINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, RecvPropEHandle(NULL, 0, 0) ),
|
||
Assert(m_hMyWearables.Count() <= MAX_WEARABLES_SENT_FROM_SERVER);
|
||
#endif
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Remove this wearable from the player's equipment list.
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::RemoveWearable(CEconWearable *pItem)
|
||
{
|
||
Assert(pItem);
|
||
|
||
for (int i = m_hMyWearables.Count() - 1; i >= 0; --i)
|
||
{
|
||
CEconWearable *pWearable = m_hMyWearables[i];
|
||
if (pWearable == pItem)
|
||
{
|
||
pItem->UnEquip(this);
|
||
UTIL_Remove(pWearable);
|
||
m_hMyWearables.Remove(i);
|
||
break;
|
||
}
|
||
|
||
// Integrety is failing, remove NULLs
|
||
if (!pWearable)
|
||
{
|
||
m_hMyWearables.Remove(i);
|
||
break;
|
||
}
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
// Double check list integrity.
|
||
for (int i = m_hMyWearables.Count() - 1; i >= 0; --i)
|
||
{
|
||
Assert(m_hMyWearables[i] != NULL);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::PlayWearableAnimsForPlaybackEvent(wearableanimplayback_t iPlayback)
|
||
{
|
||
// Tell all our wearables to play their animations
|
||
FOR_EACH_VEC(m_hMyWearables, i)
|
||
{
|
||
if (m_hMyWearables[i])
|
||
{
|
||
m_hMyWearables[i]->PlayAnimForPlaybackEvent(iPlayback);
|
||
}
|
||
}
|
||
}
|
||
#endif // USES_ECON_ITEMS
|
||
|
||
//================================================================================
|
||
// TEAM HANDLING
|
||
//================================================================================
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Put the player in the specified team
|
||
//-----------------------------------------------------------------------------
|
||
|
||
void CBasePlayer::ChangeTeam(int iTeamNum, bool bAutoTeam, bool bSilent)
|
||
{
|
||
if (!GetGlobalTeam(iTeamNum))
|
||
{
|
||
Warning("CBasePlayer::ChangeTeam( %d ) - invalid team index.\n", iTeamNum);
|
||
return;
|
||
}
|
||
|
||
// if this is our current team, just abort
|
||
if (iTeamNum == GetTeamNumber())
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Immediately tell all clients that he's changing team. This has to be done
|
||
// first, so that all user messages that follow as a result of the team change
|
||
// come after this one, allowing the client to be prepared for them.
|
||
IGameEvent * event = gameeventmanager->CreateEvent("player_team");
|
||
if (event)
|
||
{
|
||
event->SetInt("userid", GetUserID());
|
||
event->SetInt("team", iTeamNum);
|
||
event->SetInt("oldteam", GetTeamNumber());
|
||
event->SetInt("disconnect", IsDisconnecting());
|
||
event->SetInt("autoteam", bAutoTeam);
|
||
event->SetInt("silent", bSilent);
|
||
event->SetString("name", GetPlayerName());
|
||
|
||
gameeventmanager->FireEvent(event);
|
||
}
|
||
|
||
// Remove him from his current team
|
||
if (GetTeam())
|
||
{
|
||
GetTeam()->RemovePlayer(this);
|
||
}
|
||
|
||
// Are we being added to a team?
|
||
if (iTeamNum)
|
||
{
|
||
GetGlobalTeam(iTeamNum)->AddPlayer(this);
|
||
}
|
||
|
||
BaseClass::ChangeTeam(iTeamNum);
|
||
}
|
||
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Locks a player to the spot; they can't move, shoot, or be hurt
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::LockPlayerInPlace(void)
|
||
{
|
||
if (m_iPlayerLocked)
|
||
return;
|
||
|
||
AddFlag(FL_GODMODE | FL_FROZEN);
|
||
SetMoveType(MOVETYPE_NONE);
|
||
m_iPlayerLocked = true;
|
||
|
||
// force a client data update, so that anything that has been done to
|
||
// this player previously this frame won't get delayed in being sent
|
||
UpdateClientData();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Unlocks a previously locked player
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::UnlockPlayer(void)
|
||
{
|
||
if (!m_iPlayerLocked)
|
||
return;
|
||
|
||
RemoveFlag(FL_GODMODE | FL_FROZEN);
|
||
SetMoveType(MOVETYPE_WALK);
|
||
m_iPlayerLocked = false;
|
||
}
|
||
|
||
void CBasePlayer::SetPlayerInUseEnt(CBaseEntity *pUseEntity)
|
||
{
|
||
if (pUseEntity != NULL)
|
||
{
|
||
CHL2_Player *pHLPlayer = static_cast<CHL2_Player*>(this);
|
||
if (pHLPlayer)
|
||
pHLPlayer->SetHandsVisible(true);
|
||
}
|
||
}
|
||
|
||
bool CBasePlayer::ClearUseEntity()
|
||
{
|
||
if (m_hUseEntity != NULL)
|
||
{
|
||
// Stop controlling the train/object
|
||
// TODO: Send HUD Update
|
||
m_hUseEntity->Use(this, this, USE_OFF, 0);
|
||
m_hUseEntity = NULL;
|
||
|
||
CHL2_Player *pHLPlayer = static_cast<CHL2_Player*>(this);
|
||
if (pHLPlayer)
|
||
pHLPlayer->SetHandsVisible(false);
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::HideViewModels(void)
|
||
{
|
||
for (int i = 0; i < MAX_VIEWMODELS; i++)
|
||
{
|
||
CBaseViewModel *vm = GetViewModel(i);
|
||
if (!vm)
|
||
continue;
|
||
|
||
vm->SetWeaponModel(NULL, NULL);
|
||
}
|
||
}
|
||
|
||
class CStripWeapons : public CPointEntity
|
||
{
|
||
DECLARE_CLASS(CStripWeapons, CPointEntity);
|
||
public:
|
||
void InputStripWeapons(inputdata_t &data);
|
||
void InputStripWeaponsAndSuit(inputdata_t &data);
|
||
|
||
void StripWeapons(inputdata_t &data, bool stripSuit);
|
||
DECLARE_DATADESC();
|
||
};
|
||
|
||
LINK_ENTITY_TO_CLASS(player_weaponstrip, CStripWeapons);
|
||
|
||
BEGIN_DATADESC(CStripWeapons)
|
||
DEFINE_INPUTFUNC(FIELD_VOID, "Strip", InputStripWeapons),
|
||
DEFINE_INPUTFUNC(FIELD_VOID, "StripWeaponsAndSuit", InputStripWeaponsAndSuit),
|
||
END_DATADESC()
|
||
|
||
|
||
void CStripWeapons::InputStripWeapons(inputdata_t &data)
|
||
{
|
||
StripWeapons(data, false);
|
||
}
|
||
|
||
void CStripWeapons::InputStripWeaponsAndSuit(inputdata_t &data)
|
||
{
|
||
StripWeapons(data, true);
|
||
}
|
||
|
||
void CStripWeapons::StripWeapons(inputdata_t &data, bool stripSuit)
|
||
{
|
||
CBasePlayer *pPlayer = NULL;
|
||
|
||
if (data.pActivator && data.pActivator->IsPlayer())
|
||
{
|
||
pPlayer = (CBasePlayer *)data.pActivator;
|
||
}
|
||
else if (!g_pGameRules->IsDeathmatch())
|
||
{
|
||
pPlayer = UTIL_GetLocalPlayer();
|
||
}
|
||
|
||
if (pPlayer)
|
||
{
|
||
pPlayer->RemoveAllItems(stripSuit);
|
||
}
|
||
}
|
||
|
||
|
||
class CRevertSaved : public CPointEntity
|
||
{
|
||
DECLARE_CLASS(CRevertSaved, CPointEntity);
|
||
public:
|
||
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
|
||
void LoadThink(void);
|
||
|
||
DECLARE_DATADESC();
|
||
|
||
inline float Duration(void) { return m_Duration; }
|
||
inline float HoldTime(void) { return m_HoldTime; }
|
||
inline float LoadTime(void) { return m_loadTime; }
|
||
|
||
inline void SetDuration(float duration) { m_Duration = duration; }
|
||
inline void SetHoldTime(float hold) { m_HoldTime = hold; }
|
||
inline void SetLoadTime(float time) { m_loadTime = time; }
|
||
|
||
//Inputs
|
||
void InputReload(inputdata_t &data);
|
||
|
||
#ifdef HL1_DLL
|
||
void MessageThink(void);
|
||
inline float MessageTime(void) { return m_messageTime; }
|
||
inline void SetMessageTime(float time) { m_messageTime = time; }
|
||
#endif
|
||
|
||
private:
|
||
|
||
float m_loadTime;
|
||
float m_Duration;
|
||
float m_HoldTime;
|
||
|
||
#ifdef HL1_DLL
|
||
string_t m_iszMessage;
|
||
float m_messageTime;
|
||
#endif
|
||
};
|
||
|
||
LINK_ENTITY_TO_CLASS(player_loadsaved, CRevertSaved);
|
||
|
||
BEGIN_DATADESC(CRevertSaved)
|
||
|
||
#ifdef HL1_DLL
|
||
DEFINE_KEYFIELD(m_iszMessage, FIELD_STRING, "message"),
|
||
DEFINE_KEYFIELD(m_messageTime, FIELD_FLOAT, "messagetime"), // These are not actual times, but durations, so save as floats
|
||
|
||
DEFINE_FUNCTION(MessageThink),
|
||
#endif
|
||
|
||
DEFINE_KEYFIELD(m_loadTime, FIELD_FLOAT, "loadtime"),
|
||
DEFINE_KEYFIELD(m_Duration, FIELD_FLOAT, "duration"),
|
||
DEFINE_KEYFIELD(m_HoldTime, FIELD_FLOAT, "holdtime"),
|
||
|
||
DEFINE_INPUTFUNC(FIELD_VOID, "Reload", InputReload),
|
||
|
||
|
||
// Function Pointers
|
||
DEFINE_FUNCTION(LoadThink),
|
||
|
||
END_DATADESC()
|
||
|
||
CBaseEntity *CreatePlayerLoadSave(Vector vOrigin, float flDuration, float flHoldTime, float flLoadTime)
|
||
{
|
||
CRevertSaved *pRevertSaved = (CRevertSaved *)CreateEntityByName("player_loadsaved");
|
||
|
||
if (pRevertSaved == NULL)
|
||
return NULL;
|
||
|
||
UTIL_SetOrigin(pRevertSaved, vOrigin);
|
||
|
||
pRevertSaved->Spawn();
|
||
pRevertSaved->SetDuration(flDuration);
|
||
pRevertSaved->SetHoldTime(flHoldTime);
|
||
pRevertSaved->SetLoadTime(flLoadTime);
|
||
|
||
return pRevertSaved;
|
||
}
|
||
|
||
|
||
|
||
void CRevertSaved::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
|
||
{
|
||
UTIL_ScreenFadeAll(m_clrRender, Duration(), HoldTime(), FFADE_OUT);
|
||
SetNextThink(gpGlobals->curtime + LoadTime());
|
||
SetThink(&CRevertSaved::LoadThink);
|
||
|
||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||
|
||
if (pPlayer)
|
||
{
|
||
//Adrian: Setting this flag so we can't move or save a game.
|
||
pPlayer->pl.deadflag = true;
|
||
pPlayer->AddFlag((FL_NOTARGET | FL_FROZEN));
|
||
|
||
// clear any pending autosavedangerous
|
||
g_ServerGameDLL.m_fAutoSaveDangerousTime = 0.0f;
|
||
g_ServerGameDLL.m_fAutoSaveDangerousMinHealthToCommit = 0.0f;
|
||
}
|
||
}
|
||
|
||
void CRevertSaved::InputReload(inputdata_t &inputdata)
|
||
{
|
||
UTIL_ScreenFadeAll(m_clrRender, Duration(), HoldTime(), FFADE_OUT);
|
||
|
||
#ifdef HL1_DLL
|
||
SetNextThink(gpGlobals->curtime + MessageTime());
|
||
SetThink(&CRevertSaved::MessageThink);
|
||
#else
|
||
SetNextThink(gpGlobals->curtime + LoadTime());
|
||
SetThink(&CRevertSaved::LoadThink);
|
||
#endif
|
||
|
||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||
|
||
if (pPlayer)
|
||
{
|
||
//Adrian: Setting this flag so we can't move or save a game.
|
||
pPlayer->pl.deadflag = true;
|
||
pPlayer->AddFlag((FL_NOTARGET | FL_FROZEN));
|
||
|
||
// clear any pending autosavedangerous
|
||
g_ServerGameDLL.m_fAutoSaveDangerousTime = 0.0f;
|
||
g_ServerGameDLL.m_fAutoSaveDangerousMinHealthToCommit = 0.0f;
|
||
}
|
||
}
|
||
|
||
#ifdef HL1_DLL
|
||
void CRevertSaved::MessageThink(void)
|
||
{
|
||
UTIL_ShowMessageAll(STRING(m_iszMessage));
|
||
float nextThink = LoadTime() - MessageTime();
|
||
if (nextThink > 0)
|
||
{
|
||
SetNextThink(gpGlobals->curtime + nextThink);
|
||
SetThink(&CRevertSaved::LoadThink);
|
||
}
|
||
else
|
||
LoadThink();
|
||
}
|
||
#endif
|
||
|
||
|
||
void CRevertSaved::LoadThink(void)
|
||
{
|
||
if (!gpGlobals->deathmatch)
|
||
{
|
||
engine->ServerCommand("reload\n");
|
||
}
|
||
}
|
||
|
||
#define SF_SPEED_MOD_SUPPRESS_WEAPONS (1<<0) // Take away weapons
|
||
#define SF_SPEED_MOD_SUPPRESS_HUD (1<<1) // Take away the HUD
|
||
#define SF_SPEED_MOD_SUPPRESS_JUMP (1<<2)
|
||
#define SF_SPEED_MOD_SUPPRESS_DUCK (1<<3)
|
||
#define SF_SPEED_MOD_SUPPRESS_USE (1<<4)
|
||
#define SF_SPEED_MOD_SUPPRESS_SPEED (1<<5)
|
||
#define SF_SPEED_MOD_SUPPRESS_ATTACK (1<<6)
|
||
#define SF_SPEED_MOD_SUPPRESS_ZOOM (1<<7)
|
||
|
||
class CMovementSpeedMod : public CPointEntity
|
||
{
|
||
DECLARE_CLASS(CMovementSpeedMod, CPointEntity);
|
||
public:
|
||
void InputSpeedMod(inputdata_t &data);
|
||
|
||
private:
|
||
int GetDisabledButtonMask(void);
|
||
|
||
DECLARE_DATADESC();
|
||
};
|
||
|
||
LINK_ENTITY_TO_CLASS(player_speedmod, CMovementSpeedMod);
|
||
|
||
BEGIN_DATADESC(CMovementSpeedMod)
|
||
DEFINE_INPUTFUNC(FIELD_FLOAT, "ModifySpeed", InputSpeedMod),
|
||
END_DATADESC()
|
||
|
||
int CMovementSpeedMod::GetDisabledButtonMask(void)
|
||
{
|
||
int nMask = 0;
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_JUMP))
|
||
{
|
||
nMask |= IN_JUMP;
|
||
}
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_DUCK))
|
||
{
|
||
nMask |= IN_DUCK;
|
||
}
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_USE))
|
||
{
|
||
nMask |= IN_USE;
|
||
}
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_SPEED))
|
||
{
|
||
nMask |= IN_SPEED;
|
||
}
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_ATTACK))
|
||
{
|
||
nMask |= (IN_ATTACK | IN_ATTACK2);
|
||
}
|
||
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_ZOOM))
|
||
{
|
||
nMask |= IN_ZOOM;
|
||
}
|
||
|
||
return nMask;
|
||
}
|
||
|
||
void CMovementSpeedMod::InputSpeedMod(inputdata_t &data)
|
||
{
|
||
CBasePlayer *pPlayer = NULL;
|
||
|
||
if (data.pActivator && data.pActivator->IsPlayer())
|
||
{
|
||
pPlayer = (CBasePlayer *)data.pActivator;
|
||
}
|
||
else if (!g_pGameRules->IsDeathmatch())
|
||
{
|
||
pPlayer = UTIL_GetLocalPlayer();
|
||
}
|
||
|
||
if (pPlayer)
|
||
{
|
||
if (data.value.Float() != 1.0f)
|
||
{
|
||
// Holster weapon immediately, to allow it to cleanup
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_WEAPONS))
|
||
{
|
||
if (pPlayer->GetActiveWeapon())
|
||
{
|
||
pPlayer->Weapon_SetLast(pPlayer->GetActiveWeapon());
|
||
pPlayer->GetActiveWeapon()->Holster();
|
||
pPlayer->ClearActiveWeapon();
|
||
}
|
||
|
||
pPlayer->HideViewModels();
|
||
}
|
||
|
||
// Turn off the flashlight
|
||
if (pPlayer->FlashlightIsOn())
|
||
{
|
||
pPlayer->FlashlightTurnOff();
|
||
}
|
||
|
||
// Disable the flashlight's further use
|
||
pPlayer->SetFlashlightEnabled(false);
|
||
pPlayer->DisableButtons(GetDisabledButtonMask());
|
||
pPlayer->SpecialBodyDraw = true;
|
||
|
||
// Hide the HUD
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_HUD))
|
||
{
|
||
pPlayer->m_Local.m_iHideHUD |= HIDEHUD_ALL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Bring the weapon back
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_WEAPONS) && pPlayer->GetActiveWeapon() == NULL)
|
||
{
|
||
pPlayer->SetActiveWeapon(pPlayer->Weapon_GetLast());
|
||
if (pPlayer->GetActiveWeapon())
|
||
{
|
||
pPlayer->GetActiveWeapon()->Deploy();
|
||
}
|
||
}
|
||
|
||
// Allow the flashlight again
|
||
pPlayer->SetFlashlightEnabled(true);
|
||
pPlayer->EnableButtons(GetDisabledButtonMask());
|
||
pPlayer->SpecialBodyDraw = false;
|
||
|
||
// Restore the HUD
|
||
if (HasSpawnFlags(SF_SPEED_MOD_SUPPRESS_HUD))
|
||
{
|
||
pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_ALL;
|
||
}
|
||
}
|
||
|
||
pPlayer->SetLaggedMovementValue(data.value.Float());
|
||
}
|
||
}
|
||
|
||
void SendProxy_CropFlagsToPlayerFlagBitsLength(const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID)
|
||
{
|
||
int mask = (1 << PLAYER_FLAG_BITS) - 1;
|
||
int data = *(int *)pVarData;
|
||
|
||
pOut->m_Int = (data & mask);
|
||
}
|
||
// -------------------------------------------------------------------------------- //
|
||
// SendTable for CPlayerState.
|
||
// -------------------------------------------------------------------------------- //
|
||
|
||
BEGIN_SEND_TABLE_NOBASE(CPlayerState, DT_PlayerState)
|
||
SendPropInt(SENDINFO(deadflag), 1, SPROP_UNSIGNED),
|
||
END_SEND_TABLE()
|
||
|
||
// -------------------------------------------------------------------------------- //
|
||
// This data only gets sent to clients that ARE this player entity.
|
||
// -------------------------------------------------------------------------------- //
|
||
|
||
BEGIN_SEND_TABLE_NOBASE(CBasePlayer, DT_LocalPlayerExclusive)
|
||
|
||
SendPropDataTable(SENDINFO_DT(m_Local), &REFERENCE_SEND_TABLE(DT_Local)),
|
||
|
||
// If HL2_DLL is defined, then baseflex.cpp already sends these.
|
||
#ifndef HL2_DLL
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecViewOffset, 0), 8, SPROP_ROUNDDOWN, -32.0, 32.0f),
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecViewOffset, 1), 8, SPROP_ROUNDDOWN, -32.0, 32.0f),
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecViewOffset, 2), 20, SPROP_CHANGES_OFTEN, 0.0f, 256.0f),
|
||
#endif
|
||
|
||
SendPropFloat(SENDINFO(m_flFriction), 8, SPROP_ROUNDDOWN, 0.0f, 4.0f),
|
||
|
||
SendPropArray3(SENDINFO_ARRAY3(m_iAmmo), SendPropInt(SENDINFO_ARRAY(m_iAmmo), -1, SPROP_VARINT | SPROP_UNSIGNED)),
|
||
|
||
SendPropInt(SENDINFO(m_fOnTarget), 2, SPROP_UNSIGNED),
|
||
|
||
SendPropInt(SENDINFO(m_nTickBase), -1, SPROP_CHANGES_OFTEN),
|
||
SendPropInt(SENDINFO(m_nNextThinkTick)),
|
||
|
||
SendPropEHandle(SENDINFO(m_hLastWeapon)),
|
||
SendPropEHandle(SENDINFO(m_hGroundEntity), SPROP_CHANGES_OFTEN),
|
||
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecVelocity, 0), 32, SPROP_NOSCALE | SPROP_CHANGES_OFTEN),
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecVelocity, 1), 32, SPROP_NOSCALE | SPROP_CHANGES_OFTEN),
|
||
SendPropFloat(SENDINFO_VECTORELEM(m_vecVelocity, 2), 32, SPROP_NOSCALE | SPROP_CHANGES_OFTEN),
|
||
|
||
#if PREDICTION_ERROR_CHECK_LEVEL > 1
|
||
SendPropVector(SENDINFO(m_vecBaseVelocity), -1, SPROP_COORD),
|
||
#else
|
||
SendPropVector(SENDINFO(m_vecBaseVelocity), 20, 0, -1000, 1000),
|
||
#endif
|
||
|
||
SendPropEHandle(SENDINFO(m_hConstraintEntity)),
|
||
SendPropVector(SENDINFO(m_vecConstraintCenter), 0, SPROP_NOSCALE),
|
||
SendPropFloat(SENDINFO(m_flConstraintRadius), 0, SPROP_NOSCALE),
|
||
SendPropFloat(SENDINFO(m_flConstraintWidth), 0, SPROP_NOSCALE),
|
||
SendPropFloat(SENDINFO(m_flConstraintSpeedFactor), 0, SPROP_NOSCALE),
|
||
|
||
SendPropFloat(SENDINFO(m_flDeathTime), 0, SPROP_NOSCALE),
|
||
|
||
SendPropBool(SENDINFO(AllowCamAttachment)),
|
||
SendPropBool(SENDINFO(SpecialBodyDraw)),
|
||
SendPropInt(SENDINFO(m_nWaterLevel), 2, SPROP_UNSIGNED),
|
||
SendPropFloat(SENDINFO(m_flLaggedMovementValue), 0, SPROP_NOSCALE),
|
||
|
||
SendPropBool(SENDINFO(m_bIsRunning)),
|
||
//SendPropBool(SENDINFO(m_bIsSighted)),
|
||
SendPropBool(SENDINFO(m_bSlowMoIsEnabled)),
|
||
SendPropBool(SENDINFO(m_bNightvisionEnabled)),
|
||
SendPropBool(SENDINFO(m_bIsInSelectionMode)),
|
||
|
||
END_SEND_TABLE()
|
||
|
||
|
||
// -------------------------------------------------------------------------------- //
|
||
// DT_BasePlayer sendtable.
|
||
// -------------------------------------------------------------------------------- //
|
||
|
||
#if defined USES_ECON_ITEMS
|
||
EXTERN_SEND_TABLE(DT_AttributeList);
|
||
#endif
|
||
|
||
IMPLEMENT_SERVERCLASS_ST(CBasePlayer, DT_BasePlayer)
|
||
|
||
#if defined USES_ECON_ITEMS
|
||
SendPropDataTable(SENDINFO_DT(m_AttributeList), &REFERENCE_SEND_TABLE(DT_AttributeList)),
|
||
#endif
|
||
|
||
SendPropDataTable(SENDINFO_DT(pl), &REFERENCE_SEND_TABLE(DT_PlayerState), SendProxy_DataTableToDataTable),
|
||
|
||
SendPropEHandle(SENDINFO(m_hVehicle)),
|
||
SendPropEHandle(SENDINFO(m_hUseEntity)),
|
||
SendPropInt(SENDINFO(m_iHealth), -1, SPROP_VARINT | SPROP_CHANGES_OFTEN),
|
||
SendPropInt(SENDINFO(m_lifeState), 3, SPROP_UNSIGNED),
|
||
SendPropInt(SENDINFO(m_iBonusProgress), 15),
|
||
SendPropInt(SENDINFO(m_iBonusChallenge), 4),
|
||
SendPropFloat(SENDINFO(m_flMaxspeed), 12, SPROP_ROUNDDOWN, 0.0f, 2048.0f), // CL
|
||
SendPropInt(SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED | SPROP_CHANGES_OFTEN, SendProxy_CropFlagsToPlayerFlagBitsLength),
|
||
SendPropInt(SENDINFO(m_iObserverMode), 3, SPROP_UNSIGNED),
|
||
SendPropEHandle(SENDINFO(m_hObserverTarget)),
|
||
SendPropInt(SENDINFO(m_iFOV), 8, SPROP_UNSIGNED),
|
||
SendPropInt(SENDINFO(m_iFOVStart), 8, SPROP_UNSIGNED),
|
||
SendPropFloat(SENDINFO(m_flFOVTime)),
|
||
SendPropInt(SENDINFO(m_iDefaultFOV), 8, SPROP_UNSIGNED),
|
||
SendPropEHandle(SENDINFO(m_hZoomOwner)),
|
||
SendPropArray(SendPropEHandle(SENDINFO_ARRAY(m_hViewModel)), m_hViewModel),
|
||
SendPropString(SENDINFO(m_szLastPlaceName)),
|
||
|
||
SendPropInt(SENDINFO(m_iBloodOverlayDetailFrame), 8, SPROP_UNSIGNED),
|
||
SendPropFloat(SENDINFO(m_flNextBloodDryDisappear)),
|
||
|
||
#if defined USES_ECON_ITEMS
|
||
SendPropUtlVector(SENDINFO_UTLVECTOR(m_hMyWearables), MAX_WEARABLES_SENT_FROM_SERVER, SendPropEHandle(NULL, 0)),
|
||
#endif // USES_ECON_ITEMS
|
||
|
||
// Data that only gets sent to the local player.
|
||
SendPropDataTable("localdata", 0, &REFERENCE_SEND_TABLE(DT_LocalPlayerExclusive), SendProxy_SendLocalDataTable),
|
||
|
||
END_SEND_TABLE()
|
||
|
||
//=============================================================================
|
||
//
|
||
// Player Physics Shadow Code
|
||
//
|
||
|
||
void CBasePlayer::SetupVPhysicsShadow(const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, CPhysCollide *pStandModel, const char *pStandHullName, CPhysCollide *pCrouchModel, const char *pCrouchHullName)
|
||
{
|
||
solid_t solid;
|
||
Q_strncpy(solid.surfaceprop, "player", sizeof(solid.surfaceprop));
|
||
solid.params = g_PhysDefaultObjectParams;
|
||
solid.params.mass = 85.0f;
|
||
solid.params.inertia = 1e24f;
|
||
solid.params.enableCollisions = false;
|
||
//disable drag
|
||
solid.params.dragCoefficient = 0;
|
||
// create standing hull
|
||
m_pShadowStand = PhysModelCreateCustom(this, pStandModel, GetLocalOrigin(), GetLocalAngles(), pStandHullName, false, &solid);
|
||
m_pShadowStand->SetCallbackFlags(CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION);
|
||
|
||
// create crouchig hull
|
||
m_pShadowCrouch = PhysModelCreateCustom(this, pCrouchModel, GetLocalOrigin(), GetLocalAngles(), pCrouchHullName, false, &solid);
|
||
m_pShadowCrouch->SetCallbackFlags(CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION);
|
||
|
||
// default to stand
|
||
VPhysicsSetObject(m_pShadowStand);
|
||
|
||
// tell physics lists I'm a shadow controller object
|
||
PhysAddShadow(this);
|
||
m_pPhysicsController = physenv->CreatePlayerController(m_pShadowStand);
|
||
m_pPhysicsController->SetPushMassLimit(350.0f);
|
||
m_pPhysicsController->SetPushSpeedLimit(50.0f);
|
||
|
||
// Give the controller a valid position so it doesn't do anything rash.
|
||
UpdatePhysicsShadowToPosition(vecAbsOrigin);
|
||
|
||
// init state
|
||
if (GetFlags() & FL_DUCKING)
|
||
{
|
||
SetVCollisionState(vecAbsOrigin, vecAbsVelocity, VPHYS_CROUCH);
|
||
}
|
||
else
|
||
{
|
||
SetVCollisionState(vecAbsOrigin, vecAbsVelocity, VPHYS_WALK);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Empty, just want to keep the baseentity version from being called
|
||
// current so we don't kick up dust, etc.
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::VPhysicsCollision(int index, gamevcollisionevent_t *pEvent)
|
||
{
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::VPhysicsUpdate(IPhysicsObject *pPhysics)
|
||
{
|
||
float savedImpact = m_impactEnergyScale;
|
||
|
||
// HACKHACK: Reduce player's stress by 1/8th
|
||
m_impactEnergyScale *= 0.125f;
|
||
ApplyStressDamage(pPhysics, true);
|
||
m_impactEnergyScale = savedImpact;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Allow bots etc to use slightly different solid masks
|
||
//-----------------------------------------------------------------------------
|
||
unsigned int CBasePlayer::PlayerSolidMask(bool brushOnly) const
|
||
{
|
||
if (brushOnly)
|
||
{
|
||
return MASK_PLAYERSOLID_BRUSHONLY;
|
||
}
|
||
|
||
return MASK_PLAYERSOLID;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::VPhysicsShadowUpdate(IPhysicsObject *pPhysics)
|
||
{
|
||
if (sv_turbophysics.GetBool())
|
||
return;
|
||
|
||
Vector newPosition;
|
||
|
||
bool physicsUpdated = m_pPhysicsController->GetShadowPosition(&newPosition, NULL) > 0 ? true : false;
|
||
|
||
// UNDONE: If the player is penetrating, but the player's game collisions are not stuck, teleport the physics shadow to the game position
|
||
if (pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING)
|
||
{
|
||
CUtlVector<CBaseEntity *> list;
|
||
PhysGetListOfPenetratingEntities(this, list);
|
||
for (int i = list.Count() - 1; i >= 0; --i)
|
||
{
|
||
// filter out anything that isn't simulated by vphysics
|
||
// UNDONE: Filter out motion disabled objects?
|
||
if (list[i]->GetMoveType() == MOVETYPE_VPHYSICS)
|
||
{
|
||
// I'm currently stuck inside a moving object, so allow vphysics to
|
||
// apply velocity to the player in order to separate these objects
|
||
m_touchedPhysObject = true;
|
||
}
|
||
|
||
// if it's an NPC, tell them that the player is intersecting them
|
||
CAI_BaseNPC *pNPC = list[i]->MyNPCPointer();
|
||
if (pNPC)
|
||
{
|
||
pNPC->PlayerPenetratingVPhysics();
|
||
}
|
||
}
|
||
}
|
||
|
||
bool bCheckStuck = false;
|
||
if (m_afPhysicsFlags & PFLAG_GAMEPHYSICS_ROTPUSH)
|
||
{
|
||
bCheckStuck = true;
|
||
m_afPhysicsFlags &= ~PFLAG_GAMEPHYSICS_ROTPUSH;
|
||
}
|
||
if (m_pPhysicsController->IsInContact() || (m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER))
|
||
{
|
||
m_touchedPhysObject = true;
|
||
}
|
||
|
||
if (IsFollowingPhysics())
|
||
{
|
||
m_touchedPhysObject = true;
|
||
}
|
||
|
||
if (GetMoveType() == MOVETYPE_NOCLIP || pl.deadflag)
|
||
{
|
||
m_oldOrigin = GetAbsOrigin();
|
||
return;
|
||
}
|
||
|
||
if (phys_timescale.GetFloat() == 0.0f)
|
||
{
|
||
physicsUpdated = false;
|
||
}
|
||
|
||
if (!physicsUpdated)
|
||
return;
|
||
|
||
IPhysicsObject *pPhysGround = GetGroundVPhysics();
|
||
|
||
Vector newVelocity;
|
||
pPhysics->GetPosition(&newPosition, 0);
|
||
m_pPhysicsController->GetShadowVelocity(&newVelocity);
|
||
// assume vphysics gave us back a position without penetration
|
||
Vector lastValidPosition = newPosition;
|
||
|
||
if (physicsshadowupdate_render.GetBool())
|
||
{
|
||
NDebugOverlay::Box(GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs(), 255, 0, 0, 24, 15.0f);
|
||
NDebugOverlay::Box(newPosition, WorldAlignMins(), WorldAlignMaxs(), 0, 0, 255, 24, 15.0f);
|
||
// NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,0,255, 24, .01f);
|
||
}
|
||
|
||
Vector tmp = GetAbsOrigin() - newPosition;
|
||
if (!m_touchedPhysObject && !(GetFlags() & FL_ONGROUND))
|
||
{
|
||
tmp.z *= 0.5f; // don't care about z delta as much
|
||
}
|
||
|
||
float dist = tmp.LengthSqr();
|
||
float deltaV = (newVelocity - GetAbsVelocity()).LengthSqr();
|
||
|
||
float maxDistErrorSqr = VPHYS_MAX_DISTSQR;
|
||
float maxVelErrorSqr = VPHYS_MAX_VELSQR;
|
||
if (IsRideablePhysics(pPhysGround))
|
||
{
|
||
maxDistErrorSqr *= 0.25;
|
||
maxVelErrorSqr *= 0.25;
|
||
}
|
||
|
||
// player's physics was frozen, try moving to the game's simulated position if possible
|
||
if (m_pPhysicsController->WasFrozen())
|
||
{
|
||
m_bPhysicsWasFrozen = true;
|
||
// check my position (physics object could have simulated into my position
|
||
// physics is not very far away, check my position
|
||
trace_t trace;
|
||
UTIL_TraceEntity(this, GetAbsOrigin(), GetAbsOrigin(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (!trace.startsolid)
|
||
return;
|
||
|
||
// The physics shadow position is probably not in solid, try to move from there to the desired position
|
||
UTIL_TraceEntity(this, newPosition, GetAbsOrigin(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (!trace.startsolid)
|
||
{
|
||
// found a valid position between the two? take it.
|
||
SetAbsOrigin(trace.endpos);
|
||
UpdateVPhysicsPosition(trace.endpos, vec3_origin, 0);
|
||
return;
|
||
}
|
||
|
||
}
|
||
if (dist >= maxDistErrorSqr || deltaV >= maxVelErrorSqr || (pPhysGround && !m_touchedPhysObject))
|
||
{
|
||
if (m_touchedPhysObject || pPhysGround)
|
||
{
|
||
// BUGBUG: Rewrite this code using fixed timestep
|
||
if (deltaV >= maxVelErrorSqr && !m_bPhysicsWasFrozen)
|
||
{
|
||
Vector dir = GetAbsVelocity();
|
||
float len = VectorNormalize(dir);
|
||
float dot = DotProduct(newVelocity, dir);
|
||
if (dot > len)
|
||
{
|
||
dot = len;
|
||
}
|
||
else if (dot < -len)
|
||
{
|
||
dot = -len;
|
||
}
|
||
|
||
VectorMA(newVelocity, -dot, dir, newVelocity);
|
||
|
||
if (m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER)
|
||
{
|
||
float val = Lerp(0.1f, len, dot);
|
||
VectorMA(newVelocity, val - len, dir, newVelocity);
|
||
}
|
||
|
||
if (!IsRideablePhysics(pPhysGround))
|
||
{
|
||
if (!(m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER) && IsSimulatingOnAlternateTicks())
|
||
{
|
||
newVelocity *= 0.5f;
|
||
}
|
||
ApplyAbsVelocityImpulse(newVelocity);
|
||
}
|
||
}
|
||
|
||
trace_t trace;
|
||
UTIL_TraceEntity(this, newPosition, newPosition, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
if (!trace.allsolid && !trace.startsolid)
|
||
{
|
||
SetAbsOrigin(newPosition);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bCheckStuck = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_touchedPhysObject)
|
||
{
|
||
// check my position (physics object could have simulated into my position
|
||
// physics is not very far away, check my position
|
||
trace_t trace;
|
||
UTIL_TraceEntity(this, GetAbsOrigin(), GetAbsOrigin(),
|
||
MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
|
||
// is current position ok?
|
||
if (trace.allsolid || trace.startsolid)
|
||
{
|
||
// no use the final stuck check to move back to old if this stuck fix didn't work
|
||
bCheckStuck = true;
|
||
lastValidPosition = m_oldOrigin;
|
||
SetAbsOrigin(newPosition);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bCheckStuck)
|
||
{
|
||
trace_t trace;
|
||
UTIL_TraceEntity(this, GetAbsOrigin(), GetAbsOrigin(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace);
|
||
|
||
// current position is not ok, fixup
|
||
if (trace.allsolid || trace.startsolid)
|
||
{
|
||
// STUCK!?!?!
|
||
//Warning( "Checkstuck failed. Stuck on %s!!\n", trace.m_pEnt->GetClassname() );
|
||
SetAbsOrigin(lastValidPosition);
|
||
}
|
||
}
|
||
m_oldOrigin = GetAbsOrigin();
|
||
m_bPhysicsWasFrozen = false;
|
||
}
|
||
|
||
// recreate physics on save/load, don't try to save the state!
|
||
bool CBasePlayer::ShouldSavePhysics()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
void CBasePlayer::RefreshCollisionBounds(void)
|
||
{
|
||
BaseClass::RefreshCollisionBounds();
|
||
|
||
InitVCollision(GetAbsOrigin(), GetAbsVelocity());
|
||
SetViewOffset(VEC_VIEW_SCALED(this));
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InitVCollision(const Vector &vecAbsOrigin, const Vector &vecAbsVelocity)
|
||
{
|
||
// Cleanup any old vphysics stuff.
|
||
VPhysicsDestroyObject();
|
||
|
||
// in turbo physics players dont have a physics shadow
|
||
if (sv_turbophysics.GetBool())
|
||
return;
|
||
|
||
CPhysCollide *pModel = PhysCreateBbox(VEC_HULL_MIN_SCALED(this), VEC_HULL_MAX_SCALED(this));
|
||
CPhysCollide *pCrouchModel = PhysCreateBbox(VEC_DUCK_HULL_MIN_SCALED(this), VEC_DUCK_HULL_MAX_SCALED(this));
|
||
|
||
SetupVPhysicsShadow(vecAbsOrigin, vecAbsVelocity, pModel, "player_stand", pCrouchModel, "player_crouch");
|
||
}
|
||
|
||
|
||
void CBasePlayer::VPhysicsDestroyObject()
|
||
{
|
||
// Since CBasePlayer aliases its pointer to the physics object, tell CBaseEntity to
|
||
// clear out its physics object pointer so we don't wind up deleting one of
|
||
// the aliased objects twice.
|
||
VPhysicsSetObject(NULL);
|
||
|
||
PhysRemoveShadow(this);
|
||
|
||
if (m_pPhysicsController)
|
||
{
|
||
physenv->DestroyPlayerController(m_pPhysicsController);
|
||
m_pPhysicsController = NULL;
|
||
}
|
||
|
||
if (m_pShadowStand)
|
||
{
|
||
m_pShadowStand->EnableCollisions(false);
|
||
PhysDestroyObject(m_pShadowStand);
|
||
m_pShadowStand = NULL;
|
||
}
|
||
if (m_pShadowCrouch)
|
||
{
|
||
m_pShadowCrouch->EnableCollisions(false);
|
||
PhysDestroyObject(m_pShadowCrouch);
|
||
m_pShadowCrouch = NULL;
|
||
}
|
||
|
||
BaseClass::VPhysicsDestroyObject();
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SetVCollisionState(const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, int collisionState)
|
||
{
|
||
m_vphysicsCollisionState = collisionState;
|
||
switch (collisionState)
|
||
{
|
||
case VPHYS_WALK:
|
||
m_pShadowStand->SetPosition(vecAbsOrigin, vec3_angle, true);
|
||
m_pShadowStand->SetVelocity(&vecAbsVelocity, NULL);
|
||
m_pShadowCrouch->EnableCollisions(false);
|
||
m_pPhysicsController->SetObject(m_pShadowStand);
|
||
VPhysicsSwapObject(m_pShadowStand);
|
||
m_pShadowStand->EnableCollisions(true);
|
||
break;
|
||
|
||
case VPHYS_CROUCH:
|
||
m_pShadowCrouch->SetPosition(vecAbsOrigin, vec3_angle, true);
|
||
m_pShadowCrouch->SetVelocity(&vecAbsVelocity, NULL);
|
||
m_pShadowStand->EnableCollisions(false);
|
||
m_pPhysicsController->SetObject(m_pShadowCrouch);
|
||
VPhysicsSwapObject(m_pShadowCrouch);
|
||
m_pShadowCrouch->EnableCollisions(true);
|
||
break;
|
||
|
||
case VPHYS_NOCLIP:
|
||
m_pShadowCrouch->EnableCollisions(false);
|
||
m_pShadowStand->EnableCollisions(false);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
int CBasePlayer::GetFOV(void)
|
||
{
|
||
int nDefaultFOV;
|
||
|
||
// The vehicle's FOV wins if we're asking for a default value
|
||
if (GetVehicle())
|
||
{
|
||
CacheVehicleView();
|
||
nDefaultFOV = (m_flVehicleViewFOV == 0) ? GetDefaultFOV() : (int)m_flVehicleViewFOV;
|
||
}
|
||
else
|
||
{
|
||
nDefaultFOV = GetDefaultFOV();
|
||
}
|
||
|
||
int fFOV = (m_iFOV == 0) ? nDefaultFOV : m_iFOV;
|
||
|
||
// If it's immediate, just do it
|
||
if (m_Local.m_flFOVRate == 0.0f)
|
||
return fFOV;
|
||
|
||
float deltaTime = (float)(gpGlobals->curtime - m_flFOVTime) / m_Local.m_flFOVRate;
|
||
|
||
if (deltaTime >= 1.0f)
|
||
{
|
||
//If we're past the zoom time, just take the new value and stop lerping
|
||
m_iFOVStart = fFOV;
|
||
}
|
||
else
|
||
{
|
||
fFOV = SimpleSplineRemapValClamped(deltaTime, 0.0f, 1.0f, m_iFOVStart, fFOV);
|
||
}
|
||
|
||
return fFOV;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Get the current FOV used for network computations
|
||
// Choose the smallest FOV, as it will open the largest number of portals
|
||
//-----------------------------------------------------------------------------
|
||
int CBasePlayer::GetFOVForNetworking(void)
|
||
{
|
||
int nDefaultFOV;
|
||
|
||
// The vehicle's FOV wins if we're asking for a default value
|
||
if (GetVehicle())
|
||
{
|
||
CacheVehicleView();
|
||
nDefaultFOV = (m_flVehicleViewFOV == 0) ? GetDefaultFOV() : (int)m_flVehicleViewFOV;
|
||
}
|
||
else
|
||
{
|
||
nDefaultFOV = GetDefaultFOV();
|
||
}
|
||
|
||
int fFOV = (m_iFOV == 0) ? nDefaultFOV : m_iFOV;
|
||
|
||
// If it's immediate, just do it
|
||
if (m_Local.m_flFOVRate == 0.0f)
|
||
return fFOV;
|
||
|
||
if (gpGlobals->curtime - m_flFOVTime < m_Local.m_flFOVRate)
|
||
{
|
||
fFOV = MIN(fFOV, m_iFOVStart);
|
||
}
|
||
return fFOV;
|
||
}
|
||
|
||
|
||
float CBasePlayer::GetFOVDistanceAdjustFactorForNetworking()
|
||
{
|
||
float defaultFOV = (float)GetDefaultFOV();
|
||
float localFOV = (float)GetFOVForNetworking();
|
||
|
||
if (localFOV == defaultFOV || defaultFOV < 0.001f)
|
||
return 1.0f;
|
||
|
||
// If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
|
||
// shorted accordingly
|
||
return localFOV / defaultFOV;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Sets the default FOV for the player if nothing else is going on
|
||
// Input : FOV - the new base FOV for this player
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SetDefaultFOV(int FOV)
|
||
{
|
||
m_iDefaultFOV = (FOV == 0) ? g_pGameRules->DefaultFOV() : FOV;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: // static func
|
||
// Input : set -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ModifyOrAppendPlayerCriteria(AI_CriteriaSet& set)
|
||
{
|
||
// Append our health
|
||
set.AppendCriteria("playerhealth", UTIL_VarArgs("%i", GetHealth()));
|
||
float healthfrac = 0.0f;
|
||
if (GetMaxHealth() > 0)
|
||
{
|
||
healthfrac = (float)GetHealth() / (float)GetMaxHealth();
|
||
}
|
||
|
||
set.AppendCriteria("playerhealthfrac", UTIL_VarArgs("%.3f", healthfrac));
|
||
|
||
CBaseCombatWeapon *weapon = GetActiveWeapon();
|
||
if (weapon)
|
||
{
|
||
set.AppendCriteria("playerweapon", weapon->GetClassname());
|
||
}
|
||
else
|
||
{
|
||
set.AppendCriteria("playerweapon", "none");
|
||
}
|
||
|
||
// Append current activity name
|
||
set.AppendCriteria("playeractivity", CAI_BaseNPC::GetActivityName(GetActivity()));
|
||
|
||
set.AppendCriteria("playerspeed", UTIL_VarArgs("%.3f", GetAbsVelocity().Length()));
|
||
|
||
AppendContextToCriteria(set, "player");
|
||
}
|
||
|
||
|
||
const QAngle& CBasePlayer::GetPunchAngle()
|
||
{
|
||
return m_Local.m_vecPunchAngle.Get();
|
||
}
|
||
|
||
|
||
void CBasePlayer::SetPunchAngle(const QAngle &punchAngle)
|
||
{
|
||
m_Local.m_vecPunchAngle = punchAngle;
|
||
|
||
if (IsAlive())
|
||
{
|
||
int index = entindex();
|
||
|
||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||
{
|
||
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
|
||
|
||
if (pPlayer && i != index && pPlayer->GetObserverTarget() == this && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE)
|
||
{
|
||
pPlayer->SetPunchAngle(punchAngle);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Apply a movement constraint to the player
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ActivateMovementConstraint(CBaseEntity *pEntity, const Vector &vecCenter, float flRadius, float flConstraintWidth, float flSpeedFactor)
|
||
{
|
||
m_hConstraintEntity = pEntity;
|
||
m_vecConstraintCenter = vecCenter;
|
||
m_flConstraintRadius = flRadius;
|
||
m_flConstraintWidth = flConstraintWidth;
|
||
m_flConstraintSpeedFactor = flSpeedFactor;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::DeactivateMovementConstraint()
|
||
{
|
||
m_hConstraintEntity = NULL;
|
||
m_flConstraintRadius = 0.0f;
|
||
m_vecConstraintCenter = vec3_origin;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Perhaps a poorly-named function. This function traces against the supplied
|
||
// NPC's hitboxes (instead of hull). If the trace hits a different NPC, the
|
||
// new NPC is selected. Otherwise, the supplied NPC is determined to be the
|
||
// one the citizen wants. This function allows the selection of a citizen over
|
||
// another citizen's shoulder, which is impossible without tracing against
|
||
// hitboxes instead of the hull (sjb)
|
||
//-----------------------------------------------------------------------------
|
||
CBaseEntity *CBasePlayer::DoubleCheckUseNPC(CBaseEntity *pNPC, const Vector &vecSrc, const Vector &vecDir)
|
||
{
|
||
trace_t tr;
|
||
|
||
UTIL_TraceLine(vecSrc, vecSrc + vecDir * 1024, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr);
|
||
|
||
if (tr.m_pEnt != NULL && tr.m_pEnt->MyNPCPointer() && tr.m_pEnt != pNPC)
|
||
{
|
||
// Player is selecting a different NPC through some negative space
|
||
// in the first NPC's hitboxes (between legs, over shoulder, etc).
|
||
return tr.m_pEnt;
|
||
}
|
||
|
||
return pNPC;
|
||
}
|
||
|
||
|
||
bool CBasePlayer::IsBot() const
|
||
{
|
||
return (GetFlags() & FL_FAKECLIENT) != 0;
|
||
}
|
||
|
||
bool CBasePlayer::IsFakeClient() const
|
||
{
|
||
return (GetFlags() & FL_FAKECLIENT) != 0;
|
||
}
|
||
|
||
void CBasePlayer::UpdateViewModelSkin()
|
||
{
|
||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||
if (pWeapon)
|
||
pWeapon->SetSkin(pWeapon->iVMSkin, !m_Local.m_bWearingSuit);
|
||
}
|
||
|
||
void CBasePlayer::EquipSuit(bool bPlayEffects)
|
||
{
|
||
m_Local.m_bWearingSuit = true;
|
||
|
||
ConVarRef oc_player_allow_kick("oc_player_allow_kick");
|
||
|
||
if (oc_player_allow_kick.GetBool())
|
||
UTIL_HudHintText(this, "#OC_PlayerKickSystem");
|
||
|
||
UpdateViewModelSkin();
|
||
}
|
||
|
||
void CBasePlayer::RemoveSuit(void)
|
||
{
|
||
m_Local.m_bWearingSuit = false;
|
||
|
||
UpdateViewModelSkin();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &tr -
|
||
// nDamageType -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::DoImpactEffect(trace_t &tr, int nDamageType)
|
||
{
|
||
if (GetActiveWeapon())
|
||
{
|
||
GetActiveWeapon()->DoImpactEffect(tr, nDamageType);
|
||
return;
|
||
}
|
||
|
||
BaseClass::DoImpactEffect(tr, nDamageType);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InputSetHealth(inputdata_t &inputdata)
|
||
{
|
||
int iNewHealth = inputdata.value.Int();
|
||
int iDelta = abs(GetHealth() - iNewHealth);
|
||
if (iNewHealth > GetHealth())
|
||
{
|
||
TakeHealth(iDelta, DMG_GENERIC);
|
||
}
|
||
else if (iNewHealth < GetHealth())
|
||
{
|
||
// Strip off and restore armor so that it doesn't absorb any of this damage.
|
||
int armor = m_ArmorValue;
|
||
m_ArmorValue = 0;
|
||
TakeDamage(CTakeDamageInfo(this, this, iDelta, DMG_GENERIC));
|
||
m_ArmorValue = armor;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InputHandleMapEvent(inputdata_t &inputdata)
|
||
{
|
||
Internal_HandleMapEvent(inputdata);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Hides or displays the HUD
|
||
// Input : &inputdata -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InputSetHUDVisibility(inputdata_t &inputdata)
|
||
{
|
||
bool bEnable = inputdata.value.Bool();
|
||
|
||
if (bEnable)
|
||
{
|
||
m_Local.m_iHideHUD &= ~HIDEHUD_ALL;
|
||
}
|
||
else
|
||
{
|
||
m_Local.m_iHideHUD |= HIDEHUD_ALL;
|
||
}
|
||
}
|
||
|
||
|
||
#ifdef MAPBASE
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : &inputdata -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InputSetSuppressAttacks(inputdata_t &inputdata)
|
||
{
|
||
inputdata.value.Bool() ?
|
||
AddSpawnFlags(SF_PLAYER_SUPPRESS_FIRING) :
|
||
RemoveSpawnFlags(SF_PLAYER_SUPPRESS_FIRING);
|
||
}
|
||
#endif
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Set the fog controller data per player.
|
||
// Input : &inputdata -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InputSetFogController(inputdata_t &inputdata)
|
||
{
|
||
// Find the fog controller with the given name.
|
||
CFogController *pFogController = dynamic_cast<CFogController*>(gEntList.FindEntityByName(NULL, inputdata.value.String()));
|
||
if (pFogController)
|
||
{
|
||
m_Local.m_PlayerFog.m_hCtrl.Set(pFogController);
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::InitFogController(void)
|
||
{
|
||
// Setup with the default master controller.
|
||
m_Local.m_PlayerFog.m_hCtrl = FogSystem()->GetMasterFogController();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
// Input : *pEntity -
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SetViewEntity(CBaseEntity *pEntity)
|
||
{
|
||
m_hViewEntity = pEntity;
|
||
|
||
if (m_hViewEntity)
|
||
{
|
||
engine->SetView(edict(), m_hViewEntity->edict());
|
||
}
|
||
else
|
||
{
|
||
engine->SetView(edict(), edict());
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Looks at the player's reserve ammo and also all his weapons for any ammo
|
||
// of the specified type
|
||
// Input : nAmmoIndex - ammo to look for
|
||
// Output : Returns true on success, false on failure.
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::HasAnyAmmoOfType(int nAmmoIndex)
|
||
{
|
||
// Must be a valid index
|
||
if (nAmmoIndex < 0)
|
||
return false;
|
||
|
||
// If we have some in reserve, we're already done
|
||
if (GetAmmoCount(nAmmoIndex))
|
||
return true;
|
||
|
||
CBaseCombatWeapon *pWeapon;
|
||
|
||
// Check all held weapons
|
||
for (int i = 0; i < MAX_WEAPONS; i++)
|
||
{
|
||
pWeapon = GetWeapon(i);
|
||
|
||
if (!pWeapon)
|
||
continue;
|
||
|
||
// We must use clips and use this sort of ammo
|
||
if (pWeapon->UsesClipsForAmmo1() && pWeapon->GetPrimaryAmmoType() == nAmmoIndex)
|
||
{
|
||
// If we have any ammo, we're done
|
||
if (pWeapon->HasPrimaryAmmo())
|
||
return true;
|
||
}
|
||
|
||
// We'll check both clips for the same ammo type, just in case
|
||
if (pWeapon->UsesClipsForAmmo2() && pWeapon->GetSecondaryAmmoType() == nAmmoIndex)
|
||
{
|
||
if (pWeapon->HasSecondaryAmmo())
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// We're completely without this type of ammo
|
||
return false;
|
||
}
|
||
|
||
bool CBasePlayer::HandleVoteCommands(const CCommand &args)
|
||
{
|
||
if (g_voteController == NULL)
|
||
return false;
|
||
|
||
if (FStrEq(args[0], "Vote"))
|
||
{
|
||
if (args.ArgC() < 2)
|
||
return true;
|
||
|
||
const char *arg2 = args[1];
|
||
char szResultString[MAX_COMMAND_LENGTH];
|
||
|
||
CVoteController::TryCastVoteResult nTryResult = g_voteController->TryCastVote(entindex(), arg2);
|
||
switch (nTryResult)
|
||
{
|
||
case CVoteController::CAST_OK:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Voting %s.\n", arg2);
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_SERVER_DISABLE:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: server disabled.\n");
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_NO_ACTIVE_ISSUE:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "A vote has not been called.\n");
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_TEAM_RESTRICTED:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: team restricted.\n");
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_NO_CHANGES:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: no changing vote.\n");
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_DUPLICATE:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: already voting %s.\n", arg2);
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_VOTE_CLOSED:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: voting closed.\n");
|
||
break;
|
||
}
|
||
case CVoteController::CAST_FAIL_SYSTEM_ERROR:
|
||
default:
|
||
{
|
||
Q_snprintf(szResultString, MAX_COMMAND_LENGTH, "Vote failed: system error.\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
DevMsg("%s", szResultString);
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// return a string version of the players network (i.e steam) ID.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
const char *CBasePlayer::GetNetworkIDString()
|
||
{
|
||
const char *pStr = engine->GetPlayerNetworkIDString(edict());
|
||
Q_strncpy(m_szNetworkIDString, pStr ? pStr : "", sizeof(m_szNetworkIDString));
|
||
return m_szNetworkIDString;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Assign the player a name
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::SetPlayerName(const char *name)
|
||
{
|
||
Assert(name);
|
||
|
||
if (name)
|
||
{
|
||
Assert(strlen(name) > 0);
|
||
|
||
Q_strncpy(m_szNetname, name, sizeof(m_szNetname));
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// sets the "don't autokick me" flag on a player
|
||
//-----------------------------------------------------------------------------
|
||
class DisableAutokick
|
||
{
|
||
public:
|
||
DisableAutokick(int userID)
|
||
{
|
||
m_userID = userID;
|
||
}
|
||
|
||
bool operator()(CBasePlayer *player)
|
||
{
|
||
if (player->GetUserID() == m_userID)
|
||
{
|
||
Msg("autokick is disabled for %s\n", player->GetPlayerName());
|
||
player->DisableAutoKick(true);
|
||
return false; // don't need to check other players
|
||
}
|
||
|
||
return true; // keep looking at other players
|
||
}
|
||
|
||
private:
|
||
int m_userID;
|
||
};
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// sets the "don't autokick me" flag on a player
|
||
//-----------------------------------------------------------------------------
|
||
CON_COMMAND(mp_disable_autokick, "Prevents a userid from being auto-kicked")
|
||
{
|
||
if (!UTIL_IsCommandIssuedByServerAdmin())
|
||
return;
|
||
|
||
if (args.ArgC() != 2)
|
||
{
|
||
Msg("Usage: mp_disable_autokick <userid>\n");
|
||
return;
|
||
}
|
||
|
||
int userID = atoi(args[1]);
|
||
DisableAutokick disable(userID);
|
||
ForEachPlayer(disable);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose: Toggle between the duck being on and off
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::ToggleDuck(void)
|
||
{
|
||
// Toggle the state
|
||
m_bDuckToggled = !m_bDuckToggled;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Just tells us how far the stick is from the center. No directional info
|
||
//-----------------------------------------------------------------------------
|
||
float CBasePlayer::GetStickDist()
|
||
{
|
||
Vector2D controlStick;
|
||
|
||
controlStick.x = m_flForwardMove;
|
||
controlStick.y = m_flSideMove;
|
||
|
||
return controlStick.Length();
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
void CBasePlayer::HandleAnimEvent(animevent_t *pEvent)
|
||
{
|
||
|
||
if ((pEvent->type & AE_TYPE_NEWEVENTSYSTEM) && (pEvent->type & AE_TYPE_SERVER))
|
||
{
|
||
if (pEvent->event == AE_RAGDOLL)
|
||
{
|
||
// Convert to ragdoll immediately
|
||
CreateRagdollEntity();
|
||
BecomeRagdollOnClient(vec3_origin);
|
||
|
||
// Force the player to start death thinking
|
||
SetThink(&CBasePlayer::PlayerDeathThink);
|
||
SetNextThink(gpGlobals->curtime + 0.1f);
|
||
return;
|
||
}
|
||
}
|
||
|
||
BaseClass::HandleAnimEvent(pEvent);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// CPlayerInfo functions (simple passthroughts to get around the CBasePlayer multiple inheritence limitation)
|
||
//-----------------------------------------------------------------------------
|
||
const char *CPlayerInfo::GetName()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetPlayerName();
|
||
}
|
||
|
||
int CPlayerInfo::GetUserID()
|
||
{
|
||
Assert(m_pParent);
|
||
return engine->GetPlayerUserId(m_pParent->edict());
|
||
}
|
||
|
||
const char *CPlayerInfo::GetNetworkIDString()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetNetworkIDString();
|
||
}
|
||
|
||
int CPlayerInfo::GetTeamIndex()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetTeamNumber();
|
||
}
|
||
|
||
void CPlayerInfo::ChangeTeam(int iTeamNum)
|
||
{
|
||
Assert(m_pParent);
|
||
m_pParent->ChangeTeam(iTeamNum);
|
||
}
|
||
|
||
int CPlayerInfo::GetFragCount()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->FragCount();
|
||
}
|
||
|
||
int CPlayerInfo::GetDeathCount()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->DeathCount();
|
||
}
|
||
|
||
bool CPlayerInfo::IsConnected()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsConnected();
|
||
}
|
||
|
||
int CPlayerInfo::GetArmorValue()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->ArmorValue();
|
||
}
|
||
|
||
bool CPlayerInfo::IsHLTV()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsHLTV();
|
||
}
|
||
|
||
bool CPlayerInfo::IsReplay()
|
||
{
|
||
#ifdef TF_DLL // FIXME: Need run-time check for whether replay is enabled
|
||
Assert(m_pParent);
|
||
return m_pParent->IsReplay();
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
|
||
bool CPlayerInfo::IsPlayer()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsPlayer();
|
||
}
|
||
|
||
bool CPlayerInfo::IsFakeClient()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsFakeClient();
|
||
}
|
||
|
||
bool CPlayerInfo::IsDead()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsDead();
|
||
}
|
||
|
||
bool CPlayerInfo::IsInAVehicle()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsInAVehicle();
|
||
}
|
||
|
||
bool CPlayerInfo::IsObserver()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->IsObserver();
|
||
}
|
||
|
||
const Vector CPlayerInfo::GetAbsOrigin()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetAbsOrigin();
|
||
}
|
||
|
||
const QAngle CPlayerInfo::GetAbsAngles()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetAbsAngles();
|
||
}
|
||
|
||
const Vector CPlayerInfo::GetPlayerMins()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetPlayerMins();
|
||
}
|
||
|
||
const Vector CPlayerInfo::GetPlayerMaxs()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetPlayerMaxs();
|
||
}
|
||
|
||
const char *CPlayerInfo::GetWeaponName()
|
||
{
|
||
Assert(m_pParent);
|
||
CBaseCombatWeapon *weap = m_pParent->GetActiveWeapon();
|
||
if (!weap)
|
||
{
|
||
return NULL;
|
||
}
|
||
return weap->GetName();
|
||
}
|
||
|
||
const char *CPlayerInfo::GetModelName()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetModelName().ToCStr();
|
||
}
|
||
|
||
const int CPlayerInfo::GetHealth()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetHealth();
|
||
}
|
||
|
||
const int CPlayerInfo::GetMaxHealth()
|
||
{
|
||
Assert(m_pParent);
|
||
return m_pParent->GetMaxHealth();
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
void CPlayerInfo::SetAbsOrigin(Vector & vec)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
m_pParent->SetAbsOrigin(vec);
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::SetAbsAngles(QAngle & ang)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
m_pParent->SetAbsAngles(ang);
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::RemoveAllItems(bool removeSuit)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
m_pParent->RemoveAllItems(removeSuit);
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::SetActiveWeapon(const char *WeaponName)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
CBaseCombatWeapon *weap = m_pParent->Weapon_Create(WeaponName);
|
||
if (weap)
|
||
{
|
||
m_pParent->Weapon_Equip(weap);
|
||
m_pParent->Weapon_Switch(weap);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::SetLocalOrigin(const Vector& origin)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
m_pParent->SetLocalOrigin(origin);
|
||
}
|
||
}
|
||
|
||
const Vector CPlayerInfo::GetLocalOrigin(void)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
Vector origin = m_pParent->GetLocalOrigin();
|
||
return origin;
|
||
}
|
||
else
|
||
{
|
||
return Vector(0, 0, 0);
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::SetLocalAngles(const QAngle& angles)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
m_pParent->SetLocalAngles(angles);
|
||
}
|
||
}
|
||
|
||
const QAngle CPlayerInfo::GetLocalAngles(void)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
return m_pParent->GetLocalAngles();
|
||
}
|
||
else
|
||
{
|
||
return QAngle();
|
||
}
|
||
}
|
||
|
||
bool CPlayerInfo::IsEFlagSet(int nEFlagMask)
|
||
{
|
||
Assert(m_pParent);
|
||
if (m_pParent->IsBot())
|
||
{
|
||
return m_pParent->IsEFlagSet(nEFlagMask);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void CPlayerInfo::RunPlayerMove(CBotCmd *ucmd)
|
||
{
|
||
if (m_pParent->IsBot())
|
||
{
|
||
Assert(m_pParent);
|
||
CUserCmd cmd;
|
||
cmd.buttons = ucmd->buttons;
|
||
cmd.command_number = ucmd->command_number;
|
||
cmd.forwardmove = ucmd->forwardmove;
|
||
cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
|
||
cmd.impulse = ucmd->impulse;
|
||
cmd.mousedx = ucmd->mousedx;
|
||
cmd.mousedy = ucmd->mousedy;
|
||
cmd.random_seed = ucmd->random_seed;
|
||
cmd.sidemove = ucmd->sidemove;
|
||
cmd.tick_count = ucmd->tick_count;
|
||
cmd.upmove = ucmd->upmove;
|
||
cmd.viewangles = ucmd->viewangles;
|
||
cmd.weaponselect = ucmd->weaponselect;
|
||
cmd.weaponsubtype = ucmd->weaponsubtype;
|
||
|
||
// Store off the globals.. they're gonna get whacked
|
||
float flOldFrametime = gpGlobals->frametime;
|
||
float flOldCurtime = gpGlobals->curtime;
|
||
|
||
m_pParent->SetTimeBase(gpGlobals->curtime);
|
||
|
||
MoveHelperServer()->SetHost(m_pParent);
|
||
m_pParent->PlayerRunCommand(&cmd, MoveHelperServer());
|
||
|
||
// save off the last good usercmd
|
||
m_pParent->SetLastUserCommand(cmd);
|
||
|
||
// Clear out any fixangle that has been set
|
||
m_pParent->pl.fixangle = FIXANGLE_NONE;
|
||
|
||
// Restore the globals..
|
||
gpGlobals->frametime = flOldFrametime;
|
||
gpGlobals->curtime = flOldCurtime;
|
||
MoveHelperServer()->SetHost(NULL);
|
||
}
|
||
}
|
||
|
||
void CPlayerInfo::SetLastUserCommand(const CBotCmd &ucmd)
|
||
{
|
||
if (m_pParent->IsBot())
|
||
{
|
||
Assert(m_pParent);
|
||
CUserCmd cmd;
|
||
cmd.buttons = ucmd.buttons;
|
||
cmd.command_number = ucmd.command_number;
|
||
cmd.forwardmove = ucmd.forwardmove;
|
||
cmd.hasbeenpredicted = ucmd.hasbeenpredicted;
|
||
cmd.impulse = ucmd.impulse;
|
||
cmd.mousedx = ucmd.mousedx;
|
||
cmd.mousedy = ucmd.mousedy;
|
||
cmd.random_seed = ucmd.random_seed;
|
||
cmd.sidemove = ucmd.sidemove;
|
||
cmd.tick_count = ucmd.tick_count;
|
||
cmd.upmove = ucmd.upmove;
|
||
cmd.viewangles = ucmd.viewangles;
|
||
cmd.weaponselect = ucmd.weaponselect;
|
||
cmd.weaponsubtype = ucmd.weaponsubtype;
|
||
|
||
m_pParent->SetLastUserCommand(cmd);
|
||
}
|
||
}
|
||
|
||
|
||
CBotCmd CPlayerInfo::GetLastUserCommand()
|
||
{
|
||
CBotCmd cmd;
|
||
const CUserCmd *ucmd = m_pParent->GetLastUserCommand();
|
||
if (ucmd)
|
||
{
|
||
cmd.buttons = ucmd->buttons;
|
||
cmd.command_number = ucmd->command_number;
|
||
cmd.forwardmove = ucmd->forwardmove;
|
||
cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
|
||
cmd.impulse = ucmd->impulse;
|
||
cmd.mousedx = ucmd->mousedx;
|
||
cmd.mousedy = ucmd->mousedy;
|
||
cmd.random_seed = ucmd->random_seed;
|
||
cmd.sidemove = ucmd->sidemove;
|
||
cmd.tick_count = ucmd->tick_count;
|
||
cmd.upmove = ucmd->upmove;
|
||
cmd.viewangles = ucmd->viewangles;
|
||
cmd.weaponselect = ucmd->weaponselect;
|
||
cmd.weaponsubtype = ucmd->weaponsubtype;
|
||
}
|
||
return cmd;
|
||
}
|
||
|
||
// Notify that I've killed some other entity. (called from Victim's Event_Killed).
|
||
void CBasePlayer::Event_KilledOther(CBaseEntity *pVictim, const CTakeDamageInfo &info)
|
||
{
|
||
BaseClass::Event_KilledOther(pVictim, info);
|
||
if (pVictim != this)
|
||
{
|
||
gamestats->Event_PlayerKilledOther(this, pVictim, info);
|
||
}
|
||
else
|
||
{
|
||
gamestats->Event_PlayerSuicide(this);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::SetModel(const char *szModelName)
|
||
{
|
||
BaseClass::SetModel(szModelName);
|
||
m_nBodyPitchPoseParam = LookupPoseParameter("body_pitch");
|
||
}
|
||
|
||
void CBasePlayer::SetBodyPitch(float flPitch)
|
||
{
|
||
if (m_nBodyPitchPoseParam >= 0)
|
||
{
|
||
SetPoseParameter(m_nBodyPitchPoseParam, flPitch);
|
||
}
|
||
}
|
||
|
||
void CBasePlayer::AdjustDrownDmg(int nAmount)
|
||
{
|
||
m_idrowndmg += nAmount;
|
||
if (m_idrowndmg < m_idrownrestored)
|
||
{
|
||
m_idrowndmg = m_idrownrestored;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#if !defined(NO_STEAM)
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
bool CBasePlayer::GetSteamID(CSteamID *pID)
|
||
{
|
||
const CSteamID *pClientID = engine->GetClientSteamID(edict());
|
||
if (pClientID)
|
||
{
|
||
*pID = *pClientID;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Purpose:
|
||
//-----------------------------------------------------------------------------
|
||
uint64 CBasePlayer::GetSteamIDAsUInt64(void)
|
||
{
|
||
CSteamID steamIDForPlayer;
|
||
if (GetSteamID(&steamIDForPlayer))
|
||
return steamIDForPlayer.ConvertToUint64();
|
||
return 0;
|
||
}
|
||
#endif // NO_STEAM
|