2013-08-30 20:34:05 +00:00
/***
*
* Copyright ( c ) 1999 , 2000 Valve LLC . All rights reserved .
*
* This product contains software technology licensed from Id
* Software , Inc . ( " Id Technology " ) . Id Technology ( c ) 1996 Id Software , Inc .
* All Rights Reserved .
*
* Use , distribution , and modification of this source code and / or resulting
* object code is restricted to non - commercial enhancements to products from
* Valve LLC . All other use , distribution , or modification is prohibited
* without written permission from Valve LLC .
*
* * * */
/*
= = = = = player . cpp = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
functions dealing with the player
*/
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "player.h"
# include "trains.h"
# include "nodes.h"
# include "weapons.h"
# include "soundent.h"
# include "monsters.h"
# include "../engine/shake.h"
# include "decals.h"
# include "gamerules.h"
# include "animation.h"
# include "discwar.h"
# include "disc_objects.h"
# include "disc_arena.h"
// #define DUCKFIX
extern DLL_GLOBAL ULONG g_ulModelIndexPlayer ;
extern DLL_GLOBAL BOOL g_fGameOver ;
extern DLL_GLOBAL BOOL g_fDrawLines ;
int gEvilImpulse101 ;
extern DLL_GLOBAL int g_iSkillLevel , gDisplayTitle ;
BOOL gInitHUD = FALSE ;
extern void CopyToBodyQue ( entvars_t * pev ) ;
extern void respawn ( entvars_t * pev , BOOL fCopyCorpse ) ;
extern Vector VecBModelOrigin ( entvars_t * pevBModel ) ;
extern edict_t * EntSelectSpawnPoint ( CBaseEntity * pPlayer ) ;
int MapTextureTypeStepType ( char chTextureType ) ;
entvars_t * g_pevLastInflictor ; // Set in combat.cpp. Used to pass the damage inflictor for death messages.
// Better solution: Add as parameter to all Killed() functions.
// the world node graph
extern CGraph WorldGraph ;
# define PLAYER_WALLJUMP_SPEED 300 // how fast we can spring off walls
# define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump
# define TRAIN_ACTIVE 0x80
# define TRAIN_NEW 0xc0
# define TRAIN_OFF 0x00
# define TRAIN_NEUTRAL 0x01
# define TRAIN_SLOW 0x02
# define TRAIN_MEDIUM 0x03
# define TRAIN_FAST 0x04
# define TRAIN_BACK 0x05
# define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes
# define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit)
//#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 )
// Global Savedata for player
TYPEDESCRIPTION CBasePlayer : : m_playerSaveData [ ] =
{
DEFINE_FIELD ( CBasePlayer , m_flFlashLightTime , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_iFlashBattery , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_afButtonLast , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_afButtonPressed , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_afButtonReleased , FIELD_INTEGER ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgItems , FIELD_INTEGER , MAX_ITEMS ) ,
DEFINE_FIELD ( CBasePlayer , m_afPhysicsFlags , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_flTimeStepSound , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_flTimeWeaponIdle , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_flSwimTime , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_flDuckTime , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_flWallJumpTime , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_flSuitUpdate , FIELD_TIME ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgSuitPlayList , FIELD_INTEGER , CSUITPLAYLIST ) ,
DEFINE_FIELD ( CBasePlayer , m_iSuitPlayNext , FIELD_INTEGER ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgiSuitNoRepeat , FIELD_INTEGER , CSUITNOREPEAT ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgflSuitNoRepeatTime , FIELD_TIME , CSUITNOREPEAT ) ,
DEFINE_FIELD ( CBasePlayer , m_lastDamageAmount , FIELD_INTEGER ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgpPlayerItems , FIELD_CLASSPTR , MAX_ITEM_TYPES ) ,
DEFINE_FIELD ( CBasePlayer , m_pActiveItem , FIELD_CLASSPTR ) ,
DEFINE_FIELD ( CBasePlayer , m_pLastItem , FIELD_CLASSPTR ) ,
DEFINE_ARRAY ( CBasePlayer , m_rgAmmo , FIELD_INTEGER , MAX_AMMO_SLOTS ) ,
DEFINE_FIELD ( CBasePlayer , m_idrowndmg , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_idrownrestored , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_tSneaking , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_iTrain , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_bitsHUDDamage , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_flFallVelocity , FIELD_FLOAT ) ,
DEFINE_FIELD ( CBasePlayer , m_iTargetVolume , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_iWeaponVolume , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_iExtraSoundTypes , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_iWeaponFlash , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_fLongJump , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( CBasePlayer , m_fInitHUD , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( CBasePlayer , m_tbdPrev , FIELD_TIME ) ,
DEFINE_FIELD ( CBasePlayer , m_pTank , FIELD_EHANDLE ) ,
DEFINE_FIELD ( CBasePlayer , m_iHideHUD , FIELD_INTEGER ) ,
DEFINE_FIELD ( CBasePlayer , m_iFOV , FIELD_INTEGER ) ,
//DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games
//DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games
//DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ),
//DEFINE_FIELD( CBasePlayer, m_fKnownItem, FIELD_INTEGER ), // reset to zero on load
//DEFINE_FIELD( CBasePlayer, m_iPlayerSound, FIELD_INTEGER ), // Don't restore, set in Precache()
//DEFINE_FIELD( CBasePlayer, m_pentSndLast, FIELD_EDICT ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_flSndRoomtype, FIELD_FLOAT ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_flSndRange, FIELD_FLOAT ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_fNewAmmo, FIELD_INTEGER ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_flgeigerRange, FIELD_FLOAT ), // Don't restore, reset in Precache()
//DEFINE_FIELD( CBasePlayer, m_flgeigerDelay, FIELD_FLOAT ), // Don't restore, reset in Precache()
//DEFINE_FIELD( CBasePlayer, m_igeigerRangePrev, FIELD_FLOAT ), // Don't restore, reset in Precache()
//DEFINE_FIELD( CBasePlayer, m_iStepLeft, FIELD_INTEGER ), // Don't need to restore
//DEFINE_ARRAY( CBasePlayer, m_szTextureName, FIELD_CHARACTER, CBTEXTURENAMEMAX ), // Don't need to restore
//DEFINE_FIELD( CBasePlayer, m_chTextureType, FIELD_CHARACTER ), // Don't need to restore
//DEFINE_FIELD( CBasePlayer, m_fNoPlayerSound, FIELD_BOOLEAN ), // Don't need to restore, debug
//DEFINE_FIELD( CBasePlayer, m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore
//DEFINE_FIELD( CBasePlayer, m_iClientHealth, FIELD_INTEGER ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_fWeapon, FIELD_BOOLEAN ), // Don't restore, client needs reset
//DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't restore, depends on server message after spawning and only matters in multiplayer
//DEFINE_FIELD( CBasePlayer, m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed
//DEFINE_ARRAY( CBasePlayer, m_rgAmmoLast, FIELD_INTEGER, MAX_AMMO_SLOTS ), // Don't need to restore
//DEFINE_FIELD( CBasePlayer, m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore
//DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't need to restore
} ;
int giPrecacheGrunt = 0 ;
int gmsgShake = 0 ;
int gmsgFade = 0 ;
int gmsgSelAmmo = 0 ;
int gmsgFlashlight = 0 ;
int gmsgFlashBattery = 0 ;
int gmsgResetHUD = 0 ;
int gmsgInitHUD = 0 ;
int gmsgShowGameTitle = 0 ;
int gmsgCurWeapon = 0 ;
int gmsgHealth = 0 ;
int gmsgDamage = 0 ;
int gmsgBattery = 0 ;
int gmsgTrain = 0 ;
int gmsgLogo = 0 ;
int gmsgWeaponList = 0 ;
int gmsgAmmoX = 0 ;
int gmsgHudText = 0 ;
int gmsgDeathMsg = 0 ;
int gmsgScoreInfo = 0 ;
int gmsgTeamInfo = 0 ;
int gmsgTeamScore = 0 ;
int gmsgGameMode = 0 ;
int gmsgMOTD = 0 ;
int gmsgAmmoPickup = 0 ;
int gmsgWeapPickup = 0 ;
int gmsgItemPickup = 0 ;
int gmsgHideWeapon = 0 ;
int gmsgSetCurWeap = 0 ;
int gmsgSayText = 0 ;
int gmsgTextMsg = 0 ;
int gmsgSetFOV = 0 ;
int gmsgShowMenu = 0 ;
int gmsgGeigerRange = 0 ;
int gmsgSpectator = 0 ;
int gmsgStartRnd = 0 ;
int gmsgEndRnd = 0 ;
int gmsgPowerup = 0 ;
int gmsgReward = 0 ;
int gmsgFrozen = 0 ;
void LinkUserMessages ( void )
{
// Already taken care of?
if ( gmsgSelAmmo )
{
return ;
}
gmsgSelAmmo = REG_USER_MSG ( " SelAmmo " , sizeof ( SelAmmo ) ) ;
gmsgCurWeapon = REG_USER_MSG ( " CurWeapon " , 3 ) ;
gmsgGeigerRange = REG_USER_MSG ( " Geiger " , 1 ) ;
gmsgFlashlight = REG_USER_MSG ( " Flashlight " , 2 ) ;
gmsgFlashBattery = REG_USER_MSG ( " FlashBat " , 1 ) ;
gmsgHealth = REG_USER_MSG ( " Health " , 1 ) ;
gmsgDamage = REG_USER_MSG ( " Damage " , 12 ) ;
gmsgBattery = REG_USER_MSG ( " Battery " , 2 ) ;
gmsgTrain = REG_USER_MSG ( " Train " , 1 ) ;
gmsgHudText = REG_USER_MSG ( " HudText " , - 1 ) ;
gmsgSayText = REG_USER_MSG ( " SayText " , - 1 ) ;
gmsgTextMsg = REG_USER_MSG ( " TextMsg " , - 1 ) ;
gmsgWeaponList = REG_USER_MSG ( " WeaponList " , - 1 ) ;
gmsgResetHUD = REG_USER_MSG ( " ResetHUD " , 1 ) ; // called every respawn
gmsgInitHUD = REG_USER_MSG ( " InitHUD " , 0 ) ; // called every time a new player joins the server
gmsgShowGameTitle = REG_USER_MSG ( " GameTitle " , 1 ) ;
gmsgDeathMsg = REG_USER_MSG ( " DeathMsg " , - 1 ) ;
gmsgScoreInfo = REG_USER_MSG ( " ScoreInfo " , 9 ) ;
gmsgTeamInfo = REG_USER_MSG ( " TeamInfo " , - 1 ) ; // sets the name of a player's team
gmsgTeamScore = REG_USER_MSG ( " TeamScore " , - 1 ) ; // sets the score of a team on the scoreboard
gmsgGameMode = REG_USER_MSG ( " GameMode " , 1 ) ;
gmsgMOTD = REG_USER_MSG ( " MOTD " , - 1 ) ;
gmsgAmmoPickup = REG_USER_MSG ( " AmmoPickup " , 2 ) ;
gmsgWeapPickup = REG_USER_MSG ( " WeapPickup " , 1 ) ;
gmsgItemPickup = REG_USER_MSG ( " ItemPickup " , - 1 ) ;
gmsgHideWeapon = REG_USER_MSG ( " HideWeapon " , 1 ) ;
gmsgSetFOV = REG_USER_MSG ( " SetFOV " , 1 ) ;
gmsgShowMenu = REG_USER_MSG ( " ShowMenu " , - 1 ) ;
gmsgShake = REG_USER_MSG ( " ScreenShake " , sizeof ( ScreenShake ) ) ;
gmsgFade = REG_USER_MSG ( " ScreenFade " , sizeof ( ScreenFade ) ) ;
gmsgAmmoX = REG_USER_MSG ( " AmmoX " , 2 ) ;
gmsgSpectator = REG_USER_MSG ( " Spectator " , 2 ) ;
// Discwar
gmsgStartRnd = REG_USER_MSG ( " StartRnd " , - 1 ) ;
gmsgEndRnd = REG_USER_MSG ( " EndRnd " , - 1 ) ;
gmsgPowerup = REG_USER_MSG ( " Powerup " , 1 ) ;
gmsgReward = REG_USER_MSG ( " Reward " , 2 ) ;
gmsgFrozen = REG_USER_MSG ( " Frozen " , 1 ) ;
}
LINK_ENTITY_TO_CLASS ( player , CBasePlayer ) ;
void CBasePlayer : : Pain ( void )
{
float flRndSound ; //sound randomizer
flRndSound = RANDOM_FLOAT ( 0 , 1 ) ;
if ( flRndSound < = 0.33 )
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/pl_pain5.wav " , 1 , ATTN_NORM ) ;
else if ( flRndSound < = 0.66 )
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/pl_pain6.wav " , 1 , ATTN_NORM ) ;
else
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/pl_pain7.wav " , 1 , ATTN_NORM ) ;
}
/*
*
*/
Vector VecVelocityForDamage ( float flDamage )
{
Vector vec ( RANDOM_FLOAT ( - 100 , 100 ) , RANDOM_FLOAT ( - 100 , 100 ) , RANDOM_FLOAT ( 200 , 300 ) ) ;
if ( flDamage > - 50 )
vec = vec * 0.7 ;
else if ( flDamage > - 200 )
vec = vec * 2 ;
else
vec = vec * 10 ;
return vec ;
}
#if 0 /*
static void ThrowGib ( entvars_t * pev , char * szGibModel , float flDamage )
{
edict_t * pentNew = CREATE_ENTITY ( ) ;
entvars_t * pevNew = VARS ( pentNew ) ;
pevNew - > origin = pev - > origin ;
SET_MODEL ( ENT ( pevNew ) , szGibModel ) ;
UTIL_SetSize ( pevNew , g_vecZero , g_vecZero ) ;
pevNew - > velocity = VecVelocityForDamage ( flDamage ) ;
pevNew - > movetype = MOVETYPE_BOUNCE ;
pevNew - > solid = SOLID_NOT ;
pevNew - > avelocity . x = RANDOM_FLOAT ( 0 , 600 ) ;
pevNew - > avelocity . y = RANDOM_FLOAT ( 0 , 600 ) ;
pevNew - > avelocity . z = RANDOM_FLOAT ( 0 , 600 ) ;
CHANGE_METHOD ( ENT ( pevNew ) , em_think , SUB_Remove ) ;
pevNew - > ltime = gpGlobals - > time ;
pevNew - > nextthink = gpGlobals - > time + RANDOM_FLOAT ( 10 , 20 ) ;
pevNew - > frame = 0 ;
pevNew - > flags = 0 ;
}
static void ThrowHead ( entvars_t * pev , char * szGibModel , floatflDamage )
{
SET_MODEL ( ENT ( pev ) , szGibModel ) ;
pev - > frame = 0 ;
pev - > nextthink = - 1 ;
pev - > movetype = MOVETYPE_BOUNCE ;
pev - > takedamage = DAMAGE_NO ;
pev - > solid = SOLID_NOT ;
pev - > view_ofs = Vector ( 0 , 0 , 8 ) ;
UTIL_SetSize ( pev , Vector ( - 16 , - 16 , 0 ) , Vector ( 16 , 16 , 56 ) ) ;
pev - > velocity = VecVelocityForDamage ( flDamage ) ;
pev - > avelocity = RANDOM_FLOAT ( - 1 , 1 ) * Vector ( 0 , 600 , 0 ) ;
pev - > origin . z - = 24 ;
ClearBits ( pev - > flags , FL_ONGROUND ) ;
}
*/
# endif
int TrainSpeed ( int iSpeed , int iMax )
{
float fSpeed , fMax ;
int iRet = 0 ;
fMax = ( float ) iMax ;
fSpeed = iSpeed ;
fSpeed = fSpeed / fMax ;
if ( iSpeed < 0 )
iRet = TRAIN_BACK ;
else if ( iSpeed = = 0 )
iRet = TRAIN_NEUTRAL ;
else if ( fSpeed < 0.33 )
iRet = TRAIN_SLOW ;
else if ( fSpeed < 0.66 )
iRet = TRAIN_MEDIUM ;
else
iRet = TRAIN_FAST ;
return iRet ;
}
void CBasePlayer : : DeathSound ( void )
{
}
// override takehealth
// bitsDamageType indicates type of damage healed.
int CBasePlayer : : TakeHealth ( float flHealth , int bitsDamageType )
{
return CBaseMonster : : TakeHealth ( flHealth , bitsDamageType ) ;
}
Vector CBasePlayer : : GetGunPosition ( )
{
// UTIL_MakeVectors(pev->v_angle);
// m_HackedGunPos = pev->view_ofs;
Vector origin ;
origin = pev - > origin + pev - > view_ofs ;
return origin ;
}
//=========================================================
// TraceAttack
//=========================================================
void CBasePlayer : : TraceAttack ( entvars_t * pevAttacker , float flDamage , Vector vecDir , TraceResult * ptr , int bitsDamageType )
{
if ( pev - > takedamage )
{
m_LastHitGroup = ptr - > iHitgroup ;
switch ( ptr - > iHitgroup )
{
case HITGROUP_GENERIC :
break ;
case HITGROUP_HEAD :
flDamage * = gSkillData . plrHead ;
break ;
case HITGROUP_CHEST :
flDamage * = gSkillData . plrChest ;
break ;
case HITGROUP_STOMACH :
flDamage * = gSkillData . plrStomach ;
break ;
case HITGROUP_LEFTARM :
case HITGROUP_RIGHTARM :
flDamage * = gSkillData . plrArm ;
break ;
case HITGROUP_LEFTLEG :
case HITGROUP_RIGHTLEG :
flDamage * = gSkillData . plrLeg ;
break ;
default :
break ;
}
SpawnBlood ( ptr - > vecEndPos , BloodColor ( ) , flDamage ) ; // a little surface blood.
TraceBleed ( flDamage , vecDir , ptr , bitsDamageType ) ;
AddMultiDamage ( pevAttacker , this , flDamage , bitsDamageType ) ;
}
}
/*
Take some damage .
NOTE : each call to TakeDamage with bitsDamageType set to a time - based damage
type will cause the damage time countdown to be reset . Thus the ongoing effects of poison , radiation
etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC .
*/
# define ARMOR_RATIO 0.2 // Armor Takes 80% of the damage
# define ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health
int CBasePlayer : : TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
{
// Abort if its the world doing damage
//if ( ENTINDEX( ENT(pevInflictor) ) == 0 )
//return 0;
if ( pev - > takedamage = = DAMAGE_NO )
return 0 ;
// Discwar instantly kills everyone when they take damage
pev - > health = - 1 ;
g_pevLastInflictor = pevInflictor ;
if ( bitsDamageType & DMG_ALWAYSGIB )
{
Killed ( pevAttacker , GIB_ALWAYS ) ;
}
else if ( bitsDamageType & DMG_NEVERGIB )
{
Killed ( pevAttacker , GIB_NEVER ) ;
}
else
{
Killed ( pevAttacker , GIB_NORMAL ) ;
}
g_pevLastInflictor = NULL ;
return 1 ;
}
void CBasePlayer : : RemoveAllItems ( BOOL removeSuit )
{
if ( m_pActiveItem )
{
ResetAutoaim ( ) ;
m_pActiveItem - > Holster ( ) ;
m_pActiveItem = NULL ;
}
m_pLastItem = NULL ;
int i ;
CBasePlayerItem * pPendingItem ;
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
m_pActiveItem = m_rgpPlayerItems [ i ] ;
while ( m_pActiveItem )
{
pPendingItem = m_pActiveItem - > m_pNext ;
m_pActiveItem - > Drop ( ) ;
m_pActiveItem = pPendingItem ;
}
m_rgpPlayerItems [ i ] = NULL ;
}
m_pActiveItem = NULL ;
pev - > viewmodel = 0 ;
pev - > weaponmodel = 0 ;
if ( removeSuit )
pev - > weapons = 0 ;
else
pev - > weapons & = ~ WEAPON_ALLWEAPONS ;
for ( i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
m_rgAmmo [ i ] = 0 ;
UpdateClientData ( ) ;
// send Selected Weapon Message to our client
MESSAGE_BEGIN ( MSG_ONE , gmsgCurWeapon , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( 0 ) ;
MESSAGE_END ( ) ;
}
/*
* GLOBALS ASSUMED SET : g_ulModelIndexPlayer
*
* ENTITY_METHOD ( PlayerDie )
*/
void CBasePlayer : : Killed ( entvars_t * pevAttacker , int iGib )
{
CSound * pSound ;
// Discwars scoring system
if ( ( m_flLastDiscHit ! = 0 ) & & ( gpGlobals - > time < m_flLastDiscHit + MAX_SCORE_TIME_AFTER_HIT ) )
{
pevAttacker = ( ( CBaseEntity * ) m_hLastPlayerToHitMe ) - > pev ;
g_pevLastInflictor = ( ( CBaseEntity * ) m_hLastPlayerToHitMe ) - > pev ;
}
g_pGameRules - > PlayerKilled ( this , pevAttacker , g_pevLastInflictor ) ;
if ( m_pTank ! = NULL )
{
m_pTank - > Use ( this , this , USE_OFF , 0 ) ;
m_pTank = NULL ;
}
// this client isn't going to be thinking for a while, so reset the sound until they respawn
pSound = CSoundEnt : : SoundPointerForIndex ( CSoundEnt : : ClientSoundIndex ( edict ( ) ) ) ;
{
if ( pSound )
{
pSound - > Reset ( ) ;
}
}
SetAnimation ( PLAYER_DIE ) ;
m_iRespawnFrames = 0 ;
pev - > modelindex = g_ulModelIndexPlayer ; // don't use eyes
pev - > takedamage = DAMAGE_NO ;
pev - > deadflag = DEAD_DYING ;
pev - > movetype = MOVETYPE_TOSS ;
ClearBits ( pev - > flags , FL_ONGROUND ) ;
if ( pev - > velocity . z < 10 )
pev - > velocity . z + = RANDOM_FLOAT ( 0 , 300 ) ;
// clear out the suit message cache so we don't keep chattering
SetSuitUpdate ( NULL , FALSE , 0 ) ;
// send "health" update message to zero
m_iClientHealth = 0 ;
MESSAGE_BEGIN ( MSG_ONE , gmsgHealth , NULL , pev ) ;
WRITE_BYTE ( m_iClientHealth ) ;
MESSAGE_END ( ) ;
// Tell Ammo Hud that the player is dead
MESSAGE_BEGIN ( MSG_ONE , gmsgCurWeapon , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( 0XFF ) ;
WRITE_BYTE ( 0xFF ) ;
MESSAGE_END ( ) ;
// reset FOV
m_iFOV = m_iClientFOV = 0 ;
MESSAGE_BEGIN ( MSG_ONE , gmsgSetFOV , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
MESSAGE_END ( ) ;
// UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12
// UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE );
if ( ( pev - > health < - 40 & & iGib ! = GIB_NEVER ) | | iGib = = GIB_ALWAYS )
{
pev - > solid = SOLID_NOT ;
GibMonster ( ) ; // This clears pev->model
pev - > effects | = EF_NODRAW ;
// Tell the arena that this player's died
if ( m_pCurrentArena )
m_pCurrentArena - > PlayerKilled ( this ) ;
return ;
}
// Tell the arena that this player's died
if ( m_pCurrentArena )
m_pCurrentArena - > PlayerKilled ( this ) ;
DeathSound ( ) ;
pev - > angles . x = 0 ;
pev - > angles . z = 0 ;
SetThink ( & CBasePlayer : : PlayerDeathThink ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
// Tell all this player's discs to remove themselves after the 3rd bounce
edict_t * pFind = FIND_ENTITY_BY_CLASSNAME ( NULL , " disc " ) ;
while ( ! FNullEnt ( pFind ) )
{
CBaseEntity * pEnt = CBaseEntity : : Instance ( pFind ) ;
CDisc * pDisc = ( CDisc * ) pEnt ;
if ( pDisc )
{
if ( ( ( CBaseEntity * ) pDisc - > m_hOwner ) = = this )
pDisc - > m_bRemoveSelf = true ;
}
pFind = FIND_ENTITY_BY_CLASSNAME ( pFind , " disc " ) ;
}
}
// Hit by a decapitator disc
void CBasePlayer : : Decapitate ( entvars_t * pevKiller )
{
// If the player is frozen, shatter instead of decapitating
if ( m_iFrozen )
{
Shatter ( pevKiller ) ;
return ;
}
if ( IsAlive ( ) )
{
m_LastHitGroup = HITGROUP_HEAD ;
m_hLastPlayerToHitMe = CBaseEntity : : Instance ( pevKiller ) ;
m_flLastDiscHit = gpGlobals - > time ;
TakeDamage ( pev , pevKiller , 500 , DMG_NEVERGIB ) ;
EMIT_SOUND ( ENT ( pev ) , CHAN_AUTO , " decap.wav " , 1 , ATTN_NORM ) ;
// Remove the Head
SetBodygroup ( 1 , 2 ) ;
// Spawn a head
CGib * pGib = GetClassPtr ( ( CGib * ) NULL ) ;
pGib - > Spawn ( " models/head.mdl " ) ; // throw one head
pGib - > pev - > solid = SOLID_NOT ;
pGib - > pev - > groupinfo = pev - > groupinfo ;
pGib - > pev - > origin = pev - > origin + pev - > view_ofs ;
pGib - > pev - > velocity = Vector ( RANDOM_FLOAT ( - 10 , 10 ) , RANDOM_FLOAT ( - 10 , 10 ) , 300 ) ;
pGib - > pev - > avelocity . x = RANDOM_FLOAT ( 100 , 200 ) ;
pGib - > pev - > avelocity . y = RANDOM_FLOAT ( 100 , 300 ) ;
pGib - > m_bloodColor = BloodColor ( ) ;
}
}
// Hit by a frozen decapitator disc
void CBasePlayer : : Shatter ( entvars_t * pevKiller )
{
if ( IsAlive ( ) )
{
m_LastHitGroup = HITGROUP_HEAD ;
m_hLastPlayerToHitMe = CBaseEntity : : Instance ( pevKiller ) ;
m_flLastDiscHit = gpGlobals - > time ;
TakeDamage ( pev , pevKiller , 500 , DMG_NEVERGIB ) ;
EMIT_SOUND ( ENT ( pev ) , CHAN_AUTO , " shatter.wav " , 1 , ATTN_NORM ) ;
// make myself invisible
pev - > effects | = EF_NODRAW ;
pev - > solid = SOLID_NOT ;
UTIL_SetOrigin ( pev , pev - > origin ) ;
// Spawn a head
CGib : : SpawnHeadGib ( pev ) ;
CGib : : SpawnRandomGibs ( pev , 6 , 1 ) ;
}
}
# define WALK_SPEED 100
// Set the activity based on an event or current state
void CBasePlayer : : SetAnimation ( PLAYER_ANIM playerAnim )
{
int animDesired ;
float speed ;
speed = pev - > velocity . Length2D ( ) ;
if ( pev - > flags & FL_FROZEN )
{
speed = 0 ;
playerAnim = PLAYER_IDLE ;
}
switch ( playerAnim )
{
case PLAYER_JUMP :
m_IdealActivity = ACT_HOP ;
break ;
case PLAYER_SUPERJUMP :
m_IdealActivity = ACT_LEAP ;
break ;
case PLAYER_DIE :
m_IdealActivity = GetDeathActivity ( ) ;
break ;
case PLAYER_ATTACK1 :
m_IdealActivity = ACT_BASE_THROW ;
break ;
case PLAYER_FALL :
m_IdealActivity = ACT_FALL ;
break ;
case PLAYER_IDLE :
case PLAYER_WALK :
if ( ! FBitSet ( pev - > flags , FL_ONGROUND ) & & ( m_Activity = = ACT_HOP ) ) // Still jumping
{
m_IdealActivity = m_Activity ;
}
else
{
m_IdealActivity = ACT_BASE_WALK ;
}
break ;
}
Vector vecNormVel ;
float flDot , flSideDot , flVelDot ;
bool bInReverse ;
int iFrame ;
// Decide which sequence to play based upon the activity
switch ( m_IdealActivity )
{
case ACT_DIEFORWARD :
case ACT_FALL :
default :
if ( m_Activity = = m_IdealActivity )
return ;
m_Activity = ACT_FALL ;
animDesired = GetFallAnimation ( ) ;
// Already using the desired animation?
if ( pev - > sequence = = animDesired )
return ;
pev - > gaitsequence = 0 ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
case ACT_LEAP :
UTIL_MakeVectors ( pev - > angles ) ;
vecNormVel = pev - > velocity . Normalize ( ) ;
flDot = DotProduct ( vecNormVel , gpGlobals - > v_forward ) ;
if ( flDot < - 0.6 )
{
// Use non-blended backflip
animDesired = LookupSequence ( " backflip " ) ;
m_Activity = m_IdealActivity ;
pev - > gaitsequence = 0 ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
}
else
{
// Use blended longjump
animDesired = LookupSequence ( " longjump " ) ;
m_Activity = ACT_LEAP ;
pev - > gaitsequence = animDesired ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
}
break ;
case ACT_DIE_HEADSHOT :
animDesired = LookupSequence ( " die_simple " ) ;
m_Activity = m_IdealActivity ;
pev - > gaitsequence = 0 ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
case ACT_HOP :
iFrame = pev - > frame / 18 ;
if ( iFrame > = 2 & & iFrame < = 11 )
animDesired = LookupSequence ( " jump " ) ;
else
animDesired = LookupSequence ( " jumpl " ) ;
// Already using the desired animation?
if ( pev - > sequence = = animDesired )
return ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
case ACT_BASE_THROW :
// No throw animation during backflip
if ( pev - > sequence = = LookupSequence ( " backflip " ) )
return ;
// If we're in the air, we need to use the blended longjump throw
if ( pev - > sequence = = LookupSequence ( " longjump " ) )
{
// Use blended longjump
animDesired = LookupSequence ( " longjump_throw " ) ;
m_Activity = ACT_FLINCH_CLOCKWISE ;
pev - > gaitsequence = animDesired ;
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
return ;
}
animDesired = GetThrowAnim ( ) ;
m_Activity = m_IdealActivity ;
m_flThrowTime = gpGlobals - > time ;
break ;
case ACT_BASE_WALK :
UTIL_MakeVectors ( pev - > angles ) ;
bInReverse = ( pev - > sequence = = LookupSequence ( " base_reverse " ) ) ;
vecNormVel = pev - > velocity . Normalize ( ) ;
flDot = DotProduct ( vecNormVel , gpGlobals - > v_forward ) ;
flSideDot = DotProduct ( vecNormVel , gpGlobals - > v_right ) ;
flVelDot = DotProduct ( m_vecOldVelocity , vecNormVel ) ;
if ( ( m_flBackupTime < gpGlobals - > time ) & & ( m_Activity ! = ACT_BASE_THROW ) | | m_fSequenceFinished )
{
//UTIL_MakeVectors( pev->angles );
//ALERT(at_console, "%f\n", flDot );
//ALERT(at_console, "%f\n", flSideDot );
//ALERT(at_console, "%f\n", flVelDot );
//ALERT(at_console, "%f %f\n", flVelDot, flDot );
if ( speed = = 0 )
{
animDesired = LookupSequence ( " base_stand " ) ;
}
/*
else if ( ( pev - > sequence = = LookupSequence ( " base_backup " ) ) & & ( flSideDot < - 0.3 | | flSideDot > 0.3 ) & & ( flDot < - 0.3 ) )
{
// Detect running backwards -> strafe transition
animDesired = LookupSequence ( " base_reverse " ) ;
m_flTransitionTime = gpGlobals - > time + 0.5 ;
ALERT ( at_console , " HERE.. " ) ;
}
*/
else if ( flDot < - 0.6 ) // && m_flTransitionTime < gpGlobals->time )
{
animDesired = LookupSequence ( " base_backup " ) ;
}
else if ( ( flVelDot < = 0 ) & & ( flDot < = 0.6 ) )
{
animDesired = LookupSequence ( " base_reverse " ) ;
m_flBackupTime = gpGlobals - > time + 0.7 ;
pev - > effects | = EF_NOINTERP ;
}
else
{
if ( speed > WALK_SPEED )
animDesired = LookupSequence ( " base_run " ) ;
else
animDesired = LookupSequence ( " base_walk " ) ;
}
if ( animDesired = = - 1 )
{
animDesired = 0 ;
}
m_Activity = ACT_BASE_WALK ;
}
else if ( bInReverse )
{
// Don't play the backup run if we're still in the backup run
if ( DotProduct ( m_vecOldVelocity , vecNormVel ) < 0 )
{
m_flBackupTime = 0 ;
if ( speed > WALK_SPEED )
animDesired = LookupSequence ( " base_run " ) ;
else
animDesired = LookupSequence ( " base_walk " ) ;
pev - > effects | = EF_NOINTERP ;
}
else
{
animDesired = pev - > sequence ;
}
}
else
{
animDesired = pev - > sequence ;
}
break ;
}
// Set gait animation
if ( m_flBackupTime > gpGlobals - > time )
{
pev - > gaitsequence = LookupSequence ( " base_backup " ) ;
}
else
{
if ( speed > WALK_SPEED )
{
pev - > gaitsequence = LookupSequence ( " base_run " ) ;
}
else if ( speed > 0 )
{
pev - > gaitsequence = LookupSequence ( " base_walk " ) ;
}
}
// Idle?
if ( speed < = 0 )
{
pev - > gaitsequence = LookupSequence ( " base_stand " ) ;
}
// Already using the desired animation?
if ( pev - > sequence = = animDesired )
return ;
// Reset to first frame of desired animation
pev - > sequence = animDesired ;
pev - > frame = 0 ;
ResetSequenceInfo ( ) ;
}
int CBasePlayer : : GetThrowAnim ( void )
{
int throwAnim ;
if ( pev - > velocity . Length2D ( ) = = 0 )
throwAnim = LookupSequence ( " base_stand_throw " ) ;
/*
// Choose throw anim based upon powerups.
// Multiple Powerups can be had, in which case the one considered more dangerous has the throw animation.
else if ( m_iPowerups & POW_TRIPLE )
throwAnim = LookupSequence ( " triple_throw " ) ;
else if ( m_iPowerups & POW_FAST )
throwAnim = LookupSequence ( " kill_throw " ) ;
else if ( m_iPowerups & POW_HARD )
throwAnim = LookupSequence ( " hard_throw " ) ;
else if ( m_iPowerups & POW_FREEZE )
throwAnim = LookupSequence ( " freeze_throw " ) ;
*/
else
throwAnim = LookupSequence ( " base_throw " ) ;
return throwAnim ;
}
int CBasePlayer : : GetHoldAnim ( void )
{
int holdAnim ;
// Choose hold anim based upon powerups.
// Multiple Powerups can be had, in which case the one considered more dangerous has the animation.
if ( m_iPowerups & POW_TRIPLE )
holdAnim = LookupSequence ( " triple_ready " ) ;
else if ( m_iPowerups & POW_FAST )
holdAnim = LookupSequence ( " kill_ready " ) ;
else if ( m_iPowerups & POW_HARD )
holdAnim = LookupSequence ( " hard_ready " ) ;
else if ( m_iPowerups & POW_FREEZE )
holdAnim = LookupSequence ( " freeze_ready " ) ;
else
holdAnim = LookupSequence ( " base_ready " ) ;
return holdAnim ;
}
int CBasePlayer : : GetFallAnimation ( void )
{
Vector vecNormVel = pev - > velocity . Normalize ( ) ;
int fallAnim ;
UTIL_MakeVectors ( pev - > angles ) ;
float flDot = DotProduct ( vecNormVel , gpGlobals - > v_forward ) ;
float flSideDot = DotProduct ( vecNormVel , gpGlobals - > v_right ) ;
// Choose a falling animation based upon the velocity vector
if ( flDot < - 0.6 )
fallAnim = LookupSequence ( " fall_b " ) ;
else if ( flSideDot < - 0.6 )
fallAnim = LookupSequence ( " fall_r " ) ;
else if ( flSideDot > 0.6 )
fallAnim = LookupSequence ( " fall_l " ) ;
else
fallAnim = LookupSequence ( " fall_f " ) ;
return fallAnim ;
}
/*
= = = = = = = = = = =
WaterMove
= = = = = = = = = = = =
*/
# define AIRTIME 12 // lung full of air lasts this many seconds
void CBasePlayer : : WaterMove ( )
{
int air ;
if ( pev - > movetype = = MOVETYPE_NOCLIP )
return ;
if ( pev - > health < 0 )
return ;
// waterlevel 0 - not in water
// waterlevel 1 - feet in water
// waterlevel 2 - waist in water
// waterlevel 3 - head in water
if ( pev - > waterlevel ! = 3 )
{
// not underwater
// play 'up for air' sound
if ( pev - > air_finished < gpGlobals - > time )
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/pl_wade1.wav " , 1 , ATTN_NORM ) ;
else if ( pev - > air_finished < gpGlobals - > time + 9 )
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/pl_wade2.wav " , 1 , ATTN_NORM ) ;
pev - > air_finished = gpGlobals - > time + AIRTIME ;
pev - > dmg = 2 ;
// if we took drowning damage, give it back slowly
if ( m_idrowndmg > m_idrownrestored )
{
// set drowning damage bit. hack - dmg_drownrecover actually
// makes the time based damage code 'give back' health over time.
// make sure counter is cleared so we start count correctly.
// NOTE: this actually causes the count to continue restarting
// until all drowning damage is healed.
m_bitsDamageType | = DMG_DROWNRECOVER ;
m_bitsDamageType & = ~ DMG_DROWN ;
m_rgbTimeBasedDamage [ itbd_DrownRecover ] = 0 ;
}
}
else
{ // fully under water
// stop restoring damage while underwater
m_bitsDamageType & = ~ DMG_DROWNRECOVER ;
m_rgbTimeBasedDamage [ itbd_DrownRecover ] = 0 ;
if ( pev - > air_finished < gpGlobals - > time ) // drown!
{
if ( pev - > pain_finished < gpGlobals - > time )
{
// take drowning damage
pev - > dmg + = 1 ;
if ( pev - > dmg > 5 )
pev - > dmg = 5 ;
TakeDamage ( VARS ( eoNullEntity ) , VARS ( eoNullEntity ) , pev - > dmg , DMG_DROWN ) ;
pev - > pain_finished = gpGlobals - > time + 1 ;
// track drowning damage, give it back when
// player finally takes a breath
m_idrowndmg + = pev - > dmg ;
}
}
else
{
m_bitsDamageType & = ~ DMG_DROWN ;
}
}
if ( ! pev - > waterlevel )
{
if ( FBitSet ( pev - > flags , FL_INWATER ) )
{
#if 0
// play leave water sound
switch ( RANDOM_LONG ( 0 , 3 ) )
{
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade1.wav " , 1 , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade2.wav " , 1 , ATTN_NORM ) ; break ;
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade3.wav " , 1 , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade4.wav " , 1 , ATTN_NORM ) ; break ;
}
# endif
ClearBits ( pev - > flags , FL_INWATER ) ;
}
return ;
}
// make bubbles
air = ( int ) ( pev - > air_finished - gpGlobals - > time ) ;
if ( ! RANDOM_LONG ( 0 , 0x1f ) & & RANDOM_LONG ( 0 , AIRTIME - 1 ) > = air )
{
switch ( RANDOM_LONG ( 0 , 3 ) )
{
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_swim1.wav " , 0.8 , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_swim2.wav " , 0.8 , ATTN_NORM ) ; break ;
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_swim3.wav " , 0.8 , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_swim4.wav " , 0.8 , ATTN_NORM ) ; break ;
}
}
if ( pev - > watertype = = CONTENT_LAVA ) // do damage
{
if ( pev - > dmgtime < gpGlobals - > time )
TakeDamage ( VARS ( eoNullEntity ) , VARS ( eoNullEntity ) , 10 * pev - > waterlevel , DMG_BURN ) ;
}
else if ( pev - > watertype = = CONTENT_SLIME ) // do damage
{
pev - > dmgtime = gpGlobals - > time + 1 ;
TakeDamage ( VARS ( eoNullEntity ) , VARS ( eoNullEntity ) , 4 * pev - > waterlevel , DMG_ACID ) ;
}
if ( ! FBitSet ( pev - > flags , FL_INWATER ) )
{
#if 0
// player enter water sound
if ( pev - > watertype = = CONTENT_WATER )
{
switch ( RANDOM_LONG ( 0 , 3 ) )
{
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade1.wav " , 1 , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade2.wav " , 1 , ATTN_NORM ) ; break ;
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade3.wav " , 1 , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade4.wav " , 1 , ATTN_NORM ) ; break ;
}
}
# endif
SetBits ( pev - > flags , FL_INWATER ) ;
pev - > dmgtime = 0 ;
}
if ( ! FBitSet ( pev - > flags , FL_WATERJUMP ) )
pev - > velocity = pev - > velocity - 0.8 * pev - > waterlevel * gpGlobals - > frametime * pev - > velocity ;
}
// TRUE if the player is attached to a ladder
BOOL CBasePlayer : : IsOnLadder ( void )
{
return ( pev - > movetype = = MOVETYPE_FLY ) ;
}
void CBasePlayer : : PlayerDeathThink ( void )
{
float flForward ;
if ( FBitSet ( pev - > flags , FL_ONGROUND ) )
{
flForward = pev - > velocity . Length ( ) - 20 ;
if ( flForward < = 0 )
pev - > velocity = g_vecZero ;
else
pev - > velocity = flForward * pev - > velocity . Normalize ( ) ;
}
if ( pev - > modelindex & & ( ! m_fSequenceFinished ) & & ( pev - > deadflag = = DEAD_DYING ) )
{
StudioFrameAdvance ( ) ;
m_iRespawnFrames + + ; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands
if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this
return ;
}
if ( pev - > deadflag = = DEAD_DYING )
pev - > deadflag = DEAD_DEAD ;
StopAnimation ( ) ;
pev - > effects | = EF_NOINTERP ;
pev - > framerate = 0.0 ;
if ( pev - > deadflag = = DEAD_DEAD )
{
if ( g_pGameRules - > FPlayerCanRespawn ( this ) )
{
m_fDeadTime = gpGlobals - > time ;
pev - > deadflag = DEAD_RESPAWNABLE ;
}
return ;
}
// if the player has been dead for one second longer than allowed by forcerespawn,
// forcerespawn isn't on. Send the player off to an intermission camera until they
// choose to respawn.
if ( g_pGameRules - > IsMultiplayer ( ) & & ( gpGlobals - > time > ( m_fDeadTime + 6 ) ) & & ! ( m_afPhysicsFlags & PFLAG_OBSERVER ) )
{
// go to dead camera.
StartDeathCam ( ) ;
}
// wait three seconds to respawn
if ( gpGlobals - > time < = ( m_fDeadTime + 3 ) )
return ;
pev - > button = 0 ;
m_iRespawnFrames = 0 ;
//ALERT(at_console, "Respawn\n");
respawn ( pev , ! ( m_afPhysicsFlags & PFLAG_OBSERVER ) ) ; // don't copy a corpse if we're in deathcam.
pev - > nextthink = - 1 ;
// Tell the arena that this player's died
if ( m_pCurrentArena )
m_pCurrentArena - > PlayerRespawned ( this ) ;
}
//=========================================================
// StartDeathCam - find an intermission spot and send the
// player off into observer mode
//=========================================================
void CBasePlayer : : StartDeathCam ( void )
{
edict_t * pSpot , * pNewSpot ;
int iRand ;
if ( pev - > view_ofs = = g_vecZero )
{
// don't accept subsequent attempts to StartDeathCam()
return ;
}
pSpot = FIND_ENTITY_BY_CLASSNAME ( NULL , " info_intermission " ) ;
if ( ! FNullEnt ( pSpot ) )
{
// at least one intermission spot in the world.
iRand = RANDOM_LONG ( 0 , 3 ) ;
while ( iRand > 0 )
{
pNewSpot = FIND_ENTITY_BY_CLASSNAME ( pSpot , " info_intermission " ) ;
if ( pNewSpot )
{
pSpot = pNewSpot ;
}
iRand - - ;
}
CopyToBodyQue ( pev ) ;
StartObserver ( pSpot - > v . origin , pSpot - > v . v_angle ) ;
}
else
{
// no intermission spot. Push them up in the air, looking down at their corpse
TraceResult tr ;
CopyToBodyQue ( pev ) ;
UTIL_TraceLine ( pev - > origin , pev - > origin + Vector ( 0 , 0 , 128 ) , ignore_monsters , edict ( ) , & tr ) ;
StartObserver ( tr . vecEndPos , UTIL_VecToAngles ( tr . vecEndPos - pev - > origin ) ) ;
return ;
}
}
//
// PlayerUse - handles USE keypress
//
# define PLAYER_SEARCH_RADIUS (float)64
void CBasePlayer : : PlayerUse ( void )
{
// Was use pressed or released?
if ( ! ( ( pev - > button | m_afButtonPressed | m_afButtonReleased ) & IN_USE ) )
return ;
// Hit Use on a train?
if ( m_afButtonPressed & IN_USE )
{
if ( m_pTank ! = NULL )
{
// Stop controlling the tank
// TODO: Send HUD Update
m_pTank - > Use ( this , this , USE_OFF , 0 ) ;
m_pTank = NULL ;
return ;
}
else
{
if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
{
m_afPhysicsFlags & = ~ PFLAG_ONTRAIN ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
else
{ // Start controlling the train!
CBaseEntity * pTrain = CBaseEntity : : Instance ( pev - > groundentity ) ;
if ( pTrain & & ! ( pev - > button & IN_JUMP ) & & FBitSet ( pev - > flags , FL_ONGROUND ) & & ( pTrain - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) & & pTrain - > OnControls ( pev ) )
{
m_afPhysicsFlags | = PFLAG_ONTRAIN ;
m_iTrain = TrainSpeed ( pTrain - > pev - > speed , pTrain - > pev - > impulse ) ;
m_iTrain | = TRAIN_NEW ;
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " plats/train_use1.wav " , 0.8 , ATTN_NORM ) ;
return ;
}
}
}
}
CBaseEntity * pObject = NULL ;
CBaseEntity * pClosest = NULL ;
Vector vecLOS ;
float flMaxDot = VIEW_FIELD_NARROW ;
float flDot ;
UTIL_MakeVectors ( pev - > v_angle ) ; // so we know which way we are facing
while ( ( pObject = UTIL_FindEntityInSphere ( pObject , pev - > origin , PLAYER_SEARCH_RADIUS ) ) ! = NULL )
{
if ( pObject - > ObjectCaps ( ) & ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE ) )
{
// !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that
// this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS
// when player hits the use key. How many objects can be in that area, anyway? (sjb)
vecLOS = ( VecBModelOrigin ( pObject - > pev ) - ( pev - > origin + pev - > view_ofs ) ) ;
// This essentially moves the origin of the target to the corner nearest the player to test to see
// if it's "hull" is in the view cone
vecLOS = UTIL_ClampVectorToBox ( vecLOS , pObject - > pev - > size * 0.5 ) ;
flDot = DotProduct ( vecLOS , gpGlobals - > v_forward ) ;
if ( flDot > flMaxDot )
{ // only if the item is in front of the user
pClosest = pObject ;
flMaxDot = flDot ;
// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
}
// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot );
}
}
pObject = pClosest ;
// Found an object
if ( pObject )
{
//!!!UNDONE: traceline here to prevent USEing buttons through walls
int caps = pObject - > ObjectCaps ( ) ;
if ( m_afButtonPressed & IN_USE )
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " common/wpn_select.wav " , 0.4 , ATTN_NORM ) ;
if ( ( ( pev - > button & IN_USE ) & & ( caps & FCAP_CONTINUOUS_USE ) ) | |
( ( m_afButtonPressed & IN_USE ) & & ( caps & ( FCAP_IMPULSE_USE | FCAP_ONOFF_USE ) ) ) )
{
if ( caps & FCAP_CONTINUOUS_USE )
m_afPhysicsFlags | = PFLAG_USING ;
pObject - > Use ( this , this , USE_SET , 1 ) ;
}
// UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
else if ( ( m_afButtonReleased & IN_USE ) & & ( pObject - > ObjectCaps ( ) & FCAP_ONOFF_USE ) ) // BUGBUG This is an "off" use
{
pObject - > Use ( this , this , USE_SET , 0 ) ;
}
}
else
{
if ( m_afButtonPressed & IN_USE )
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " common/wpn_denyselect.wav " , 0.4 , ATTN_NORM ) ;
}
}
void CBasePlayer : : Jump ( )
{
Vector vecWallCheckDir ; // direction we're tracing a line to find a wall when walljumping
Vector vecAdjustedVelocity ;
Vector vecSpot ;
TraceResult tr ;
if ( FBitSet ( pev - > flags , FL_WATERJUMP ) )
return ;
if ( pev - > waterlevel > = 2 )
{
return ;
}
// jump velocity is sqrt( height * gravity * 2)
// If this isn't the first frame pressing the jump button, break out.
if ( ! FBitSet ( m_afButtonPressed , IN_JUMP ) )
return ; // don't pogo stick
if ( ! ( pev - > flags & FL_ONGROUND ) | | ! pev - > groundentity )
{
return ;
}
// many features in this function use v_forward, so makevectors now.
UTIL_MakeVectors ( pev - > angles ) ;
SetAnimation ( PLAYER_JUMP ) ;
// If you're standing on a conveyor, add it's velocity to yours (for momentum)
entvars_t * pevGround = VARS ( pev - > groundentity ) ;
if ( pevGround & & ( pevGround - > flags & FL_CONVEYOR ) )
{
pev - > velocity = pev - > velocity + pev - > basevelocity ;
}
}
// This is a glorious hack to find free space when you've crouched into some solid space
// Our crouching collisions do not work correctly for some reason and this is easier
// than fixing the problem :(
void FixPlayerCrouchStuck ( edict_t * pPlayer )
{
TraceResult trace ;
// Move up as many as 18 pixels if the player is stuck.
for ( int i = 0 ; i < 18 ; i + + )
{
UTIL_TraceHull ( pPlayer - > v . origin , pPlayer - > v . origin , dont_ignore_monsters , head_hull , pPlayer , & trace ) ;
if ( trace . fStartSolid )
pPlayer - > v . origin . z + + ;
else
break ;
}
}
void CBasePlayer : : Duck ( )
{
return ;
}
//
// ID's player as such.
//
int CBasePlayer : : Classify ( void )
{
return CLASS_PLAYER ;
}
void CBasePlayer : : AddPoints ( int score , BOOL bAllowNegativeScore )
{
// Positive score always adds
if ( score < 0 )
{
if ( ! bAllowNegativeScore )
{
if ( pev - > frags < 0 ) // Can't go more negative
return ;
if ( - score > pev - > frags ) // Will this go negative?
{
score = - pev - > frags ; // Sum will be 0
}
}
}
pev - > frags + = score ;
}
void CBasePlayer : : AddPointsToTeam ( int score , BOOL bAllowNegativeScore )
{
int index = entindex ( ) ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBaseEntity * pPlayer = UTIL_PlayerByIndex ( i ) ;
if ( pPlayer & & i ! = index )
{
if ( g_pGameRules - > PlayerRelationship ( this , pPlayer ) = = GR_TEAMMATE )
{
pPlayer - > AddPoints ( score , bAllowNegativeScore ) ;
}
}
}
}
#if 0
void CBasePlayer : : CheckWeapon ( void )
{
// play a weapon idle anim if it's time!
if ( gpGlobals - > time > m_flTimeWeaponIdle )
{
WeaponIdle ( ) ;
}
}
# endif
// play a footstep if it's time - this will eventually be frame-based. not time based.
# define STEP_CONCRETE 0 // default step sound
# define STEP_METAL 1 // metal floor
# define STEP_DIRT 2 // dirt, sand, rock
# define STEP_VENT 3 // ventillation duct
# define STEP_GRATE 4 // metal grating
# define STEP_TILE 5 // floor tiles
# define STEP_SLOSH 6 // shallow liquid puddle
# define STEP_WADE 7 // wading in liquid
# define STEP_LADDER 8 // climbing ladder
// Play correct step sound for material we're on or in
void CBasePlayer : : PlayStepSound ( int step , float fvol )
{
static int iSkipStep = 0 ;
if ( ! g_pGameRules - > PlayFootstepSounds ( this , fvol ) )
return ;
// irand - 0,1 for right foot, 2,3 for left foot
// used to alternate left and right foot
int irand = RANDOM_LONG ( 0 , 1 ) + ( m_iStepLeft * 2 ) ;
m_iStepLeft = ! m_iStepLeft ;
switch ( step )
{
default :
case STEP_CONCRETE :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_step1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_step3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_step2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_step4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_METAL :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_metal1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_metal3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_metal2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_metal4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_DIRT :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_dirt1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_dirt3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_dirt2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_dirt4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_VENT :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_duct1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_duct3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_duct2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_duct4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_GRATE :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_grate1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_grate3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_grate2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_grate4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_TILE :
if ( ! RANDOM_LONG ( 0 , 4 ) )
irand = 4 ;
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_tile1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_tile3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_tile2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_tile4.wav " , fvol , ATTN_NORM ) ; break ;
case 4 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_tile5.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_SLOSH :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_slosh1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_slosh3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_slosh2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_slosh4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_WADE :
if ( iSkipStep = = 0 )
{
iSkipStep + + ;
break ;
}
if ( iSkipStep + + = = 3 )
{
iSkipStep = 0 ;
}
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade2.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade3.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_wade4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
case STEP_LADDER :
switch ( irand )
{
// right foot
case 0 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_ladder1.wav " , fvol , ATTN_NORM ) ; break ;
case 1 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_ladder3.wav " , fvol , ATTN_NORM ) ; break ;
// left foot
case 2 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_ladder2.wav " , fvol , ATTN_NORM ) ; break ;
case 3 : EMIT_SOUND ( ENT ( pev ) , CHAN_BODY , " player/pl_ladder4.wav " , fvol , ATTN_NORM ) ; break ;
}
break ;
}
}
// Simple mapping from texture type character to step type
int MapTextureTypeStepType ( char chTextureType )
{
switch ( chTextureType )
{
default :
case CHAR_TEX_CONCRETE : return STEP_CONCRETE ;
case CHAR_TEX_METAL : return STEP_METAL ;
case CHAR_TEX_DIRT : return STEP_DIRT ;
case CHAR_TEX_VENT : return STEP_VENT ;
case CHAR_TEX_GRATE : return STEP_GRATE ;
case CHAR_TEX_TILE : return STEP_TILE ;
case CHAR_TEX_SLOSH : return STEP_SLOSH ;
}
}
// Play left or right footstep based on material player is on or in
void CBasePlayer : : UpdateStepSound ( void )
{
int fWalking ;
float fvol ;
char szbuffer [ 64 ] ;
const char * pTextureName ;
Vector start , end ;
float rgfl1 [ 3 ] ;
float rgfl2 [ 3 ] ;
Vector knee ;
Vector feet ;
Vector center ;
float height ;
float speed ;
float velrun ;
float velwalk ;
float flduck ;
int fLadder ;
int step ;
if ( gpGlobals - > time < = m_flTimeStepSound )
return ;
if ( pev - > flags & FL_FROZEN )
return ;
if ( m_flTouchedByJumpPad > gpGlobals - > time )
return ;
speed = pev - > velocity . Length ( ) ;
// determine if we are on a ladder
fLadder = IsOnLadder ( ) ;
// UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
if ( FBitSet ( pev - > flags , FL_DUCKING ) | | fLadder )
{
velwalk = 60 ; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
velrun = 80 ; // UNDONE: Move walking to server
flduck = 0.1 ;
}
else
{
velwalk = 120 ;
velrun = 210 ;
flduck = 0.0 ;
}
// ALERT (at_console, "vel: %f\n", vecVel.Length());
// if we're on a ladder or on the ground, and we're moving fast enough,
// play step sound. Also, if m_flTimeStepSound is zero, get the new
// sound right away - we just started moving in new level.
if ( ( fLadder | | FBitSet ( pev - > flags , FL_ONGROUND ) ) & & pev - > velocity ! = g_vecZero
& & ( speed > = velwalk | | ! m_flTimeStepSound ) )
{
SetAnimation ( PLAYER_WALK ) ;
fWalking = speed < velrun ;
center = knee = feet = ( pev - > absmin + pev - > absmax ) * 0.5 ;
height = pev - > absmax . z - pev - > absmin . z ;
knee . z = pev - > absmin . z + height * 0.2 ;
feet . z = pev - > absmin . z ;
// find out what we're stepping in or on...
if ( fLadder )
{
step = STEP_LADDER ;
fvol = 0.35 ;
m_flTimeStepSound = gpGlobals - > time + 0.35 ;
}
else if ( UTIL_PointContents ( knee ) = = CONTENTS_WATER )
{
step = STEP_WADE ;
fvol = 0.65 ;
m_flTimeStepSound = gpGlobals - > time + 0.6 ;
}
else if ( UTIL_PointContents ( feet ) = = CONTENTS_WATER )
{
step = STEP_SLOSH ;
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
}
else
{
// find texture under player, if different from current texture,
// get material type
start = end = center ; // center point of player BB
start . z = end . z = pev - > absmin . z ; // copy zmin
start . z + = 4.0 ; // extend start up
end . z - = 24.0 ; // extend end down
start . CopyToArray ( rgfl1 ) ;
end . CopyToArray ( rgfl2 ) ;
pTextureName = TRACE_TEXTURE ( ENT ( pev - > groundentity ) , rgfl1 , rgfl2 ) ;
if ( pTextureName )
{
// strip leading '-0' or '{' or '!'
if ( * pTextureName = = ' - ' )
pTextureName + = 2 ;
if ( * pTextureName = = ' { ' | | * pTextureName = = ' ! ' )
pTextureName + + ;
if ( _strnicmp ( pTextureName , m_szTextureName , CBTEXTURENAMEMAX - 1 ) )
{
// current texture is different from texture player is on...
// set current texture
strcpy ( szbuffer , pTextureName ) ;
szbuffer [ CBTEXTURENAMEMAX - 1 ] = 0 ;
strcpy ( m_szTextureName , szbuffer ) ;
// ALERT ( at_aiconsole, "texture: %s\n", m_szTextureName );
// get texture type
m_chTextureType = TEXTURETYPE_Find ( m_szTextureName ) ;
}
}
step = MapTextureTypeStepType ( m_chTextureType ) ;
switch ( m_chTextureType )
{
default :
case CHAR_TEX_CONCRETE :
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_METAL :
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_DIRT :
fvol = fWalking ? 0.25 : 0.55 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_VENT :
fvol = fWalking ? 0.4 : 0.7 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_GRATE :
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_TILE :
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
case CHAR_TEX_SLOSH :
fvol = fWalking ? 0.2 : 0.5 ;
m_flTimeStepSound = fWalking ? gpGlobals - > time + 0.4 : gpGlobals - > time + 0.3 ;
break ;
}
}
m_flTimeStepSound + = flduck ; // slower step time if ducking
// play the sound
// 35% volume if ducking
if ( pev - > flags & FL_DUCKING )
fvol * = 0.35 ;
}
}
# define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing
# define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible
# define CLIMB_SPEED_DEC 15 // climbing deceleration rate
# define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing
# define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing
void CBasePlayer : : PreThink ( void )
{
int buttonsChanged = ( m_afButtonLast ^ pev - > button ) ; // These buttons have changed this frame
// Fade away the renderfx
if ( pev - > renderamt )
{
if ( ! m_iFrozen )
pev - > renderamt - = 25 ;
if ( pev - > renderamt < = 0 | | ( m_flFreezeTime < gpGlobals - > time & & m_iFrozen ) )
ClearFreezeAndRender ( ) ;
}
if ( m_flSendArenaStatus ! = - 1 & & m_flSendArenaStatus < = gpGlobals - > time )
{
g_pGameRules - > UpdateGameMode ( this ) ;
m_flSendArenaStatus = - 1 ;
}
// Hack to pass down the weapon information to the client after they've connected.
// Needed for listen servers because they lose msgs while bringing up the svr.
if ( m_flKnownItemTime & & m_flKnownItemTime < gpGlobals - > time )
{
CLIENT_COMMAND ( edict ( ) , " r_drawviewmodel 0 \n " ) ;
m_fKnownItem = FALSE ;
m_flKnownItemTime = 0 ;
}
// Debounced button codes for pressed/released
// UNDONE: Do we need auto-repeat?
m_afButtonPressed = buttonsChanged & pev - > button ; // The changed ones still down are "pressed"
m_afButtonReleased = buttonsChanged & ( ~ pev - > button ) ; // The ones not down are "released"
g_pGameRules - > PlayerThink ( this ) ;
if ( g_fGameOver )
return ; // intermission or finale
UTIL_MakeVectors ( pev - > v_angle ) ; // is this still used?
ItemPreFrame ( ) ;
WaterMove ( ) ;
if ( g_pGameRules & & g_pGameRules - > FAllowFlashlight ( ) )
m_iHideHUD & = ~ HIDEHUD_FLASHLIGHT ;
else
m_iHideHUD | = HIDEHUD_FLASHLIGHT ;
// JOHN: checks if new client data (for HUD and view control) needs to be sent to the client
UpdateClientData ( ) ;
CheckTimeBasedDamage ( ) ;
// Observer Button Handling
if ( IsObserver ( ) )
{
Observer_HandleButtons ( ) ;
pev - > impulse = 0 ;
return ;
}
CheckSuitUpdate ( ) ;
if ( pev - > deadflag > = DEAD_DYING )
{
PlayerDeathThink ( ) ;
return ;
}
// So the correct flags get sent to client asap.
//
if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
pev - > flags | = FL_ONTRAIN ;
else
pev - > flags & = ~ FL_ONTRAIN ;
// Train speed control
if ( m_afPhysicsFlags & PFLAG_ONTRAIN )
{
CBaseEntity * pTrain = CBaseEntity : : Instance ( pev - > groundentity ) ;
float vel ;
if ( ! pTrain )
{
TraceResult trainTrace ;
// Maybe this is on the other side of a level transition
UTIL_TraceLine ( pev - > origin , pev - > origin + Vector ( 0 , 0 , - 38 ) , ignore_monsters , ENT ( pev ) , & trainTrace ) ;
// HACKHACK - Just look for the func_tracktrain classname
if ( trainTrace . flFraction ! = 1.0 & & trainTrace . pHit )
pTrain = CBaseEntity : : Instance ( trainTrace . pHit ) ;
if ( ! pTrain | | ! ( pTrain - > ObjectCaps ( ) & FCAP_DIRECTIONAL_USE ) | | ! pTrain - > OnControls ( pev ) )
{
//ALERT( at_error, "In train mode with no train!\n" );
m_afPhysicsFlags & = ~ PFLAG_ONTRAIN ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
}
else if ( ! FBitSet ( pev - > flags , FL_ONGROUND ) | | FBitSet ( pTrain - > pev - > spawnflags , SF_TRACKTRAIN_NOCONTROL ) | | ( pev - > button & ( IN_MOVELEFT | IN_MOVERIGHT ) ) )
{
// Turn off the train if you jump, strafe, or the train controls go dead
m_afPhysicsFlags & = ~ PFLAG_ONTRAIN ;
m_iTrain = TRAIN_NEW | TRAIN_OFF ;
return ;
}
pev - > velocity = g_vecZero ;
vel = 0 ;
if ( m_afButtonPressed & IN_FORWARD )
{
vel = 1 ;
pTrain - > Use ( this , this , USE_SET , ( float ) vel ) ;
}
else if ( m_afButtonPressed & IN_BACK )
{
vel = - 1 ;
pTrain - > Use ( this , this , USE_SET , ( float ) vel ) ;
}
if ( vel )
{
m_iTrain = TrainSpeed ( pTrain - > pev - > speed , pTrain - > pev - > impulse ) ;
m_iTrain | = TRAIN_ACTIVE | TRAIN_NEW ;
}
} else if ( m_iTrain & TRAIN_ACTIVE )
m_iTrain = TRAIN_NEW ; // turn off train
// DISCWAR: No Jumping or Ducking
/*
if ( pev - > button & IN_JUMP )
{
// If on a ladder, jump off the ladder
// else Jump
Jump ( ) ;
}
// If trying to duck, already ducked, or in the process of ducking
if ( ( pev - > button & IN_DUCK ) | | FBitSet ( pev - > flags , FL_DUCKING ) | | ( m_afPhysicsFlags & PFLAG_DUCKING ) )
Duck ( ) ;
*/
// DISCWAR: Impart the velocity from a disc hit onto the player
if ( m_vecHitVelocity ! = g_vecZero )
{
pev - > velocity = m_vecHitVelocity ;
m_vecHitVelocity = g_vecZero ;
}
// play a footstep if it's time - this will eventually be frame-based. not time based.
UpdateStepSound ( ) ;
if ( ! FBitSet ( pev - > flags , FL_ONGROUND ) )
{
m_flFallVelocity = - pev - > velocity . z ;
}
// StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating?
// Clear out ladder pointer
m_hEnemy = NULL ;
if ( m_afPhysicsFlags & PFLAG_ONBARNACLE )
{
pev - > velocity = g_vecZero ;
}
}
/* Time based Damage works as follows:
1 ) There are several types of timebased damage :
# define DMG_PARALYZE (1 << 14) // slows affected creature down
# define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad
# define DMG_POISON (1 << 16) // blood poisioning
# define DMG_RADIATION (1 << 17) // radiation exposure
# define DMG_DROWNRECOVER (1 << 18) // drown recovery
# define DMG_ACID (1 << 19) // toxic chemicals or acid burns
# define DMG_SLOWBURN (1 << 20) // in an oven
# define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer
2 ) A new hit inflicting tbd restarts the tbd counter - each monster has an 8 bit counter ,
per damage type . The counter is decremented every second , so the maximum time
an effect will last is 255 / 60 = 4.25 minutes . Of course , staying within the radius
of a damaging effect like fire , nervegas , radiation will continually reset the counter to max .
3 ) Every second that a tbd counter is running , the player takes damage . The damage
is determined by the type of tdb .
Paralyze - 1 / 2 movement rate , 30 second duration .
Nervegas - 5 points per second , 16 second duration = 80 points max dose .
Poison - 2 points per second , 25 second duration = 50 points max dose .
Radiation - 1 point per second , 50 second duration = 50 points max dose .
Drown - 5 points per second , 2 second duration .
Acid / Chemical - 5 points per second , 10 second duration = 50 points max .
Burn - 10 points per second , 2 second duration .
Freeze - 3 points per second , 10 second duration = 30 points max .
4 ) Certain actions or countermeasures counteract the damaging effects of tbds :
Armor / Heater / Cooler - Chemical ( acid ) , burn , freeze all do damage to armor power , then to body
- recharged by suit recharger
Air In Lungs - drowning damage is done to air in lungs first , then to body
- recharged by poking head out of water
- 10 seconds if swiming fast
Air In SCUBA - drowning damage is done to air in tanks first , then to body
- 2 minutes in tanks . Need new tank once empty .
Radiation Syringe - Each syringe full provides protection vs one radiation dosage
Antitoxin Syringe - Each syringe full provides protection vs one poisoning ( nervegas or poison ) .
Health kit - Immediate stop to acid / chemical , fire or freeze damage .
Radiation Shower - Immediate stop to radiation damage , acid / chemical or fire damage .
*/
// If player is taking time based damage, continue doing damage to player -
// this simulates the effect of being poisoned, gassed, dosed with radiation etc -
// anything that continues to do damage even after the initial contact stops.
// Update all time based damage counters, and shut off any that are done.
// The m_bitsDamageType bit MUST be set if any damage is to be taken.
// This routine will detect the initial on value of the m_bitsDamageType
// and init the appropriate counter. Only processes damage every second.
//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage
//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval
//#define NERVEGAS_DURATION 16
//#define NERVEGAS_DAMAGE 5.0
//#define POISON_DURATION 25
//#define POISON_DAMAGE 2.0
//#define RADIATION_DURATION 50
//#define RADIATION_DAMAGE 1.0
//#define ACID_DURATION 10
//#define ACID_DAMAGE 5.0
//#define SLOWBURN_DURATION 2
//#define SLOWBURN_DAMAGE 1.0
//#define SLOWFREEZE_DURATION 1.0
//#define SLOWFREEZE_DAMAGE 3.0
/* */
void CBasePlayer : : CheckTimeBasedDamage ( )
{
int i ;
BYTE bDuration = 0 ;
static float gtbdPrev = 0.0 ;
if ( ! ( m_bitsDamageType & DMG_TIMEBASED ) )
return ;
// only check for time based damage approx. every 2 seconds
if ( abs ( gpGlobals - > time - m_tbdPrev ) < 2.0 )
return ;
m_tbdPrev = gpGlobals - > time ;
for ( i = 0 ; i < CDMG_TIMEBASED ; i + + )
{
// make sure bit is set for damage type
if ( m_bitsDamageType & ( DMG_PARALYZE < < i ) )
{
switch ( i )
{
case itbd_Paralyze :
// UNDONE - flag movement as half-speed
bDuration = PARALYZE_DURATION ;
break ;
case itbd_NerveGas :
// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC);
bDuration = NERVEGAS_DURATION ;
break ;
case itbd_Poison :
TakeDamage ( pev , pev , POISON_DAMAGE , DMG_GENERIC ) ;
bDuration = POISON_DURATION ;
break ;
case itbd_Radiation :
// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC);
bDuration = RADIATION_DURATION ;
break ;
case itbd_DrownRecover :
// NOTE: this hack is actually used to RESTORE health
// after the player has been drowning and finally takes a breath
if ( m_idrowndmg > m_idrownrestored )
{
int idif = min ( m_idrowndmg - m_idrownrestored , 10 ) ;
TakeHealth ( idif , DMG_GENERIC ) ;
m_idrownrestored + = idif ;
}
bDuration = 4 ; // get up to 5*10 = 50 points back
break ;
case itbd_Acid :
// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC);
bDuration = ACID_DURATION ;
break ;
case itbd_SlowBurn :
// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC);
bDuration = SLOWBURN_DURATION ;
break ;
case itbd_SlowFreeze :
// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC);
bDuration = SLOWFREEZE_DURATION ;
break ;
default :
bDuration = 0 ;
}
if ( m_rgbTimeBasedDamage [ i ] )
{
// use up an antitoxin on poison or nervegas after a few seconds of damage
if ( ( ( i = = itbd_NerveGas ) & & ( m_rgbTimeBasedDamage [ i ] < NERVEGAS_DURATION ) ) | |
( ( i = = itbd_Poison ) & & ( m_rgbTimeBasedDamage [ i ] < POISON_DURATION ) ) )
{
if ( m_rgItems [ ITEM_ANTIDOTE ] )
{
m_rgbTimeBasedDamage [ i ] = 0 ;
m_rgItems [ ITEM_ANTIDOTE ] - - ;
SetSuitUpdate ( " !HEV_HEAL4 " , FALSE , SUIT_REPEAT_OK ) ;
}
}
// decrement damage duration, detect when done.
if ( ! m_rgbTimeBasedDamage [ i ] | | - - m_rgbTimeBasedDamage [ i ] = = 0 )
{
m_rgbTimeBasedDamage [ i ] = 0 ;
// if we're done, clear damage bits
m_bitsDamageType & = ~ ( DMG_PARALYZE < < i ) ;
}
}
else
// first time taking this damage type - init damage duration
m_rgbTimeBasedDamage [ i ] = bDuration ;
}
}
}
/*
THE POWER SUIT
The Suit provides 3 main functions : Protection , Notification and Augmentation .
Some functions are automatic , some require power .
The player gets the suit shortly after getting off the train in C1A0 and it stays
with him for the entire game .
Protection
Heat / Cold
When the player enters a hot / cold area , the heating / cooling indicator on the suit
will come on and the battery will drain while the player stays in the area .
After the battery is dead , the player starts to take damage .
This feature is built into the suit and is automatically engaged .
Radiation Syringe
This will cause the player to be immune from the effects of radiation for N seconds . Single use item .
Anti - Toxin Syringe
This will cure the player from being poisoned . Single use item .
Health
Small ( 1 st 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 - > time < m_flgeigerDelay )
return ;
m_flgeigerDelay = gpGlobals - > time + GEIGERDELAY ;
// send range to radition source to client
range = ( BYTE ) ( m_flgeigerRange / 4 ) ;
if ( range ! = m_igeigerRangePrev )
{
m_igeigerRangePrev = range ;
MESSAGE_BEGIN ( MSG_ONE , gmsgGeigerRange , NULL , pev ) ;
WRITE_BYTE ( range ) ;
MESSAGE_END ( ) ;
}
// reset counter and semaphore
if ( ! RANDOM_LONG ( 0 , 3 ) )
m_flgeigerRange = 1000 ;
}
/*
= = = = = = = = = = = = = = = =
CheckSuitUpdate
Play suit update if it ' s time
= = = = = = = = = = = = = = = =
*/
# define SUITUPDATETIME 3.5
# define SUITFIRSTUPDATETIME 0.1
void CBasePlayer : : CheckSuitUpdate ( )
{
int i ;
int isentence = 0 ;
int isearch = m_iSuitPlayNext ;
// Ignore suit updates if no suit
if ( ! ( pev - > weapons & ( 1 < < WEAPON_SUIT ) ) )
return ;
// if in range of radiation source, ping geiger counter
UpdateGeigerCounter ( ) ;
if ( g_pGameRules - > IsMultiplayer ( ) )
{
// don't bother updating HEV voice in multiplayer.
return ;
}
if ( gpGlobals - > time > = m_flSuitUpdate & & m_flSuitUpdate > 0 )
{
// play a sentence off of the end of the queue
for ( i = 0 ; i < CSUITPLAYLIST ; i + + )
{
if ( isentence = m_rgSuitPlayList [ isearch ] )
break ;
if ( + + isearch = = CSUITPLAYLIST )
isearch = 0 ;
}
if ( isentence )
{
m_rgSuitPlayList [ isearch ] = 0 ;
if ( isentence > 0 )
{
// play sentence number
char sentence [ CBSENTENCENAME_MAX + 1 ] ;
strcpy ( sentence , " ! " ) ;
strcat ( sentence , gszallsentencenames [ isentence ] ) ;
EMIT_SOUND_SUIT ( ENT ( pev ) , sentence ) ;
}
else
{
// play sentence group
EMIT_GROUPID_SUIT ( ENT ( pev ) , - isentence ) ;
}
m_flSuitUpdate = gpGlobals - > time + SUITUPDATETIME ;
}
else
// queue is empty, don't check
m_flSuitUpdate = 0 ;
}
}
// add sentence to suit playlist queue. if fgroup is true, then
// name is a sentence group (HEV_AA), otherwise name is a specific
// sentence name ie: !HEV_AA0. If iNoRepeat is specified in
// seconds, then we won't repeat playback of this word or sentence
// for at least that number of seconds.
void CBasePlayer : : SetSuitUpdate ( char * name , int fgroup , int iNoRepeatTime )
{
int i ;
int isentence ;
int iempty = - 1 ;
// Ignore suit updates if no suit
if ( ! ( pev - > weapons & ( 1 < < WEAPON_SUIT ) ) )
return ;
if ( g_pGameRules - > IsMultiplayer ( ) )
{
// due to static channel design, etc. We don't play HEV sounds in multiplayer right now.
return ;
}
// if name == NULL, then clear out the queue
if ( ! name )
{
for ( i = 0 ; i < CSUITPLAYLIST ; i + + )
m_rgSuitPlayList [ i ] = 0 ;
return ;
}
// get sentence or group number
if ( ! fgroup )
{
isentence = SENTENCEG_Lookup ( name , NULL ) ;
if ( isentence < 0 )
return ;
}
else
// mark group number as negative
isentence = - SENTENCEG_GetIndex ( name ) ;
// check norepeat list - this list lets us cancel
// the playback of words or sentences that have already
// been played within a certain time.
for ( i = 0 ; i < CSUITNOREPEAT ; i + + )
{
if ( isentence = = m_rgiSuitNoRepeat [ i ] )
{
// this sentence or group is already in
// the norepeat list
if ( m_rgflSuitNoRepeatTime [ i ] < gpGlobals - > time )
{
// norepeat time has expired, clear it out
m_rgiSuitNoRepeat [ i ] = 0 ;
m_rgflSuitNoRepeatTime [ i ] = 0.0 ;
iempty = i ;
break ;
}
else
{
// don't play, still marked as norepeat
return ;
}
}
// keep track of empty slot
if ( ! m_rgiSuitNoRepeat [ i ] )
iempty = i ;
}
// sentence is not in norepeat list, save if norepeat time was given
if ( iNoRepeatTime )
{
if ( iempty < 0 )
iempty = RANDOM_LONG ( 0 , CSUITNOREPEAT - 1 ) ; // pick random slot to take over
m_rgiSuitNoRepeat [ iempty ] = isentence ;
m_rgflSuitNoRepeatTime [ iempty ] = iNoRepeatTime + gpGlobals - > time ;
}
// find empty spot in queue, or overwrite last spot
m_rgSuitPlayList [ m_iSuitPlayNext + + ] = isentence ;
if ( m_iSuitPlayNext = = CSUITPLAYLIST )
m_iSuitPlayNext = 0 ;
if ( m_flSuitUpdate < = gpGlobals - > time )
{
if ( m_flSuitUpdate = = 0 )
// play queue is empty, don't delay too long before playback
m_flSuitUpdate = gpGlobals - > time + SUITFIRSTUPDATETIME ;
else
m_flSuitUpdate = gpGlobals - > time + SUITUPDATETIME ;
}
}
/*
= = = = = = = = = = = = = = = =
CheckPowerups
Check for turning off powerups
GLOBALS ASSUMED SET : g_ulModelIndexPlayer
= = = = = = = = = = = = = = = =
*/
static void
CheckPowerups ( entvars_t * pev )
{
if ( pev - > health < = 0 )
return ;
pev - > modelindex = g_ulModelIndexPlayer ; // don't use eyes
}
//=========================================================
// UpdatePlayerSound - updates the position of the player's
// reserved sound slot in the sound list.
//=========================================================
void CBasePlayer : : UpdatePlayerSound ( void )
{
int iBodyVolume ;
int iVolume ;
CSound * pSound ;
pSound = CSoundEnt : : SoundPointerForIndex ( CSoundEnt : : ClientSoundIndex ( edict ( ) ) ) ;
if ( ! pSound )
{
ALERT ( at_console , " Client lost reserved sound! \n " ) ;
return ;
}
pSound - > m_iType = bits_SOUND_NONE ;
// now calculate the best target volume for the sound. If the player's weapon
// is louder than his body/movement, use the weapon volume, else, use the body volume.
if ( FBitSet ( pev - > flags , FL_ONGROUND ) )
{
iBodyVolume = pev - > velocity . Length ( ) ;
// clamp the noise that can be made by the body, in case a push trigger,
// weapon recoil, or anything shoves the player abnormally fast.
if ( iBodyVolume > 512 )
{
iBodyVolume = 512 ;
}
}
else
{
iBodyVolume = 0 ;
}
if ( pev - > button & IN_JUMP )
{
iBodyVolume + = 100 ;
}
// convert player move speed and actions into sound audible by monsters.
if ( m_iWeaponVolume > iBodyVolume )
{
m_iTargetVolume = m_iWeaponVolume ;
// OR in the bits for COMBAT sound if the weapon is being louder than the player.
pSound - > m_iType | = bits_SOUND_COMBAT ;
}
else
{
m_iTargetVolume = iBodyVolume ;
}
// decay weapon volume over time so bits_SOUND_COMBAT stays set for a while
m_iWeaponVolume - = 250 * gpGlobals - > frametime ;
if ( m_iWeaponVolume < 0 )
{
iVolume = 0 ;
}
// if target volume is greater than the player sound's current volume, we paste the new volume in
// immediately. If target is less than the current volume, current volume is not set immediately to the
// lower volume, rather works itself towards target volume over time. This gives monsters a much better chance
// to hear a sound, especially if they don't listen every frame.
iVolume = pSound - > m_iVolume ;
if ( m_iTargetVolume > iVolume )
{
iVolume = m_iTargetVolume ;
}
else if ( iVolume > m_iTargetVolume )
{
iVolume - = 250 * gpGlobals - > frametime ;
if ( iVolume < m_iTargetVolume )
{
iVolume = 0 ;
}
}
if ( m_fNoPlayerSound )
{
// debugging flag, lets players move around and shoot without monsters hearing.
iVolume = 0 ;
}
if ( gpGlobals - > time > m_flStopExtraSoundTime )
{
// since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two
// after actual emission to make sure it gets heard.
m_iExtraSoundTypes = 0 ;
}
if ( pSound )
{
pSound - > m_vecOrigin = pev - > origin ;
pSound - > m_iType | = ( bits_SOUND_PLAYER | m_iExtraSoundTypes ) ;
pSound - > m_iVolume = iVolume ;
}
// keep track of virtual muzzle flash
m_iWeaponFlash - = 256 * gpGlobals - > frametime ;
if ( m_iWeaponFlash < 0 )
m_iWeaponFlash = 0 ;
UTIL_MakeVectors ( pev - > angles ) ;
gpGlobals - > v_forward . z = 0 ;
// Below are a couple of useful little bits that make it easier to determine just how much noise the
// player is making.
// UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 );
//ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume );
}
void CBasePlayer : : PostThink ( )
{
if ( g_fGameOver )
goto pt_end ; // intermission or finale
if ( ! IsAlive ( ) )
goto pt_end ;
// Handle Tank controlling
if ( m_pTank ! = NULL )
{ // if they've moved too far from the gun, or selected a weapon, unuse the gun
if ( m_pTank - > OnControls ( pev ) & & ! pev - > weaponmodel )
{
m_pTank - > Use ( this , this , USE_SET , 2 ) ; // try fire the gun
}
else
{ // they've moved off the platform
m_pTank - > Use ( this , this , USE_OFF , 0 ) ;
m_pTank = NULL ;
}
}
// do weapon stuff
ItemPostFrame ( ) ;
// check to see if player landed hard enough to make a sound
// falling farther than half of the maximum safe distance, but not as far a max safe distance will
// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half
// of maximum safe distance will make no sound. Falling farther than max safe distance will play a
// fallpain sound, and damage will be inflicted based on how far the player fell
if ( ( FBitSet ( pev - > flags , FL_ONGROUND ) ) & & ( pev - > health > 0 ) & & m_flFallVelocity > = PLAYER_FALL_PUNCH_THRESHHOLD )
{
float fvol = 0.5 ;
// ALERT ( at_console, "%f\n", m_flFallVelocity );
if ( pev - > watertype = = CONTENT_WATER )
{
// Did he hit the world or a non-moving entity?
// BUG - this happens all the time in water, especially when
// BUG - water has current force
// if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 )
// EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM);
}
else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED )
{ // after this point, we start doing damage
// No falling damage in discwar
/*
float flFallDamage = g_pGameRules - > FlPlayerFallDamage ( this ) ;
if ( flFallDamage > pev - > health )
{ //splat
// note: play on item channel because we play footstep landing on body channel
EMIT_SOUND ( ENT ( pev ) , CHAN_ITEM , " common/bodysplat.wav " , 1 , ATTN_NORM ) ;
}
if ( flFallDamage > 0 )
{
TakeDamage ( VARS ( eoNullEntity ) , VARS ( eoNullEntity ) , flFallDamage , DMG_FALL ) ;
pev - > punchangle . x = 0 ;
}
*/
fvol = 1.0 ;
}
else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 )
{
// EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_jumpland2.wav", 1, ATTN_NORM);
fvol = 0.85 ;
}
else if ( m_flFallVelocity < PLAYER_MIN_BOUNCE_SPEED )
{
fvol = 0 ;
}
if ( fvol > 0.0 )
{
// get current texture under player right away
m_flTimeStepSound = 0 ;
UpdateStepSound ( ) ;
}
if ( IsAlive ( ) )
{
SetAnimation ( PLAYER_WALK ) ;
}
}
if ( FBitSet ( pev - > flags , FL_ONGROUND ) )
{
if ( m_flFallVelocity > 64 & & ! g_pGameRules - > IsMultiplayer ( ) )
{
CSoundEnt : : InsertSound ( bits_SOUND_PLAYER , pev - > origin , m_flFallVelocity , 0.2 ) ;
// ALERT( at_console, "fall %f\n", m_flFallVelocity );
}
m_flFallVelocity = 0 ;
}
// select the proper animation for the player character
if ( IsAlive ( ) & & ( m_flTouchedByJumpPad < gpGlobals - > time ) )
{
if ( ! pev - > velocity . x & & ! pev - > velocity . y )
SetAnimation ( PLAYER_IDLE ) ;
else if ( ( pev - > velocity . x | | pev - > velocity . y ) & & ( FBitSet ( pev - > flags , FL_ONGROUND ) ) )
SetAnimation ( PLAYER_WALK ) ;
else if ( pev - > waterlevel > 1 )
SetAnimation ( PLAYER_WALK ) ;
}
if ( IsAlive ( ) & & ( m_flThrowTime ) & & ( m_flThrowTime + 0.25 < gpGlobals - > time ) )
{
m_Activity = ACT_BASE_WALK ;
m_flThrowTime = 0.0 ;
if ( ! pev - > velocity . x & & ! pev - > velocity . y )
{
SetAnimation ( PLAYER_IDLE ) ;
}
else
{
SetAnimation ( PLAYER_WALK ) ;
}
}
StudioFrameAdvance ( ) ;
CheckPowerups ( pev ) ;
UpdatePlayerSound ( ) ;
pt_end :
// Store old velocity for use in backpedalling animations
m_vecOldVelocity = pev - > velocity . Normalize ( ) ;
// Decay timers on weapons
// go through all of the weapons and make a list of the ones to pack
for ( int i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] )
{
CBasePlayerItem * pPlayerItem = m_rgpPlayerItems [ i ] ;
while ( pPlayerItem )
{
CBasePlayerWeapon * gun ;
gun = ( CBasePlayerWeapon * ) pPlayerItem - > GetWeaponPtr ( ) ;
if ( gun & & gun - > UseDecrement ( ) )
{
2024-08-21 02:58:27 +00:00
gun - > m_flNextPrimaryAttack = max ( gun - > m_flNextPrimaryAttack - gpGlobals - > frametime , - 1.0f ) ;
gun - > m_flNextSecondaryAttack = max ( gun - > m_flNextSecondaryAttack - gpGlobals - > frametime , - 0.001f ) ;
2013-08-30 20:34:05 +00:00
if ( gun - > m_flTimeWeaponIdle ! = 1000 )
{
2024-08-21 02:58:27 +00:00
gun - > m_flTimeWeaponIdle = max ( gun - > m_flTimeWeaponIdle - gpGlobals - > frametime , - 0.001f ) ;
2013-08-30 20:34:05 +00:00
}
}
pPlayerItem = pPlayerItem - > m_pNext ;
}
}
}
m_flNextAttack - = gpGlobals - > frametime ;
if ( m_flNextAttack < - 0.001 )
m_flNextAttack = - 0.001 ;
// Track button info so we can detect 'pressed' and 'released' buttons next frame
m_afButtonLast = pev - > button ;
}
// checks if the spot is clear of players
BOOL IsSpawnPointValid ( CBaseEntity * pPlayer , CBaseEntity * pSpot )
{
CBaseEntity * ent = NULL ;
if ( ! pSpot - > IsTriggered ( pPlayer ) )
{
return FALSE ;
}
while ( ( ent = UTIL_FindEntityInSphere ( ent , pSpot - > pev - > origin , 96 ) ) ! = NULL )
{
// if ent is a client, don't spawn on 'em
if ( ent - > IsPlayer ( ) & & ent ! = pPlayer )
{
if ( ( pPlayer - > pev - > groupinfo = = 0 ) | | ( ent - > pev - > groupinfo & pPlayer - > pev - > groupinfo ) )
return FALSE ;
}
}
// DISCWAR
// Make sure they're on the right team
if ( InArenaMode ( ) & & pSpot - > pev - > team ! = 0 & & pSpot - > pev - > team ! = pPlayer - > pev - > team )
return FALSE ;
return TRUE ;
}
DLL_GLOBAL CBaseEntity * g_pLastSpawn ;
inline int FNullEnt ( CBaseEntity * ent ) { return ( ent = = NULL ) | | FNullEnt ( ent - > edict ( ) ) ; }
/*
= = = = = = = = = = = =
EntSelectSpawnPoint
Returns the entity to spawn at
USES AND SETS GLOBAL g_pLastSpawn
= = = = = = = = = = = =
*/
edict_t * EntSelectSpawnPoint ( CBaseEntity * pPlayer )
{
CBaseEntity * pSpot ;
edict_t * player ;
player = pPlayer - > edict ( ) ;
EMIT_SOUND ( player , CHAN_AUTO , " r_tele1.wav " , 1 , ATTN_NORM ) ;
// choose a info_player_deathmatch point
if ( g_pGameRules - > IsCoOp ( ) )
{
pSpot = UTIL_FindEntityByClassname ( g_pLastSpawn , " info_player_coop " ) ;
if ( ! FNullEnt ( pSpot ) )
goto ReturnSpot ;
pSpot = UTIL_FindEntityByClassname ( g_pLastSpawn , " info_player_start " ) ;
if ( ! FNullEnt ( pSpot ) )
goto ReturnSpot ;
}
else if ( g_pGameRules - > IsDeathmatch ( ) )
{
pSpot = g_pLastSpawn ;
// Randomize the start spot
for ( int i = RANDOM_LONG ( 1 , 5 ) ; i > 0 ; i - - )
pSpot = UTIL_FindEntityByClassname ( pSpot , " info_player_deathmatch " ) ;
if ( FNullEnt ( pSpot ) ) // skip over the null point
pSpot = UTIL_FindEntityByClassname ( pSpot , " info_player_deathmatch " ) ;
CBaseEntity * pFirstSpot = pSpot ;
do
{
if ( pSpot )
{
// check if pSpot is valid
if ( IsSpawnPointValid ( pPlayer , pSpot ) )
{
if ( pSpot - > pev - > origin = = Vector ( 0 , 0 , 0 ) )
{
pSpot = UTIL_FindEntityByClassname ( pSpot , " info_player_deathmatch " ) ;
continue ;
}
// if so, go to pSpot
goto ReturnSpot ;
}
}
// increment pSpot
pSpot = UTIL_FindEntityByClassname ( pSpot , " info_player_deathmatch " ) ;
} while ( pSpot ! = pFirstSpot ) ; // loop if we're not back to the start
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
if ( ! FNullEnt ( pSpot ) )
{
CBaseEntity * ent = NULL ;
while ( ( ent = UTIL_FindEntityInSphere ( ent , pSpot - > pev - > origin , 128 ) ) ! = NULL )
{
// if ent is a client, kill em (unless they are ourselves)
if ( ent - > IsPlayer ( ) & & ! ( ent - > edict ( ) = = player ) & & ( ent - > pev - > groupinfo & player - > v . groupinfo ) & & ( ( CBasePlayer * ) pPlayer ) - > IsObserver ( ) = = false )
ent - > TakeDamage ( VARS ( INDEXENT ( 0 ) ) , VARS ( INDEXENT ( 0 ) ) , 300 , DMG_GENERIC | DMG_ALWAYSGIB ) ;
}
goto ReturnSpot ;
}
}
// If startspot is set, (re)spawn there.
if ( FStringNull ( gpGlobals - > startspot ) | | ! strlen ( STRING ( gpGlobals - > startspot ) ) )
{
pSpot = UTIL_FindEntityByClassname ( NULL , " info_player_start " ) ;
if ( ! FNullEnt ( pSpot ) )
goto ReturnSpot ;
}
else
{
pSpot = UTIL_FindEntityByTargetname ( NULL , STRING ( gpGlobals - > startspot ) ) ;
if ( ! FNullEnt ( pSpot ) )
goto ReturnSpot ;
}
ReturnSpot :
if ( FNullEnt ( pSpot ) )
{
ALERT ( at_error , " PutClientInServer: no info_player_start on level " ) ;
return INDEXENT ( 0 ) ;
}
g_pLastSpawn = pSpot ;
return pSpot - > edict ( ) ;
}
void CBasePlayer : : Spawn ( void )
{
pev - > classname = MAKE_STRING ( " player " ) ;
pev - > health = 100 ;
pev - > armorvalue = 0 ;
pev - > takedamage = DAMAGE_AIM ;
pev - > solid = SOLID_SLIDEBOX ;
pev - > movetype = MOVETYPE_WALK ;
pev - > max_health = pev - > health ;
pev - > flags = FL_CLIENT ;
pev - > air_finished = gpGlobals - > time + 12 ;
pev - > dmg = 2 ; // initial water damage
pev - > effects = 0 ;
pev - > deadflag = DEAD_NO ;
pev - > dmg_take = 0 ;
pev - > dmg_save = 0 ;
pev - > friction = 1.0 ;
pev - > gravity = 1.0 ;
m_bitsHUDDamage = - 1 ;
m_bitsDamageType = 0 ;
m_afPhysicsFlags = 0 ;
m_fLongJump = FALSE ; // no longjump module.
m_flTouchedByJumpPad = 0 ;
m_flNextAttack = gpGlobals - > time + 0.5 ; // Prevent fire
g_engfuncs . pfnSetPhysicsKeyValue ( edict ( ) , " slj " , " 0 " ) ;
g_engfuncs . pfnSetPhysicsKeyValue ( edict ( ) , " hl " , " 1 " ) ;
m_iFOV = 0 ; // init field of view.
m_iClientFOV = - 1 ; // make sure fov reset is sent
m_flNextDecalTime = 0 ; // let this player decal as soon as he spawns.
m_flgeigerDelay = gpGlobals - > time + 2.0 ; // wait a few seconds until user-defined message registrations
// are recieved by all clients
m_flTimeStepSound = 0 ;
m_iStepLeft = 0 ;
m_flFieldOfView = 0.5 ; // some monsters use this to determine whether or not the player is looking at them.
m_bloodColor = BLOOD_COLOR_RED ;
m_flNextAttack = UTIL_WeaponTimeBase ( ) ;
StartSneaking ( ) ;
m_iFlashBattery = 99 ;
m_flFlashLightTime = 1 ; // force first message
// dont let uninitialized value here hurt the player
m_flFallVelocity = 0 ;
g_pGameRules - > GetPlayerSpawnSpot ( this ) ;
SET_MODEL ( ENT ( pev ) , " models/player/male/male.mdl " ) ;
g_ulModelIndexPlayer = pev - > modelindex ;
pev - > sequence = LookupActivity ( ACT_IDLE ) ;
if ( FBitSet ( pev - > flags , FL_DUCKING ) )
UTIL_SetSize ( pev , VEC_DUCK_HULL_MIN , VEC_DUCK_HULL_MAX ) ;
else
UTIL_SetSize ( pev , VEC_HULL_MIN , VEC_HULL_MAX ) ;
pev - > view_ofs = VEC_VIEW ;
Precache ( ) ;
m_HackedGunPos = Vector ( 0 , 32 , 0 ) ;
if ( m_iPlayerSound = = SOUNDLIST_EMPTY )
{
ALERT ( at_console , " Couldn't alloc player sound slot! \n " ) ;
}
m_fNoPlayerSound = FALSE ; // normal sound behavior.
m_pLastItem = NULL ;
m_iClientHideHUD = - 1 ; // force this to be recalculated
m_fWeapon = FALSE ;
m_pClientActiveItem = NULL ;
m_iClientBattery = - 1 ;
// reset all ammo values to 0
for ( int i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
{
m_rgAmmo [ i ] = 0 ;
m_rgAmmoLast [ i ] = 0 ; // client ammo values also have to be reset (the death hud clear messages does on the client side)
}
m_lastx = m_lasty = 0 ;
g_pGameRules - > PlayerSpawn ( this ) ;
SetBodygroup ( 1 , 1 ) ;
ClearFreezeAndRender ( ) ;
}
void CBasePlayer : : Precache ( void )
{
// in the event that the player JUST spawned, and the level node graph
// was loaded, fix all of the node graph pointers before the game starts.
// !!!BUGBUG - now that we have multiplayer, this needs to be moved!
if ( WorldGraph . m_fGraphPresent & & ! WorldGraph . m_fGraphPointersSet )
{
if ( ! WorldGraph . FSetGraphPointers ( ) )
{
ALERT ( at_console , " **Graph pointers were not set! \n " ) ;
}
else
{
ALERT ( at_console , " **Graph Pointers Set! \n " ) ;
}
}
// SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific)
// because they need to precache before any clients have connected
// init geiger counter vars during spawn and each time
// we cross a level transition
m_flgeigerRange = 1000 ;
m_igeigerRangePrev = 1000 ;
m_bitsDamageType = 0 ;
m_bitsHUDDamage = - 1 ;
m_iClientBattery = - 1 ;
m_iTrain = TRAIN_NEW ;
// Make sure any necessary user messages have been registered
LinkUserMessages ( ) ;
m_iUpdateTime = 5 ; // won't update for 1/2 a second
if ( gInitHUD )
m_fInitHUD = TRUE ;
}
int CBasePlayer : : Save ( CSave & save )
{
if ( ! CBaseMonster : : Save ( save ) )
return 0 ;
return save . WriteFields ( " PLAYER " , this , m_playerSaveData , ARRAYSIZE ( m_playerSaveData ) ) ;
}
//
// Marks everything as new so the player will resend this to the hud.
//
void CBasePlayer : : RenewItems ( void )
{
}
int CBasePlayer : : Restore ( CRestore & restore )
{
if ( ! CBaseMonster : : Restore ( restore ) )
return 0 ;
int status = restore . ReadFields ( " PLAYER " , this , m_playerSaveData , ARRAYSIZE ( m_playerSaveData ) ) ;
SAVERESTOREDATA * pSaveData = ( SAVERESTOREDATA * ) gpGlobals - > pSaveData ;
// landmark isn't present.
if ( ! pSaveData - > fUseLandmark )
{
ALERT ( at_console , " No Landmark:%s \n " , pSaveData - > szLandmarkName ) ;
// default to normal spawn
edict_t * pentSpawnSpot = EntSelectSpawnPoint ( this ) ;
pev - > origin = VARS ( pentSpawnSpot ) - > origin + Vector ( 0 , 0 , 1 ) ;
pev - > angles = VARS ( pentSpawnSpot ) - > angles ;
}
pev - > v_angle . z = 0 ; // Clear out roll
pev - > angles = pev - > v_angle ;
pev - > fixangle = TRUE ; // turn this way immediately
// Copied from spawn() for now
m_bloodColor = BLOOD_COLOR_RED ;
g_ulModelIndexPlayer = pev - > modelindex ;
if ( FBitSet ( pev - > flags , FL_DUCKING ) )
{
// Use the crouch HACK
// FixPlayerCrouchStuck( edict() );
UTIL_SetSize ( pev , VEC_DUCK_HULL_MIN , VEC_DUCK_HULL_MAX ) ;
}
else
{
UTIL_SetSize ( pev , VEC_HULL_MIN , VEC_HULL_MAX ) ;
}
RenewItems ( ) ;
return status ;
}
void CBasePlayer : : SelectNextItem ( int iItem )
{
CBasePlayerItem * pItem ;
pItem = m_rgpPlayerItems [ iItem ] ;
if ( ! pItem )
return ;
if ( pItem = = m_pActiveItem )
{
// select the next one in the chain
pItem = m_pActiveItem - > m_pNext ;
if ( ! pItem )
{
return ;
}
CBasePlayerItem * pLast ;
pLast = pItem ;
while ( pLast - > m_pNext )
pLast = pLast - > m_pNext ;
// relink chain
pLast - > m_pNext = m_pActiveItem ;
m_pActiveItem - > m_pNext = NULL ;
m_rgpPlayerItems [ iItem ] = pItem ;
}
ResetAutoaim ( ) ;
// FIX, this needs to queue them up and delay
if ( m_pActiveItem )
{
m_pActiveItem - > Holster ( ) ;
}
m_pActiveItem = pItem ;
if ( m_pActiveItem )
{
m_pActiveItem - > Deploy ( ) ;
m_pActiveItem - > UpdateItemInfo ( ) ;
}
}
void CBasePlayer : : SelectItem ( const char * pstr )
{
if ( ! pstr )
return ;
CBasePlayerItem * pItem = NULL ;
for ( int i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] )
{
pItem = m_rgpPlayerItems [ i ] ;
while ( pItem )
{
if ( FClassnameIs ( pItem - > pev , pstr ) )
break ;
pItem = pItem - > m_pNext ;
}
}
if ( pItem )
break ;
}
if ( ! pItem )
return ;
if ( pItem = = m_pActiveItem )
return ;
ResetAutoaim ( ) ;
// FIX, this needs to queue them up and delay
if ( m_pActiveItem )
m_pActiveItem - > Holster ( ) ;
m_pLastItem = m_pActiveItem ;
m_pActiveItem = pItem ;
if ( m_pActiveItem )
{
m_pActiveItem - > Deploy ( ) ;
m_pActiveItem - > UpdateItemInfo ( ) ;
}
}
void CBasePlayer : : SelectLastItem ( void )
{
if ( ! m_pLastItem )
{
return ;
}
if ( m_pActiveItem & & ! m_pActiveItem - > CanHolster ( ) )
{
return ;
}
ResetAutoaim ( ) ;
// FIX, this needs to queue them up and delay
if ( m_pActiveItem )
m_pActiveItem - > Holster ( ) ;
CBasePlayerItem * pTemp = m_pActiveItem ;
m_pActiveItem = m_pLastItem ;
m_pLastItem = pTemp ;
m_pActiveItem - > Deploy ( ) ;
m_pActiveItem - > UpdateItemInfo ( ) ;
}
//==============================================
// HasWeapons - do I have any weapons at all?
//==============================================
BOOL CBasePlayer : : HasWeapons ( void )
{
int i ;
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] )
{
return TRUE ;
}
}
return FALSE ;
}
void CBasePlayer : : SelectPrevItem ( int iItem )
{
}
const char * CBasePlayer : : TeamID ( void )
{
if ( pev = = NULL ) // Not fully connected yet
return " " ;
// return their team name
return m_szTeamName ;
}
//==============================================
// !!!UNDONE:ultra temporary SprayCan entity to apply
// decal frame at a time. For PreAlpha CD
//==============================================
class CSprayCan : public CBaseEntity
{
public :
void Spawn ( entvars_t * pevOwner ) ;
void Think ( void ) ;
virtual int ObjectCaps ( void ) { return FCAP_DONT_SAVE ; }
} ;
void CSprayCan : : Spawn ( entvars_t * pevOwner )
{
pev - > origin = pevOwner - > origin + Vector ( 0 , 0 , 32 ) ;
pev - > angles = pevOwner - > v_angle ;
pev - > owner = ENT ( pevOwner ) ;
pev - > frame = 0 ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
EMIT_SOUND ( ENT ( pev ) , CHAN_VOICE , " player/sprayer.wav " , 1 , ATTN_NORM ) ;
}
void CSprayCan : : Think ( void )
{
TraceResult tr ;
int playernum ;
int nFrames ;
CBasePlayer * pPlayer ;
pPlayer = ( CBasePlayer * ) GET_PRIVATE ( pev - > owner ) ;
if ( pPlayer )
nFrames = pPlayer - > GetCustomDecalFrames ( ) ;
else
nFrames = - 1 ;
playernum = ENTINDEX ( pev - > owner ) ;
// ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames);
UTIL_MakeVectors ( pev - > angles ) ;
UTIL_TraceLine ( pev - > origin , pev - > origin + gpGlobals - > v_forward * 128 , ignore_monsters , pev - > owner , & tr ) ;
// No customization present.
if ( nFrames = = - 1 )
{
UTIL_DecalTrace ( & tr , DECAL_LAMBDA6 ) ;
UTIL_Remove ( this ) ;
}
else
{
UTIL_PlayerDecalTrace ( & tr , playernum , pev - > frame , TRUE ) ;
// Just painted last custom frame.
if ( pev - > frame + + > = ( nFrames - 1 ) )
UTIL_Remove ( this ) ;
}
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
class CBloodSplat : public CBaseEntity
{
public :
void Spawn ( entvars_t * pevOwner ) ;
void Spray ( void ) ;
} ;
void CBloodSplat : : Spawn ( entvars_t * pevOwner )
{
pev - > origin = pevOwner - > origin + Vector ( 0 , 0 , 32 ) ;
pev - > angles = pevOwner - > v_angle ;
pev - > owner = ENT ( pevOwner ) ;
SetThink ( & CBloodSplat : : Spray ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
void CBloodSplat : : Spray ( void )
{
TraceResult tr ;
if ( g_Language ! = LANGUAGE_GERMAN )
{
UTIL_MakeVectors ( pev - > angles ) ;
UTIL_TraceLine ( pev - > origin , pev - > origin + gpGlobals - > v_forward * 128 , ignore_monsters , pev - > owner , & tr ) ;
UTIL_BloodDecalTrace ( & tr , BLOOD_COLOR_RED ) ;
}
SetThink ( & CBloodSplat : : SUB_Remove ) ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
}
//==============================================
void CBasePlayer : : GiveNamedItem ( const char * pszName )
{
edict_t * pent ;
int istr = MAKE_STRING ( pszName ) ;
pent = CREATE_NAMED_ENTITY ( istr ) ;
if ( FNullEnt ( pent ) )
{
ALERT ( at_console , " NULL Ent in GiveNamedItem! \n " ) ;
return ;
}
VARS ( pent ) - > origin = pev - > origin ;
pent - > v . spawnflags | = SF_NORESPAWN ;
DispatchSpawn ( pent ) ;
DispatchTouch ( pent , ENT ( pev ) ) ;
}
CBaseEntity * FindEntityForward ( CBaseEntity * pMe )
{
TraceResult tr ;
UTIL_MakeVectors ( pMe - > pev - > v_angle ) ;
UTIL_TraceLine ( pMe - > pev - > origin + pMe - > pev - > view_ofs , pMe - > pev - > origin + pMe - > pev - > view_ofs + gpGlobals - > v_forward * 8192 , dont_ignore_monsters , pMe - > edict ( ) , & tr ) ;
if ( tr . flFraction ! = 1.0 & & ! FNullEnt ( tr . pHit ) )
{
CBaseEntity * pHit = CBaseEntity : : Instance ( tr . pHit ) ;
return pHit ;
}
return NULL ;
}
BOOL CBasePlayer : : FlashlightIsOn ( void )
{
return FBitSet ( pev - > effects , EF_DIMLIGHT ) ;
}
void CBasePlayer : : FlashlightTurnOn ( void )
{
if ( ! g_pGameRules - > FAllowFlashlight ( ) )
{
return ;
}
if ( ( pev - > weapons & ( 1 < < WEAPON_SUIT ) ) )
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_WEAPON , SOUND_FLASHLIGHT_ON , 1.0 , ATTN_NORM , 0 , PITCH_NORM ) ;
SetBits ( pev - > effects , EF_DIMLIGHT ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgFlashlight , NULL , pev ) ;
WRITE_BYTE ( 1 ) ;
WRITE_BYTE ( m_iFlashBattery ) ;
MESSAGE_END ( ) ;
m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals - > time ;
}
}
void CBasePlayer : : FlashlightTurnOff ( void )
{
EMIT_SOUND_DYN ( ENT ( pev ) , CHAN_WEAPON , SOUND_FLASHLIGHT_OFF , 1.0 , ATTN_NORM , 0 , PITCH_NORM ) ;
ClearBits ( pev - > effects , EF_DIMLIGHT ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgFlashlight , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( m_iFlashBattery ) ;
MESSAGE_END ( ) ;
m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals - > time ;
}
/*
= = = = = = = = = = = = = = =
ForceClientDllUpdate
When recording a demo , we need to have the server tell us the entire client state
so that the client side . dll can behave correctly .
Reset stuff so that the state is transmitted .
= = = = = = = = = = = = = = =
*/
void CBasePlayer : : ForceClientDllUpdate ( void )
{
m_iClientHealth = - 1 ;
m_iClientBattery = - 1 ;
m_iTrain | = TRAIN_NEW ; // Force new train message.
m_fWeapon = FALSE ; // Force weapon send
m_fKnownItem = FALSE ; // Force weaponinit messages.
// Now force all the necessary messages
// to be sent.
UpdateClientData ( ) ;
}
/*
= = = = = = = = = = = =
ImpulseCommands
= = = = = = = = = = = =
*/
void CBasePlayer : : ImpulseCommands ( )
{
TraceResult tr ; // UNDONE: kill me! This is temporary for PreAlpha CDs
// Handle use events
PlayerUse ( ) ;
int iImpulse = ( int ) pev - > impulse ;
switch ( iImpulse )
{
case 99 :
{
int iOn ;
if ( ! gmsgLogo )
{
iOn = 1 ;
gmsgLogo = REG_USER_MSG ( " Logo " , 1 ) ;
}
else
{
iOn = 0 ;
}
ASSERT ( gmsgLogo > 0 ) ;
// send "health" update message
MESSAGE_BEGIN ( MSG_ONE , gmsgLogo , NULL , pev ) ;
WRITE_BYTE ( iOn ) ;
MESSAGE_END ( ) ;
if ( ! iOn )
gmsgLogo = 0 ;
break ;
}
case 100 :
// temporary flashlight for level designers
if ( FlashlightIsOn ( ) )
{
FlashlightTurnOff ( ) ;
}
else
{
FlashlightTurnOn ( ) ;
}
break ;
case 201 : // paint decal
if ( gpGlobals - > time < m_flNextDecalTime )
{
// too early!
break ;
}
UTIL_MakeVectors ( pev - > v_angle ) ;
UTIL_TraceLine ( pev - > origin + pev - > view_ofs , pev - > origin + pev - > view_ofs + gpGlobals - > v_forward * 128 , ignore_monsters , ENT ( pev ) , & tr ) ;
if ( tr . flFraction ! = 1.0 )
{ // line hit something, so paint a decal
m_flNextDecalTime = gpGlobals - > time + CVAR_GET_FLOAT ( " decalfrequency " ) ;
CSprayCan * pCan = GetClassPtr ( ( CSprayCan * ) NULL ) ;
pCan - > Spawn ( pev ) ;
}
break ;
case 204 : // Demo recording, update client dll specific data again.
ForceClientDllUpdate ( ) ;
break ;
default :
// check all of the cheat impulse commands now
CheatImpulseCommands ( iImpulse ) ;
break ;
}
pev - > impulse = 0 ;
}
//=========================================================
//=========================================================
void CBasePlayer : : CheatImpulseCommands ( int iImpulse )
{
# if !defined( HLDEMO_BUILD )
2024-08-21 02:58:27 +00:00
if ( CVAR_GET_FLOAT ( " sv_cheats " ) = = 0.0 )
2013-08-30 20:34:05 +00:00
{
return ;
}
CBaseEntity * pEntity ;
TraceResult tr ;
switch ( iImpulse )
{
case 76 :
{
if ( ! giPrecacheGrunt )
{
giPrecacheGrunt = 1 ;
ALERT ( at_console , " You must now restart to use Grunt-o-matic. \n " ) ;
}
else
{
UTIL_MakeVectors ( Vector ( 0 , pev - > v_angle . y , 0 ) ) ;
Create ( " monster_human_grunt " , pev - > origin + gpGlobals - > v_forward * 128 , pev - > angles ) ;
}
break ;
}
case 101 :
gEvilImpulse101 = TRUE ;
GiveNamedItem ( " item_suit " ) ;
GiveNamedItem ( " item_battery " ) ;
GiveNamedItem ( " weapon_crowbar " ) ;
GiveNamedItem ( " weapon_9mmhandgun " ) ;
GiveNamedItem ( " ammo_9mmclip " ) ;
GiveNamedItem ( " weapon_shotgun " ) ;
GiveNamedItem ( " ammo_buckshot " ) ;
GiveNamedItem ( " weapon_9mmAR " ) ;
GiveNamedItem ( " ammo_9mmAR " ) ;
GiveNamedItem ( " ammo_ARgrenades " ) ;
GiveNamedItem ( " weapon_handgrenade " ) ;
GiveNamedItem ( " weapon_tripmine " ) ;
# ifndef OEM_BUILD
GiveNamedItem ( " weapon_357 " ) ;
GiveNamedItem ( " ammo_357 " ) ;
GiveNamedItem ( " weapon_crossbow " ) ;
GiveNamedItem ( " ammo_crossbow " ) ;
GiveNamedItem ( " weapon_egon " ) ;
GiveNamedItem ( " weapon_gauss " ) ;
GiveNamedItem ( " ammo_gaussclip " ) ;
GiveNamedItem ( " weapon_rpg " ) ;
GiveNamedItem ( " ammo_rpgclip " ) ;
GiveNamedItem ( " weapon_satchel " ) ;
GiveNamedItem ( " weapon_snark " ) ;
GiveNamedItem ( " weapon_hornetgun " ) ;
# endif
gEvilImpulse101 = FALSE ;
break ;
case 102 :
// Gibbage!!!
CGib : : SpawnRandomGibs ( pev , 1 , 1 ) ;
break ;
case 103 :
// What the hell are you doing?
pEntity = FindEntityForward ( this ) ;
if ( pEntity )
{
CBaseMonster * pMonster = pEntity - > MyMonsterPointer ( ) ;
if ( pMonster )
pMonster - > ReportAIState ( ) ;
}
break ;
case 104 :
// Dump all of the global state varaibles (and global entity names)
gGlobalState . DumpGlobals ( ) ;
break ;
case 105 : // player makes no sound for monsters to hear.
{
if ( m_fNoPlayerSound )
{
ALERT ( at_console , " Player is audible \n " ) ;
m_fNoPlayerSound = FALSE ;
}
else
{
ALERT ( at_console , " Player is silent \n " ) ;
m_fNoPlayerSound = TRUE ;
}
break ;
}
case 106 :
// Give me the classname and targetname of this entity.
pEntity = FindEntityForward ( this ) ;
if ( pEntity )
{
ALERT ( at_console , " Classname: %s " , STRING ( pEntity - > pev - > classname ) ) ;
if ( ! FStringNull ( pEntity - > pev - > targetname ) )
{
ALERT ( at_console , " - Targetname: %s \n " , STRING ( pEntity - > pev - > targetname ) ) ;
}
else
{
ALERT ( at_console , " - TargetName: No Targetname \n " ) ;
}
ALERT ( at_console , " Model: %s \n " , STRING ( pEntity - > pev - > model ) ) ;
if ( pEntity - > pev - > globalname )
ALERT ( at_console , " Globalname: %s \n " , STRING ( pEntity - > pev - > globalname ) ) ;
}
break ;
case 107 :
{
TraceResult tr ;
edict_t * pWorld = g_engfuncs . pfnPEntityOfEntIndex ( 0 ) ;
Vector start = pev - > origin + pev - > view_ofs ;
Vector end = start + gpGlobals - > v_forward * 1024 ;
UTIL_TraceLine ( start , end , ignore_monsters , edict ( ) , & tr ) ;
if ( tr . pHit )
pWorld = tr . pHit ;
const char * pTextureName = TRACE_TEXTURE ( pWorld , start , end ) ;
if ( pTextureName )
ALERT ( at_console , " Texture: %s \n " , pTextureName ) ;
}
break ;
case 195 : // show shortest paths for entire level to nearest node
{
Create ( " node_viewer_fly " , pev - > origin , pev - > angles ) ;
}
break ;
case 196 : // show shortest paths for entire level to nearest node
{
Create ( " node_viewer_large " , pev - > origin , pev - > angles ) ;
}
break ;
case 197 : // show shortest paths for entire level to nearest node
{
Create ( " node_viewer_human " , pev - > origin , pev - > angles ) ;
}
break ;
case 199 : // show nearest node and all connections
{
ALERT ( at_console , " %d \n " , WorldGraph . FindNearestNode ( pev - > origin , bits_NODE_GROUP_REALM ) ) ;
WorldGraph . ShowNodeConnections ( WorldGraph . FindNearestNode ( pev - > origin , bits_NODE_GROUP_REALM ) ) ;
}
break ;
case 202 : // Random blood splatter
UTIL_MakeVectors ( pev - > v_angle ) ;
UTIL_TraceLine ( pev - > origin + pev - > view_ofs , pev - > origin + pev - > view_ofs + gpGlobals - > v_forward * 128 , ignore_monsters , ENT ( pev ) , & tr ) ;
if ( tr . flFraction ! = 1.0 )
{ // line hit something, so paint a decal
CBloodSplat * pBlood = GetClassPtr ( ( CBloodSplat * ) NULL ) ;
pBlood - > Spawn ( pev ) ;
}
break ;
case 203 : // remove creature.
pEntity = FindEntityForward ( this ) ;
if ( pEntity )
{
if ( pEntity - > pev - > takedamage )
pEntity - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
}
break ;
}
# endif // HLDEMO_BUILD
}
//
// Add a weapon to the player (Item == Weapon == Selectable Object)
//
int CBasePlayer : : AddPlayerItem ( CBasePlayerItem * pItem )
{
CBasePlayerItem * pInsert ;
pInsert = m_rgpPlayerItems [ pItem - > iItemSlot ( ) ] ;
while ( pInsert )
{
if ( FClassnameIs ( pInsert - > pev , STRING ( pItem - > pev - > classname ) ) )
{
if ( pItem - > AddDuplicate ( pInsert ) )
{
g_pGameRules - > PlayerGotWeapon ( this , pItem ) ;
pItem - > CheckRespawn ( ) ;
// ugly hack to update clip w/o an update clip message
pInsert - > UpdateItemInfo ( ) ;
if ( m_pActiveItem )
m_pActiveItem - > UpdateItemInfo ( ) ;
pItem - > Kill ( ) ;
}
else if ( gEvilImpulse101 )
{
// FIXME: remove anyway for deathmatch testing
pItem - > Kill ( ) ;
}
return FALSE ;
}
pInsert = pInsert - > m_pNext ;
}
if ( pItem - > AddToPlayer ( this ) )
{
g_pGameRules - > PlayerGotWeapon ( this , pItem ) ;
pItem - > CheckRespawn ( ) ;
pItem - > m_pNext = m_rgpPlayerItems [ pItem - > iItemSlot ( ) ] ;
m_rgpPlayerItems [ pItem - > iItemSlot ( ) ] = pItem ;
// should we switch to this item?
if ( g_pGameRules - > FShouldSwitchWeapon ( this , pItem ) )
{
SwitchWeapon ( pItem ) ;
}
return TRUE ;
}
else if ( gEvilImpulse101 )
{
// FIXME: remove anyway for deathmatch testing
pItem - > Kill ( ) ;
}
return FALSE ;
}
int CBasePlayer : : RemovePlayerItem ( CBasePlayerItem * pItem )
{
if ( m_pActiveItem = = pItem )
{
ResetAutoaim ( ) ;
pItem - > Holster ( ) ;
pItem - > pev - > nextthink = 0 ; // crowbar may be trying to swing again, etc.
pItem - > SetThink ( NULL ) ;
m_pActiveItem = NULL ;
pev - > viewmodel = 0 ;
pev - > weaponmodel = 0 ;
}
2024-08-21 02:58:27 +00:00
if ( m_pLastItem = = pItem )
2013-08-30 20:34:05 +00:00
m_pLastItem = NULL ;
CBasePlayerItem * pPrev = m_rgpPlayerItems [ pItem - > iItemSlot ( ) ] ;
if ( pPrev = = pItem )
{
m_rgpPlayerItems [ pItem - > iItemSlot ( ) ] = pItem - > m_pNext ;
return TRUE ;
}
else
{
while ( pPrev & & pPrev - > m_pNext ! = pItem )
{
pPrev = pPrev - > m_pNext ;
}
if ( pPrev )
{
pPrev - > m_pNext = pItem - > m_pNext ;
return TRUE ;
}
}
return FALSE ;
}
//
// Returns the unique ID for the ammo, or -1 if error
//
int CBasePlayer : : GiveAmmo ( int iCount , char * szName , int iMax )
{
if ( ! szName )
{
// no ammo.
return - 1 ;
}
if ( ! g_pGameRules - > CanHaveAmmo ( this , szName , iMax ) )
{
// game rules say I can't have any more of this ammo type.
return - 1 ;
}
int i = 0 ;
i = GetAmmoIndex ( szName ) ;
if ( i < 0 | | i > = MAX_AMMO_SLOTS )
return - 1 ;
int iAdd = min ( iCount , iMax - m_rgAmmo [ i ] ) ;
if ( iAdd < 1 )
return i ;
m_rgAmmo [ i ] + = iAdd ;
if ( gmsgAmmoPickup ) // make sure the ammo messages have been linked first
{
// Send the message that ammo has been picked up
MESSAGE_BEGIN ( MSG_ONE , gmsgAmmoPickup , NULL , pev ) ;
WRITE_BYTE ( GetAmmoIndex ( szName ) ) ; // ammo ID
WRITE_BYTE ( iAdd ) ; // amount
MESSAGE_END ( ) ;
}
return i ;
}
/*
= = = = = = = = = = = =
ItemPreFrame
Called every frame by the player PreThink
= = = = = = = = = = = =
*/
void CBasePlayer : : ItemPreFrame ( )
{
if ( m_flNextAttack > 0 )
{
return ;
}
if ( ! m_pActiveItem )
return ;
m_pActiveItem - > ItemPreFrame ( ) ;
}
/*
= = = = = = = = = = = =
ItemPostFrame
Called every frame by the player PostThink
= = = = = = = = = = = =
*/
void CBasePlayer : : ItemPostFrame ( )
{
static int fInSelect = FALSE ;
// check if the player is using a tank
if ( m_pTank ! = NULL )
return ;
if ( m_flNextAttack > 0 )
{
return ;
}
ImpulseCommands ( ) ;
if ( ! m_pActiveItem )
return ;
m_pActiveItem - > ItemPostFrame ( ) ;
}
int CBasePlayer : : AmmoInventory ( int iAmmoIndex )
{
if ( iAmmoIndex = = - 1 )
{
return - 1 ;
}
return m_rgAmmo [ iAmmoIndex ] ;
}
int CBasePlayer : : GetAmmoIndex ( const char * psz )
{
int i ;
if ( ! psz )
return - 1 ;
for ( i = 1 ; i < MAX_AMMO_SLOTS ; i + + )
{
if ( ! CBasePlayerItem : : AmmoInfoArray [ i ] . pszName )
continue ;
if ( stricmp ( psz , CBasePlayerItem : : AmmoInfoArray [ i ] . pszName ) = = 0 )
return i ;
}
return - 1 ;
}
// Called from UpdateClientData
// makes sure the client has all the necessary ammo info, if values have changed
void CBasePlayer : : SendAmmoUpdate ( void )
{
for ( int i = 0 ; i < MAX_AMMO_SLOTS ; i + + )
{
if ( m_rgAmmo [ i ] ! = m_rgAmmoLast [ i ] )
{
m_rgAmmoLast [ i ] = m_rgAmmo [ i ] ;
ASSERT ( m_rgAmmo [ i ] > = 0 ) ;
ASSERT ( m_rgAmmo [ i ] < 255 ) ;
// send "Ammo" update message
MESSAGE_BEGIN ( MSG_ONE , gmsgAmmoX , NULL , pev ) ;
WRITE_BYTE ( i ) ;
WRITE_BYTE ( max ( min ( m_rgAmmo [ i ] , 254 ) , 0 ) ) ; // clamp the value to one byte
MESSAGE_END ( ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
UpdateClientData
resends any changed player HUD info to the client .
Called every frame by PlayerPreThink
Also called at start of demo recording and playback by
ForceClientDllUpdate to ensure the demo gets messages
reflecting all of the HUD state info .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void CBasePlayer : : UpdateClientData ( void )
{
if ( m_fInitHUD )
{
m_fInitHUD = FALSE ;
gInitHUD = FALSE ;
m_flSendArenaStatus = gpGlobals - > time = 1.0f ;
MESSAGE_BEGIN ( MSG_ONE , gmsgResetHUD , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
MESSAGE_END ( ) ;
if ( ! m_fGameHUDInitialized )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgInitHUD , NULL , pev ) ;
MESSAGE_END ( ) ;
g_pGameRules - > InitHUD ( this ) ;
m_fGameHUDInitialized = TRUE ;
if ( g_pGameRules - > IsMultiplayer ( ) )
{
FireTargets ( " game_playerjoin " , this , this , USE_TOGGLE , 0 ) ;
}
}
FireTargets ( " game_playerspawn " , this , this , USE_TOGGLE , 0 ) ;
}
if ( m_iHideHUD ! = m_iClientHideHUD )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgHideWeapon , NULL , pev ) ;
WRITE_BYTE ( m_iHideHUD ) ;
MESSAGE_END ( ) ;
m_iClientHideHUD = m_iHideHUD ;
}
if ( m_iFOV ! = m_iClientFOV )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgSetFOV , NULL , pev ) ;
WRITE_BYTE ( m_iFOV ) ;
MESSAGE_END ( ) ;
// cache FOV change at end of function, so weapon updates can see that FOV has changed
}
// HACKHACK -- send the message to display the game title
if ( gDisplayTitle )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgShowGameTitle , NULL , pev ) ;
WRITE_BYTE ( 0 ) ;
MESSAGE_END ( ) ;
gDisplayTitle = 0 ;
}
if ( pev - > health ! = m_iClientHealth )
{
# define clamp( val, min, max ) ( ((val) > (max)) ? (max) : ( ((val) < (min)) ? (min) : (val) ) )
int iHealth = clamp ( pev - > health , 0 , 255 ) ; // make sure that no negative health values are sent
if ( pev - > health > 0.0f & & pev - > health < = 1.0f )
iHealth = 1 ;
// send "health" update message
MESSAGE_BEGIN ( MSG_ONE , gmsgHealth , NULL , pev ) ;
WRITE_BYTE ( iHealth ) ;
MESSAGE_END ( ) ;
m_iClientHealth = pev - > health ;
}
if ( pev - > armorvalue ! = m_iClientBattery )
{
m_iClientBattery = pev - > armorvalue ;
ASSERT ( gmsgBattery > 0 ) ;
// send "health" update message
MESSAGE_BEGIN ( MSG_ONE , gmsgBattery , NULL , pev ) ;
WRITE_SHORT ( ( int ) pev - > armorvalue ) ;
MESSAGE_END ( ) ;
}
if ( pev - > dmg_take | | pev - > dmg_save | | m_bitsHUDDamage ! = m_bitsDamageType )
{
// Comes from inside me if not set
Vector damageOrigin = pev - > origin ;
// send "damage" message
// causes screen to flash, and pain compass to show direction of damage
edict_t * other = pev - > dmg_inflictor ;
if ( other )
{
CBaseEntity * pEntity = CBaseEntity : : Instance ( other ) ;
if ( pEntity )
damageOrigin = pEntity - > Center ( ) ;
}
// only send down damage type that have hud art
int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD ;
MESSAGE_BEGIN ( MSG_ONE , gmsgDamage , NULL , pev ) ;
WRITE_BYTE ( pev - > dmg_save ) ;
WRITE_BYTE ( pev - > dmg_take ) ;
WRITE_LONG ( visibleDamageBits ) ;
WRITE_COORD ( damageOrigin . x ) ;
WRITE_COORD ( damageOrigin . y ) ;
WRITE_COORD ( damageOrigin . z ) ;
MESSAGE_END ( ) ;
pev - > dmg_take = 0 ;
pev - > dmg_save = 0 ;
m_bitsHUDDamage = m_bitsDamageType ;
// Clear off non-time-based damage indicators
m_bitsDamageType & = DMG_TIMEBASED ;
}
// Update Flashlight
if ( ( m_flFlashLightTime ) & & ( m_flFlashLightTime < = gpGlobals - > time ) )
{
if ( FlashlightIsOn ( ) )
{
if ( m_iFlashBattery )
{
m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals - > time ;
m_iFlashBattery - - ;
if ( ! m_iFlashBattery )
FlashlightTurnOff ( ) ;
}
}
else
{
if ( m_iFlashBattery < 100 )
{
m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals - > time ;
m_iFlashBattery + + ;
}
else
m_flFlashLightTime = 0 ;
}
MESSAGE_BEGIN ( MSG_ONE , gmsgFlashBattery , NULL , pev ) ;
WRITE_BYTE ( m_iFlashBattery ) ;
MESSAGE_END ( ) ;
}
if ( m_iTrain & TRAIN_NEW )
{
ASSERT ( gmsgTrain > 0 ) ;
// send "health" update message
MESSAGE_BEGIN ( MSG_ONE , gmsgTrain , NULL , pev ) ;
WRITE_BYTE ( m_iTrain & 0xF ) ;
MESSAGE_END ( ) ;
m_iTrain & = ~ TRAIN_NEW ;
}
//
// New Weapon?
//
if ( ! m_fKnownItem )
{
m_fKnownItem = TRUE ;
// WeaponInit Message
// byte = # of weapons
//
// for each weapon:
// byte name str length (not including null)
// bytes... name
// byte Ammo Type
// byte Ammo2 Type
// byte bucket
// byte bucket pos
// byte flags
// ???? Icons
// Send ALL the weapon info now
int i ;
for ( i = 0 ; i < MAX_WEAPONS ; i + + )
{
ItemInfo & II = CBasePlayerItem : : ItemInfoArray [ i ] ;
if ( ! II . iId )
continue ;
const char * pszName ;
if ( ! II . pszName )
pszName = " Empty " ;
else
pszName = II . pszName ;
MESSAGE_BEGIN ( MSG_ONE , gmsgWeaponList , NULL , pev ) ;
WRITE_STRING ( pszName ) ; // string weapon name
WRITE_BYTE ( GetAmmoIndex ( II . pszAmmo1 ) ) ; // byte Ammo Type
WRITE_BYTE ( II . iMaxAmmo1 ) ; // byte Max Ammo 1
WRITE_BYTE ( GetAmmoIndex ( II . pszAmmo2 ) ) ; // byte Ammo2 Type
WRITE_BYTE ( II . iMaxAmmo2 ) ; // byte Max Ammo 2
WRITE_BYTE ( II . iSlot ) ; // byte bucket
WRITE_BYTE ( II . iPosition ) ; // byte bucket pos
WRITE_BYTE ( II . iId ) ; // byte id (bit index into pev->weapons)
WRITE_BYTE ( II . iFlags ) ; // byte Flags
MESSAGE_END ( ) ;
}
}
SendAmmoUpdate ( ) ;
// Update all the items
for ( int i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
if ( m_rgpPlayerItems [ i ] ) // each item updates it's successors
m_rgpPlayerItems [ i ] - > UpdateClientData ( this ) ;
}
// Cache and client weapon change
m_pClientActiveItem = m_pActiveItem ;
m_iClientFOV = m_iFOV ;
if ( ( m_iClientFrags ! = pev - > frags ) | | ( m_iClientDeaths ! = m_iDeaths ) | | ( m_iClientPlayerClass ! = pev - > playerclass ) | | ( m_iClientTeam ! = pev - > team ) )
{
// update all players with this info, for their scoreboards
MESSAGE_BEGIN ( MSG_ALL , gmsgScoreInfo ) ;
WRITE_BYTE ( ENTINDEX ( edict ( ) ) ) ;
WRITE_SHORT ( pev - > frags ) ;
WRITE_SHORT ( m_iDeaths ) ;
WRITE_SHORT ( pev - > playerclass ) ;
WRITE_SHORT ( pev - > team ) ;
MESSAGE_END ( ) ;
m_iClientPlayerClass = pev - > playerclass ;
m_iClientTeam = pev - > team ;
m_iClientDeaths = m_iDeaths ;
m_iClientFrags = pev - > frags ;
}
// Update Freeze
if ( m_iFrozen ! = m_iClientFrozen )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgFrozen , NULL , pev ) ;
WRITE_BYTE ( m_iFrozen ) ;
MESSAGE_END ( ) ;
m_iClientFrozen = m_iFrozen ;
}
}
//=========================================================
// FBecomeProne - Overridden for the player to set the proper
// physics flags when a barnacle grabs player.
//=========================================================
BOOL CBasePlayer : : FBecomeProne ( void )
{
m_afPhysicsFlags | = PFLAG_ONBARNACLE ;
return TRUE ;
}
//=========================================================
// BarnacleVictimBitten - bad name for a function that is called
// by Barnacle victims when the barnacle pulls their head
// into its mouth. For the player, just die.
//=========================================================
void CBasePlayer : : BarnacleVictimBitten ( entvars_t * pevBarnacle )
{
TakeDamage ( pevBarnacle , pevBarnacle , pev - > health + pev - > armorvalue , DMG_SLASH | DMG_ALWAYSGIB ) ;
}
//=========================================================
// BarnacleVictimReleased - overridden for player who has
// physics flags concerns.
//=========================================================
void CBasePlayer : : BarnacleVictimReleased ( void )
{
m_afPhysicsFlags & = ~ PFLAG_ONBARNACLE ;
}
//=========================================================
// Illumination
// return player light level plus virtual muzzle flash
//=========================================================
int CBasePlayer : : Illumination ( void )
{
int iIllum = CBaseEntity : : Illumination ( ) ;
iIllum + = m_iWeaponFlash ;
if ( iIllum > 255 )
return 255 ;
return iIllum ;
}
void CBasePlayer : : EnableControl ( BOOL fControl )
{
if ( ! fControl )
pev - > flags | = FL_FROZEN ;
else
pev - > flags & = ~ FL_FROZEN ;
}
# define DOT_1DEGREE 0.9998476951564
# define DOT_2DEGREE 0.9993908270191
# define DOT_3DEGREE 0.9986295347546
# define DOT_4DEGREE 0.9975640502598
# define DOT_5DEGREE 0.9961946980917
# define DOT_6DEGREE 0.9945218953683
# define DOT_7DEGREE 0.9925461516413
# define DOT_8DEGREE 0.9902680687416
# define DOT_9DEGREE 0.9876883405951
# define DOT_10DEGREE 0.9848077530122
# define DOT_15DEGREE 0.9659258262891
# define DOT_20DEGREE 0.9396926207859
# define DOT_25DEGREE 0.9063077870367
//=========================================================
// Autoaim
// set crosshair position to point to enemey
//=========================================================
Vector CBasePlayer : : GetAutoaimVector ( float flDelta )
{
if ( g_iSkillLevel = = SKILL_HARD )
{
UTIL_MakeVectors ( pev - > v_angle + pev - > punchangle ) ;
return gpGlobals - > v_forward ;
}
Vector vecSrc = GetGunPosition ( ) ;
float flDist = 8192 ;
// always use non-sticky autoaim
// UNDONE: use sever variable to chose!
if ( 1 | | g_iSkillLevel = = SKILL_MEDIUM )
{
m_vecAutoAim = Vector ( 0 , 0 , 0 ) ;
// flDelta *= 0.5;
}
BOOL m_fOldTargeting = m_fOnTarget ;
Vector angles = AutoaimDeflection ( vecSrc , flDist , flDelta ) ;
// update ontarget if changed
if ( ! g_pGameRules - > AllowAutoTargetCrosshair ( ) )
m_fOnTarget = 0 ;
else if ( m_fOldTargeting ! = m_fOnTarget )
{
m_pActiveItem - > UpdateItemInfo ( ) ;
}
if ( angles . x > 180 )
angles . x - = 360 ;
if ( angles . x < - 180 )
angles . x + = 360 ;
if ( angles . y > 180 )
angles . y - = 360 ;
if ( angles . y < - 180 )
angles . y + = 360 ;
if ( angles . x > 25 )
angles . x = 25 ;
if ( angles . x < - 25 )
angles . x = - 25 ;
if ( angles . y > 12 )
angles . y = 12 ;
if ( angles . y < - 12 )
angles . y = - 12 ;
// always use non-sticky autoaim
// UNDONE: use sever variable to chose!
if ( 0 | | g_iSkillLevel = = SKILL_EASY )
{
m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33 ;
}
else
{
m_vecAutoAim = angles * 0.9 ;
}
// m_vecAutoAim = m_vecAutoAim * 0.99;
// Don't send across network if sv_aim is 0
if ( CVAR_GET_FLOAT ( " sv_aim " ) ! = 0 )
{
if ( m_vecAutoAim . x ! = m_lastx | |
m_vecAutoAim . y ! = m_lasty )
{
SET_CROSSHAIRANGLE ( edict ( ) , - m_vecAutoAim . x , m_vecAutoAim . y ) ;
m_lastx = m_vecAutoAim . x ;
m_lasty = m_vecAutoAim . y ;
}
}
// ALERT( at_console, "%f %f\n", angles.x, angles.y );
UTIL_MakeVectors ( pev - > v_angle + pev - > punchangle + m_vecAutoAim ) ;
return gpGlobals - > v_forward ;
}
Vector CBasePlayer : : AutoaimDeflection ( Vector & vecSrc , float flDist , float flDelta )
{
edict_t * pEdict = g_engfuncs . pfnPEntityOfEntIndex ( 1 ) ;
CBaseEntity * pEntity ;
float bestdot ;
Vector bestdir ;
edict_t * bestent ;
TraceResult tr ;
if ( CVAR_GET_FLOAT ( " sv_aim " ) = = 0 )
{
m_fOnTarget = FALSE ;
return g_vecZero ;
}
UTIL_MakeVectors ( pev - > v_angle + pev - > punchangle + m_vecAutoAim ) ;
// try all possible entities
bestdir = gpGlobals - > v_forward ;
bestdot = flDelta ; // +- 10 degrees
bestent = NULL ;
m_fOnTarget = FALSE ;
UTIL_TraceLine ( vecSrc , vecSrc + bestdir * flDist , dont_ignore_monsters , edict ( ) , & tr ) ;
if ( tr . pHit & & tr . pHit - > v . takedamage ! = DAMAGE_NO )
{
// don't look through water
if ( ! ( ( pev - > waterlevel ! = 3 & & tr . pHit - > v . waterlevel = = 3 )
| | ( pev - > waterlevel = = 3 & & tr . pHit - > v . waterlevel = = 0 ) ) )
{
if ( tr . pHit - > v . takedamage = = DAMAGE_AIM )
m_fOnTarget = TRUE ;
return m_vecAutoAim ;
}
}
for ( int i = 1 ; i < gpGlobals - > maxEntities ; i + + , pEdict + + )
{
Vector center ;
Vector dir ;
float dot ;
if ( pEdict - > free ) // Not in use
continue ;
if ( pEdict - > v . takedamage ! = DAMAGE_AIM )
continue ;
if ( pEdict = = edict ( ) )
continue ;
// if (pev->team > 0 && pEdict->v.team == pev->team)
// continue; // don't aim at teammate
if ( ! g_pGameRules - > ShouldAutoAim ( this , pEdict ) )
continue ;
pEntity = Instance ( pEdict ) ;
if ( pEntity = = NULL )
continue ;
if ( ! pEntity - > IsAlive ( ) )
continue ;
// don't look through water
if ( ( pev - > waterlevel ! = 3 & & pEntity - > pev - > waterlevel = = 3 )
| | ( pev - > waterlevel = = 3 & & pEntity - > pev - > waterlevel = = 0 ) )
continue ;
center = pEntity - > BodyTarget ( vecSrc ) ;
dir = ( center - vecSrc ) . Normalize ( ) ;
// make sure it's in front of the player
if ( DotProduct ( dir , gpGlobals - > v_forward ) < 0 )
continue ;
dot = fabs ( DotProduct ( dir , gpGlobals - > v_right ) )
+ fabs ( DotProduct ( dir , gpGlobals - > v_up ) ) * 0.5 ;
// tweek for distance
dot * = 1.0 + 0.2 * ( ( center - vecSrc ) . Length ( ) / flDist ) ;
if ( dot > bestdot )
continue ; // to far to turn
UTIL_TraceLine ( vecSrc , center , dont_ignore_monsters , edict ( ) , & tr ) ;
if ( tr . flFraction ! = 1.0 & & tr . pHit ! = pEdict )
{
// ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) );
continue ;
}
// don't shoot at friends
if ( IRelationship ( pEntity ) < 0 )
{
if ( ! pEntity - > IsPlayer ( ) & & ! g_pGameRules - > IsDeathmatch ( ) )
// ALERT( at_console, "friend\n");
continue ;
}
// can shoot at this one
bestdot = dot ;
bestent = pEdict ;
bestdir = dir ;
}
if ( bestent )
{
bestdir = UTIL_VecToAngles ( bestdir ) ;
bestdir . x = - bestdir . x ;
bestdir = bestdir - pev - > v_angle - pev - > punchangle ;
if ( bestent - > v . takedamage = = DAMAGE_AIM )
m_fOnTarget = TRUE ;
return bestdir ;
}
return Vector ( 0 , 0 , 0 ) ;
}
void CBasePlayer : : ResetAutoaim ( )
{
if ( m_vecAutoAim . x ! = 0 | | m_vecAutoAim . y ! = 0 )
{
m_vecAutoAim = Vector ( 0 , 0 , 0 ) ;
SET_CROSSHAIRANGLE ( edict ( ) , 0 , 0 ) ;
}
m_fOnTarget = FALSE ;
}
/*
= = = = = = = = = = = = =
SetCustomDecalFrames
UNDONE : Determine real frame limit , 8 is a placeholder .
Note : - 1 means no custom frames present .
= = = = = = = = = = = = =
*/
void CBasePlayer : : SetCustomDecalFrames ( int nFrames )
{
if ( nFrames > 0 & &
nFrames < 8 )
m_nCustomSprayFrames = nFrames ;
else
m_nCustomSprayFrames = - 1 ;
}
/*
= = = = = = = = = = = = =
GetCustomDecalFrames
Returns the # of custom frames this player ' s custom clan logo contains .
= = = = = = = = = = = = =
*/
int CBasePlayer : : GetCustomDecalFrames ( void )
{
return m_nCustomSprayFrames ;
}
//=========================================================
// DropPlayerItem - drop the named item, or if no name,
// the active item.
//=========================================================
void CBasePlayer : : DropPlayerItem ( char * pszItemName )
{
// no dropping in disc war
return ;
}
//=========================================================
// HasPlayerItem Does the player already have this item?
//=========================================================
BOOL CBasePlayer : : HasPlayerItem ( CBasePlayerItem * pCheckItem )
{
CBasePlayerItem * pItem = m_rgpPlayerItems [ pCheckItem - > iItemSlot ( ) ] ;
while ( pItem )
{
if ( FClassnameIs ( pItem - > pev , STRING ( pCheckItem - > pev - > classname ) ) )
{
return TRUE ;
}
pItem = pItem - > m_pNext ;
}
return FALSE ;
}
//=========================================================
// HasNamedPlayerItem Does the player already have this item?
//=========================================================
BOOL CBasePlayer : : HasNamedPlayerItem ( const char * pszItemName )
{
CBasePlayerItem * pItem ;
int i ;
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
pItem = m_rgpPlayerItems [ i ] ;
while ( pItem )
{
if ( ! strcmp ( pszItemName , STRING ( pItem - > pev - > classname ) ) )
{
return TRUE ;
}
pItem = pItem - > m_pNext ;
}
}
return FALSE ;
}
//=========================================================
//
//=========================================================
BOOL CBasePlayer : : SwitchWeapon ( CBasePlayerItem * pWeapon )
{
if ( ! pWeapon - > CanDeploy ( ) )
{
return FALSE ;
}
ResetAutoaim ( ) ;
if ( m_pActiveItem )
{
m_pActiveItem - > Holster ( ) ;
}
m_pActiveItem = pWeapon ;
pWeapon - > Deploy ( ) ;
return TRUE ;
}
//=========================================================
// Dead HEV suit prop
//=========================================================
class CDeadHEV : public CBaseMonster
{
public :
void Spawn ( void ) ;
int Classify ( void ) { return CLASS_HUMAN_MILITARY ; }
void KeyValue ( KeyValueData * pkvd ) ;
int m_iPose ; // which sequence to display -- temporary, don't need to save
static char * m_szPoses [ 4 ] ;
} ;
char * CDeadHEV : : m_szPoses [ ] = { " deadback " , " deadsitting " , " deadstomach " , " deadtable " } ;
void CDeadHEV : : KeyValue ( KeyValueData * pkvd )
{
if ( FStrEq ( pkvd - > szKeyName , " pose " ) )
{
m_iPose = atoi ( pkvd - > szValue ) ;
pkvd - > fHandled = TRUE ;
}
else
CBaseMonster : : KeyValue ( pkvd ) ;
}
LINK_ENTITY_TO_CLASS ( monster_hevsuit_dead , CDeadHEV ) ;
//=========================================================
// ********** DeadHEV SPAWN **********
//=========================================================
void CDeadHEV : : Spawn ( void )
{
PRECACHE_MODEL ( " models/player.mdl " ) ;
SET_MODEL ( ENT ( pev ) , " models/player.mdl " ) ;
pev - > effects = 0 ;
pev - > yaw_speed = 8 ;
pev - > sequence = 0 ;
pev - > body = 1 ;
m_bloodColor = BLOOD_COLOR_RED ;
pev - > sequence = LookupSequence ( m_szPoses [ m_iPose ] ) ;
if ( pev - > sequence = = - 1 )
{
ALERT ( at_console , " Dead hevsuit with bad pose \n " ) ;
pev - > sequence = 0 ;
pev - > effects = EF_BRIGHTFIELD ;
}
// Corpses have less health
pev - > health = 8 ;
MonsterInitDead ( ) ;
}
class CStripWeapons : public CPointEntity
{
public :
void Use ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value ) ;
private :
} ;
LINK_ENTITY_TO_CLASS ( player_weaponstrip , CStripWeapons ) ;
void CStripWeapons : : Use ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value )
{
CBasePlayer * pPlayer = NULL ;
if ( pActivator & & pActivator - > IsPlayer ( ) )
{
pPlayer = ( CBasePlayer * ) pActivator ;
}
else if ( ! g_pGameRules - > IsDeathmatch ( ) )
{
pPlayer = ( CBasePlayer * ) CBaseEntity : : Instance ( g_engfuncs . pfnPEntityOfEntIndex ( 1 ) ) ;
}
if ( pPlayer )
pPlayer - > RemoveAllItems ( FALSE ) ;
}
class CRevertSaved : public CPointEntity
{
public :
void Use ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value ) ;
void EXPORT MessageThink ( void ) ;
void EXPORT LoadThink ( void ) ;
void KeyValue ( KeyValueData * pkvd ) ;
virtual int Save ( CSave & save ) ;
virtual int Restore ( CRestore & restore ) ;
static TYPEDESCRIPTION m_SaveData [ ] ;
inline float Duration ( void ) { return pev - > dmg_take ; }
inline float HoldTime ( void ) { return pev - > dmg_save ; }
inline float MessageTime ( void ) { return m_messageTime ; }
inline float LoadTime ( void ) { return m_loadTime ; }
inline void SetDuration ( float duration ) { pev - > dmg_take = duration ; }
inline void SetHoldTime ( float hold ) { pev - > dmg_save = hold ; }
inline void SetMessageTime ( float time ) { m_messageTime = time ; }
inline void SetLoadTime ( float time ) { m_loadTime = time ; }
private :
float m_messageTime ;
float m_loadTime ;
} ;
LINK_ENTITY_TO_CLASS ( player_loadsaved , CRevertSaved ) ;
TYPEDESCRIPTION CRevertSaved : : m_SaveData [ ] =
{
DEFINE_FIELD ( CRevertSaved , m_messageTime , FIELD_FLOAT ) , // These are not actual times, but durations, so save as floats
DEFINE_FIELD ( CRevertSaved , m_loadTime , FIELD_FLOAT ) ,
} ;
IMPLEMENT_SAVERESTORE ( CRevertSaved , CPointEntity ) ;
void CRevertSaved : : KeyValue ( KeyValueData * pkvd )
{
if ( FStrEq ( pkvd - > szKeyName , " duration " ) )
{
SetDuration ( atof ( pkvd - > szValue ) ) ;
pkvd - > fHandled = TRUE ;
}
else if ( FStrEq ( pkvd - > szKeyName , " holdtime " ) )
{
SetHoldTime ( atof ( pkvd - > szValue ) ) ;
pkvd - > fHandled = TRUE ;
}
else if ( FStrEq ( pkvd - > szKeyName , " messagetime " ) )
{
SetMessageTime ( atof ( pkvd - > szValue ) ) ;
pkvd - > fHandled = TRUE ;
}
else if ( FStrEq ( pkvd - > szKeyName , " loadtime " ) )
{
SetLoadTime ( atof ( pkvd - > szValue ) ) ;
pkvd - > fHandled = TRUE ;
}
else
CPointEntity : : KeyValue ( pkvd ) ;
}
void CRevertSaved : : Use ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value )
{
UTIL_ScreenFadeAll ( pev - > rendercolor , Duration ( ) , HoldTime ( ) , pev - > renderamt , FFADE_OUT ) ;
pev - > nextthink = gpGlobals - > time + MessageTime ( ) ;
SetThink ( & CRevertSaved : : MessageThink ) ;
}
void CRevertSaved : : MessageThink ( void )
{
UTIL_ShowMessageAll ( STRING ( pev - > message ) ) ;
float nextThink = LoadTime ( ) - MessageTime ( ) ;
if ( nextThink > 0 )
{
pev - > nextthink = gpGlobals - > time + nextThink ;
SetThink ( & CRevertSaved : : LoadThink ) ;
}
else
LoadThink ( ) ;
}
void CRevertSaved : : LoadThink ( void )
{
if ( ! gpGlobals - > deathmatch )
{
SERVER_COMMAND ( " reload \n " ) ;
}
}
//=========================================================
// Multiplayer intermission spots.
//=========================================================
class CInfoIntermission : public CPointEntity
{
void Spawn ( void ) ;
void Think ( void ) ;
} ;
void CInfoIntermission : : Spawn ( void )
{
UTIL_SetOrigin ( pev , pev - > origin ) ;
pev - > solid = SOLID_NOT ;
pev - > effects = EF_NODRAW ;
pev - > v_angle = g_vecZero ;
pev - > nextthink = gpGlobals - > time + 2 ; // let targets spawn!
}
void CInfoIntermission : : Think ( void )
{
edict_t * pTarget ;
// find my target
pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL , STRING ( pev - > target ) ) ;
if ( ! FNullEnt ( pTarget ) )
{
pev - > v_angle = UTIL_VecToAngles ( ( pTarget - > v . origin - pev - > origin ) . Normalize ( ) ) ;
pev - > v_angle . x = - pev - > v_angle . x ;
}
}
LINK_ENTITY_TO_CLASS ( info_intermission , CInfoIntermission ) ;
//=========================================================
// Freeze
//=========================================================
void CBasePlayer : : Freeze ( void )
{
// Glow blue
pev - > renderfx = kRenderFxGlowShell ;
pev - > rendercolor . z = 200 ;
pev - > renderamt = 25 ;
pev - > maxspeed = FREEZE_SPEED ;
m_iFrozen = 1 ;
m_flFreezeTime = gpGlobals - > time + FREEZE_TIME ;
}
void CBasePlayer : : ClearFreezeAndRender ( )
{
pev - > renderfx = kRenderFxNone ;
pev - > rendercolor = g_vecZero ;
pev - > renderamt = 0 ;
pev - > nextthink = 0 ;
m_iFrozen = 0 ;
if ( IsObserver ( ) )
pev - > maxspeed = 1 ;
else
pev - > maxspeed = 320 ;
}
// Force a client to hear a specific VOX sentence.
// This should eventually be moved into the engine.
void CBasePlayer : : ClientHearVox ( const char * pSentence )
{
MESSAGE_BEGIN ( MSG_ONE , SVC_STUFFTEXT , NULL , pev ) ;
// If it's a sentence, don't put quotes around it
if ( pSentence [ 0 ] = = ' # ' )
{
WRITE_STRING ( UTIL_VarArgs ( " spk %s \n " , pSentence ) ) ;
}
else
{
WRITE_STRING ( UTIL_VarArgs ( " spk \" %s \" \n " , pSentence ) ) ;
}
MESSAGE_END ( ) ;
}